Bug 253759

Summary: sendmail does not quote GECOS information for From header
Product: Base System Reporter: Michael Osipov <michael.osipov>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Some People CC: gshapiro, lwhsu, michael.osipov, michaelo
Priority: ---    
Version: 12.2-STABLE   
Hardware: Any   
OS: Any   

Description Michael Osipov 2021-02-22 11:12:12 UTC
My GECOS field contains the following data: "LDA CaFE (DW) Service User Admin"
The sendmail is used to send e-mails. The "From:" is constructed literally: "LDA CaFE (DW) Service User Admin <root>" and delivered via SMART_HOST but the parentheses never arrive at the target.

When looking at rfc5322#section-3.2.3 the situation is quite clear: "(" and ")" are part of the specials production therefore section 3.2.4 says that the display-name must be quoted to avoid interpretations on the server side.

The request is either to test GECOS for these special chars or simply always quote GECOS information to avoid the loss of information.

Snippet from truss:
?Date: Mon, 22 Feb 2021 11:40:38 +0100 (CET)\nH?F?From: LDA CaFE (DW) Service User Admin <root>\nH?x?Full-Name: L
Comment 1 Michael Osipov freebsd_committer freebsd_triage 2024-04-15 15:43:05 UTC
So the bug is truly in sendmail:
https://github.com/freebsd/freebsd-src/blob/303dea74c2cb3a41fba455fce8577993e637c3da/contrib/sendmail/src/srvrsmtp.c#L5470-L5481

The fullname/GECOS is neither basically quoted nor escaped.

In old ssmtp it is at least quoted: https://salsa.debian.org/debian/ssmtp/-/blob/master/ssmtp.c?ref_type=heads#L463-473
In postfix it is handled perfectly: https://github.com/vdukhovni/postfix/blob/a6993c3a48ebc3ac6cefd9913dab4b8c23b66ab8/postfix/src/smtp/smtp_proto.c#L1436-L1438, it does even escape double quotes in full names.

sendmail has this idiom:
 863         if (!rfc822_string(p))
 864         {
 865             /*
 866             **  Quote a full name with special characters
 867             **  as a comment so crackaddr() doesn't destroy
 868             **  the name portion of the address.
 869             */
 870
 871             p = addquotes(p, e->e_rpool);
 872         }

from ./src/util.c

These spots needs to be analyzed:
osipovmi@deblndw011x:~/var/Projekte/freebsd/src/contrib/sendmail (main =)
$ grep -r q_fullname .
./src/alias.c:  a->q_fullname = NULL;
./src/parseaddr.c:                                   a->q_fullname == NULL ? "(none)" : a->q_fullname);
./src/recipient.c:                              if (a->q_fullname == NULL)
./src/recipient.c:                                      a->q_fullname = ctladdr->q_fullname;
./src/recipient.c:                              new->q_fullname = sm_rpool_strdup_x(e->e_rpool,
./src/sendmail.h:       char            *q_fullname;    /* full name if known */
./src/srvrsmtp.c:       if (a->q_fullname == NULL)
./src/srvrsmtp.c:               message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
Comment 2 Michael Osipov freebsd_committer freebsd_triage 2024-04-15 17:14:03 UTC
As it turns out to:
$ grep -ri -e MustQuoteChars -e MUST_QUOTE_CHARS .
./KNOWNBUGS:  If a full name phrase includes characters from MustQuoteChars, sendmail
./KNOWNBUGS:  will quote the entire full name phrase.  If MustQuoteChars includes
./KNOWNBUGS:  MustQuoteChars even though it is not listed as a special character in
./RELEASE_NOTES:        DOC: Note to set MustQuoteChars=. due to DKIM signatures.
./RELEASE_NOTES:                confALLOW_BOGUS_HELO, and confMUST_QUOTE_CHARS for
./RELEASE_NOTES:                MustQuoteChars respectively.
./RELEASE_NOTES:        Add MustQuoteChars option.  This is a list of characters that must
./cf/README:confMUST_QUOTE_CHARS        MustQuoteChars  [.'] Characters to be quoted in a full
./cf/cf/submit.cf:#O MustQuoteChars=.
./cf/m4/proto.m4:_OPTION(MustQuoteChars, `confMUST_QUOTE_CHARS', `.')
./doc/op/op.me:.ip MustQuoteChars=\fIs\fP
./doc/op/op.me:O MustQuoteChars=.
./src/conf.c:   MustQuoteChars = "@,;:\\()[].'";
./src/headers.c:                if (strchr(MustQuoteChars, c) != NULL)
./src/readcf.c: { "MustQuoteChars",             O_MUSTQUOTE,    OI_NONE },
./src/readcf.c:                                      "Warning: MustQuoteChars too long, ignored.\n");
./src/readcf.c:         MustQuoteChars = newstr(buf);
./src/sendmail.h:EXTERN char    *MustQuoteChars;        /* quote these characters in phrases */
./src/util.c:** XXX: This may be a problem for EAI? MustQuoteChars is used.
./src/util.c:                            strchr(MustQuoteChars, *c) != NULL)

sendmail does include a sensible default in C, but it is overridden in ./cf/m4/proto.m4, thus disabling it.

You have to modify your mc file:
define(`confMUST_QUOTE_CHARS', `@,;:\()[].<>')
to get back RFC compliant behavior with 3.2.3 specials production.

Personally, I don't understand that since I expect by default compliant behavior. I still consider it as a bug in the default installation.