File sendmail-8.15.2-smtpmode.patch of Package sendmail.32316

---
 doc/op/op.me        |   31 ++++++++++++
 sendmail/collect.c  |  134 +++++++++++++++++++++++++++++++++-------------------
 sendmail/envelope.c |    2 
 sendmail/main.c     |    5 +
 sendmail/mime.c     |    4 -
 sendmail/sendmail.h |   13 +++--
 sendmail/srvrsmtp.c |   55 ++++++++++++---------
 7 files changed, 165 insertions(+), 79 deletions(-)

--- doc/op/op.me
+++ doc/op/op.me	2024-01-24 12:26:34.361010730 +0000
@@ -4441,6 +4441,30 @@ passive attack (e.g., PLAIN, LOGIN), unl
 Option `l' requires SMTP AUTH for a connection.
 Options 'B', 'D', 'E', and 'X' suppress SMTP VERB, DSN, ETRN, and EXPN,
 respectively.
+Option 'o' causes the server to accept only
+CR LF . CR LF
+as end of an SMTP message as required by the RFCs
+which is also a defense against SMTP smuggling (CVE-2023-51765).
+Option 'O' allows the server to accept a single dot on a line by itself
+as end of an SMTP message.
+Option 'g' instructs the server to fail SMTP messages
+which have a LF without a CR directly before it ("bare LF")
+by dropping the session with a 421 error.
+Option 'G' accepts SMTP messages which have a "bare LF".
+Option 'u' instructs the server to fail SMTP messages
+which have a CR without a LF directly after it ("bare CR")
+by dropping the session with a 421 error.
+Option 'U' accepts SMTP messages which have a "bare CR".
+If needed, internal system with broken SMTP implementations
+can be allowed some violations, e.g., a combination of
+.(b
+G U O
+.)b
+A command like
+.(b
+egrep 'Bare.*(CR|LF).*not allowed' $MAILLOG
+.)b
+can be used to find hosts which send bare CR/LF.
 .(b
 .ta 9n
 A	Do not offer AUTH
@@ -4454,12 +4478,19 @@ D	Do not offer DSN
 d	Offer DSN (default)
 E	Do not offer ETRN
 e	Offer ETRN (default)
+G	Accept "bare LF"s in a message
+g	Do not accept "bare LF"s in a message (default)
 L	Do not require AUTH (default)
 l	Require AUTH
+O	Accept a single dot on a line by itself
+	as end of an SMTP message
+o	Require CR LF . CR LF as end of an SMTP message (default)
 P	Do not offer PIPELINING
 p	Offer PIPELINING (default)
 S	Do not offer STARTTLS
 s	Offer STARTTLS (default)
+U	Accept "bare CR"s in a message
+u	Do not accept "bare CR"s in a message (default)
 V	Do not request a client certificate
 v	Request a client certificate (default)
 X	Do not offer EXPN
--- sendmail/collect.c
+++ sendmail/collect.c	2024-01-24 11:57:28.125474171 +0000
@@ -239,10 +239,10 @@ collect_dfopen(e)
 **
 **	Parameters:
 **		fp -- file to read.
-**		smtpmode -- if set, we are running SMTP: give an RFC821
-**			style message to say we are ready to collect
-**			input, and never ignore a single dot to mean
-**			end of message.
+**		smtpmode -- if >= SMTPMODE_LAX we are running SMTP:
+**			give an RFC821 style message to say we are
+**			ready to collect input, and never ignore
+**			a single dot to mean end of message.
 **		hdrp -- the location to stash the header.
 **		e -- the current envelope.
 **		rsetsize -- reset e_msgsize?
@@ -265,20 +265,26 @@ collect_dfopen(e)
 /* values for input state machine */
 #define IS_NORM		0	/* middle of line */
 #define IS_BOL		1	/* beginning of line */
-#define IS_DOT		2	/* read a dot at beginning of line */
+#define IS_DOT		2	/* read "." at beginning of line */
 #define IS_DOTCR	3	/* read ".\r" at beginning of line */
-#define IS_CR		4	/* read a carriage return */
+#define IS_CR		4	/* read "\r" */
+
+/* hack to enhance readability of debug output */
+static const char *istates[] = { "NORM", "BOL", "DOT", "DOTCR", "CR" };
+#define ISTATE istates[istate]
 
 /* values for message state machine */
 #define MS_UFROM	0	/* reading Unix from line */
 #define MS_HEADER	1	/* reading message header */
 #define MS_BODY		2	/* reading message body */
 #define MS_DISCARD	3	/* discarding rest of message */
+#define BARE_LF_MSG "Bare linefeed (LF) not allowed"
+#define BARE_CR_MSG "Bare carriage return (CR) not allowed"
 
 void
 collect(fp, smtpmode, hdrp, e, rsetsize)
 	SM_FILE_T *fp;
-	bool smtpmode;
+	int smtpmode;
 	HDR **hdrp;
 	register ENVELOPE *e;
 	bool rsetsize;
@@ -304,12 +310,19 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 #if _FFR_REJECT_NUL_BYTE
 	bool hasNUL;		/* has at least one NUL input byte */
 #endif /* _FFR_REJECT_NUL_BYTE */
+	bool bare_lf = false;
+	bool bare_cr = false;
+
+#define SMTPMODE	(smtpmode >= SMTPMODE_LAX)
+#define SMTPMODE_STRICT		((smtpmode & SMTPMODE_CRLF) != 0)
+#define SMTPMODE_BARE_LF_421	((smtpmode & SMTPMODE_LF_421) != 0)
+#define SMTPMODE_BARE_CR_421	((smtpmode & SMTPMODE_CR_421) != 0)
 
 	df = NULL;
-	ignrdot = smtpmode ? false : IgnrDot;
+	ignrdot = SMTPMODE ? false : IgnrDot;
 
 	/* timeout for I/O functions is in milliseconds */
-	dbto = smtpmode ? ((int) TimeOuts.to_datablock * 1000)
+	dbto = SMTPMODE ? ((int) TimeOuts.to_datablock * 1000)
 			: SM_TIME_FOREVER;
 	sm_io_setinfo(fp, SM_IO_WHAT_TIMEOUT, &dbto);
 	old_rd_tmo = set_tls_rd_tmo(TimeOuts.to_datablock);
@@ -332,15 +345,15 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 	**  Tell ARPANET to go ahead.
 	*/
 
-	if (smtpmode)
-		message("354 Enter mail, end with \".\" on a line by itself");
+	if (SMTPMODE)
+		message("354 End data with <CR><LF>.<CR><LF>");
 
 	/* simulate an I/O timeout when used as sink */
 	if (tTd(83, 101))
 		sleep(319);
 
 	if (tTd(30, 2))
-		sm_dprintf("collect\n");
+		sm_dprintf("collect, smtpmode=%#x\n", smtpmode);
 
 	/*
 	**  Read the message.
@@ -356,7 +369,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 	for (;;)
 	{
 		if (tTd(30, 35))
-			sm_dprintf("top, istate=%d, mstate=%d\n", istate,
+			sm_dprintf("top, istate=%s, mstate=%d\n", ISTATE,
 				   mstate);
 		for (;;)
 		{
@@ -377,7 +390,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 
 					/* timeout? */
 					if (c == SM_IO_EOF && errno == EAGAIN
-					    && smtpmode)
+					    && SMTPMODE)
 					{
 						/*
 						**  Override e_message in
@@ -415,15 +428,36 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 					hasNUL = true;
 #endif /* _FFR_REJECT_NUL_BYTE */
 				if (c == SM_IO_EOF)
-					goto readerr;
+					goto readdone;
 				if (SevenBitInput)
 					c &= 0x7f;
 				else
 					HasEightBits |= bitset(0x80, c);
 			}
 			if (tTd(30, 94))
-				sm_dprintf("istate=%d, c=%c (0x%x)\n",
-					istate, (char) c, c);
+				sm_dprintf("istate=%s, c=%c (0x%x)\n",
+					ISTATE, (char) c, c);
+			if ('\n' == c && !bare_lf && SMTPMODE &&
+			    !(IS_CR == istate || IS_DOTCR == istate))
+			{
+				bare_lf = true;
+				if (SMTPMODE_BARE_LF_421)
+				{
+					inputerr = true;
+					goto readabort;
+				}
+			}
+			if (!bare_cr && SMTPMODE &&
+			    (IS_CR == istate || IS_DOTCR == istate)
+			    && '\n' != c)
+			{
+				bare_cr = true;
+				if (SMTPMODE_BARE_CR_421)
+				{
+					inputerr = true;
+					goto readabort;
+				}
+			}
 			switch (istate)
 			{
 			  case IS_BOL:
@@ -435,11 +469,9 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 				break;
 
 			  case IS_DOT:
-				if (c == '\n' && !ignrdot &&
-				    !bitset(EF_NL_NOT_EOL, e->e_flags))
-					goto readerr;
-				else if (c == '\r' &&
-					 !bitset(EF_CRLF_NOT_EOL, e->e_flags))
+				if (c == '\n' && !ignrdot && !SMTPMODE_STRICT)
+					goto readdone;
+				else if (c == '\r')
 				{
 					istate = IS_DOTCR;
 					continue;
@@ -460,7 +492,7 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 
 			  case IS_DOTCR:
 				if (c == '\n' && !ignrdot)
-					goto readerr;
+					goto readdone;
 				else
 				{
 					/* push back the ".\rx" */
@@ -494,13 +526,12 @@ collect(fp, smtpmode, hdrp, e, rsetsize)
 				goto bufferchar;
 			}
 
-			if (c == '\r' && !bitset(EF_CRLF_NOT_EOL, e->e_flags))
+			if (c == '\r')
 			{
 				istate = IS_CR;
 				continue;
 			}
-			else if (c == '\n' && !bitset(EF_NL_NOT_EOL,
-						      e->e_flags))
+			else if (c == '\n' && !SMTPMODE_STRICT)
 				istate = IS_BOL;
 			else
 				istate = IS_NORM;
@@ -593,8 +624,8 @@ bufferchar:
 
 nextstate:
 		if (tTd(30, 35))
-			sm_dprintf("nextstate, istate=%d, mstate=%d, line=\"%s\"\n",
-				istate, mstate, buf);
+			sm_dprintf("nextstate, istate=%s, mstate=%d, line=\"%s\"\n",
+				ISTATE, mstate, buf);
 		switch (mstate)
 		{
 		  case MS_UFROM:
@@ -625,7 +656,7 @@ nextstate:
 
 				/* timeout? */
 				if (c == SM_IO_EOF && errno == EAGAIN
-				    && smtpmode)
+				    && SMTPMODE)
 				{
 					/*
 					**  Override e_message in
@@ -674,7 +705,7 @@ nextstate:
 				sm_dprintf("EOH\n");
 
 			if (headeronly)
-				goto readerr;
+				goto readdone;
 
 			df = collect_eoh(e, numhdrs, hdrslen);
 			if (df == NULL)
@@ -683,10 +714,8 @@ nextstate:
 			bp = buf;
 
 			/* toss blank line */
-			if ((!bitset(EF_CRLF_NOT_EOL, e->e_flags) &&
-				bp[0] == '\r' && bp[1] == '\n') ||
-			    (!bitset(EF_NL_NOT_EOL, e->e_flags) &&
-				bp[0] == '\n'))
+			if ((bp[0] == '\r' && bp[1] == '\n') ||
+			    (bp[0] == '\n'))
 			{
 				break;
 			}
@@ -703,8 +732,8 @@ nextstate:
 		bp = buf;
 	}
 
-readerr:
-	if ((sm_io_eof(fp) && smtpmode) || sm_io_error(fp))
+readdone:
+	if ((sm_io_eof(fp) && SMTPMODE) || sm_io_error(fp))
 	{
 		const char *errmsg;
 
@@ -744,7 +773,7 @@ readerr:
 	}
 	else if (SuperSafe == SAFE_NO ||
 		 SuperSafe == SAFE_INTERACTIVE ||
-		 (SuperSafe == SAFE_REALLY_POSTMILTER && smtpmode))
+		 (SuperSafe == SAFE_REALLY_POSTMILTER && SMTPMODE))
 	{
 		/* skip next few clauses */
 		/* EMPTY */
@@ -821,21 +850,26 @@ readerr:
 			problem = "unexpected close";
 		else if (sm_io_error(fp))
 			problem = "I/O error";
+		else if (bare_lf)
+			problem = "bare LF";
+		else if (bare_cr)
+			problem = "bare CR";
 		else
 			problem = "read timeout";
-		if (LogLevel > 0 && sm_io_eof(fp))
+
+#define CONN_ERR_TXT	"collect: %s on connection from %s, from=%s%s%s"
+#define CONN_ERR_CODE	"421 4.4.1 "
+#define CONN_ERR_BARE bare_lf ? BARE_LF_MSG : (bare_cr ? BARE_CR_MSG : "")
+#define CONN_ERR_ARGS problem, host, shortenstring(e->e_from.q_paddr, MAXSHORTSTR), (bare_lf || bare_cr) ? ", info=" : "", CONN_ERR_BARE
+		if (LogLevel > 0 && (sm_io_eof(fp) || bare_lf || bare_cr))
 			sm_syslog(LOG_NOTICE, e->e_id,
-				"collect: %s on connection from %.100s, sender=%s",
-				problem, host,
-				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
-		if (sm_io_eof(fp))
-			usrerr("421 4.4.1 collect: %s on connection from %s, from=%s",
-				problem, host,
-				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+				CONN_ERR_TXT, CONN_ERR_ARGS);
+		if (bare_lf || bare_cr)
+			usrerr(CONN_ERR_CODE "%s", CONN_ERR_BARE);
+		else if (sm_io_eof(fp))
+			usrerr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS);
 		else
-			syserr("421 4.4.1 collect: %s on connection from %s, from=%s",
-				problem, host,
-				shortenstring(e->e_from.q_paddr, MAXSHORTSTR));
+			syserr(CONN_ERR_CODE CONN_ERR_TXT, CONN_ERR_ARGS);
 		flush_errors(true);
 
 		/* don't return an error indication */
@@ -866,6 +900,10 @@ readerr:
 		logsender(e, e->e_msgid);
 		e->e_flags &= ~EF_LOGSENDER;
 	}
+	if (bare_lf && LogLevel > 8)
+		sm_syslog(LOG_NOTICE, e->e_id, BARE_LF_MSG);
+	if (bare_cr && LogLevel > 8)
+		sm_syslog(LOG_NOTICE, e->e_id, BARE_CR_MSG);
 
 	/* check for message too large */
 	if (bitset(EF_TOOBIG, e->e_flags))
--- sendmail/envelope.c
+++ sendmail/envelope.c	2024-01-24 08:40:15.186162779 +0000
@@ -1271,8 +1271,6 @@ static struct eflags	EnvelopeFlags[] =
 	{ "LOGSENDER",		EF_LOGSENDER	},
 	{ "NORECEIPT",		EF_NORECEIPT	},
 	{ "HAS8BIT",		EF_HAS8BIT	},
-	{ "NL_NOT_EOL",		EF_NL_NOT_EOL	},
-	{ "CRLF_NOT_EOL",	EF_CRLF_NOT_EOL	},
 	{ "RET_PARAM",		EF_RET_PARAM	},
 	{ "HAS_DF",		EF_HAS_DF	},
 	{ "IS_MIME",		EF_IS_MIME	},
--- sendmail/main.c
+++ sendmail/main.c	2024-01-18 14:01:08.494154339 +0000
@@ -2790,7 +2790,8 @@ main(argc, argv, envp)
 
 		/* collect body for UUCP return */
 		if (OpMode != MD_VERIFY)
-			collect(InChannel, false, NULL, &MainEnvelope, true);
+			collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope,
+				true);
 		finis(true, true, EX_USAGE);
 		/* NOTREACHED */
 	}
@@ -2850,7 +2851,7 @@ main(argc, argv, envp)
 		MainEnvelope.e_flags &= ~EF_FATALERRS;
 		Errors = 0;
 		buffer_errors();
-		collect(InChannel, false, NULL, &MainEnvelope, true);
+		collect(InChannel, SMTPMODE_NO, NULL, &MainEnvelope, true);
 
 		/* header checks failed */
 		if (Errors > 0)
--- sendmail/mime.c
+++ sendmail/mime.c	2024-01-18 14:01:08.494154339 +0000
@@ -346,7 +346,7 @@ mime8to7(mci, header, e, boundaries, fla
 				goto writeerr;
 			if (tTd(43, 35))
 				sm_dprintf("  ...%s\n", buf);
-			collect(e->e_dfp, false, &hdr, e, false);
+			collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false);
 			if (tTd(43, 101))
 				putline("+++after collect", mci);
 			if (!putheader(mci, hdr, e, flags))
@@ -408,7 +408,7 @@ mime8to7(mci, header, e, boundaries, fla
 				goto writeerr;
 
 			mci->mci_flags |= MCIF_INMIME;
-			collect(e->e_dfp, false, &hdr, e, false);
+			collect(e->e_dfp, SMTPMODE_NO, &hdr, e, false);
 			if (tTd(43, 101))
 				putline("+++after collect", mci);
 			if (!putheader(mci, hdr, e, flags))
--- sendmail/sendmail.h
+++ sendmail/sendmail.h	2024-01-24 08:41:39.060584463 +0000
@@ -1017,8 +1017,8 @@ struct envelope
 #define EF_LOGSENDER	0x00008000L	/* need to log the sender */
 #define EF_NORECEIPT	0x00010000L	/* suppress all return-receipts */
 #define EF_HAS8BIT	0x00020000L	/* at least one 8-bit char in body */
-#define EF_NL_NOT_EOL	0x00040000L	/* don't accept raw NL as EOLine */
-#define EF_CRLF_NOT_EOL	0x00080000L	/* don't accept CR-LF as EOLine */
+/* was: #define EF_NL_NOT_EOL	0x00040000L	* don't accept raw NL as EOLine */
+/* was: #define EF_CRLF_NOT_EOL	0x00080000L	* don't accept CR-LF as EOLine */
 #define EF_RET_PARAM	0x00100000L	/* RCPT command had RET argument */
 #define EF_HAS_DF	0x00200000L	/* set when data file is instantiated */
 #define EF_IS_MIME	0x00400000L	/* really is a MIME message */
@@ -2681,7 +2681,7 @@ extern void	cleanup_shm __P((bool));
 #endif /* SM_CONF_SHM */
 extern void	close_sendmail_pid __P((void));
 extern void	clrdaemon __P((void));
-extern void	collect __P((SM_FILE_T *, bool, HDR **, ENVELOPE *, bool));
+extern void	collect __P((SM_FILE_T *, int, HDR **, ENVELOPE *, bool));
 extern bool	connection_rate_check __P((SOCKADDR *, ENVELOPE *));
 extern time_t	convtime __P((char *, int));
 extern char	**copyplist __P((char **, bool, SM_RPOOL_T *));
@@ -2864,6 +2864,13 @@ extern bool	xtextok __P((char *));
 extern int	xunlink __P((char *));
 extern char	*xuntextify __P((char *));
 
+#define SMTPMODE_NO	0
+#define SMTPMODE_LAX	0x01
+#define SMTPMODE_CRLF	0x02	/* CRLF.CRLF required for EOM */
+#define SMTPMODE_LF_421	0x04	/* no bare LF - drop connection */
+#define SMTPMODE_CR_421	0x08	/* no bare CR - drop connection */
+
+
 #if _FFR_RCPTFLAGS
 extern bool	newmodmailer __P((ADDRESS *, int));
 #endif
--- sendmail/srvrsmtp.c
+++ sendmail/srvrsmtp.c	2024-01-24 12:06:37.619288193 +0000
@@ -47,26 +47,29 @@ static bool	NotFirstDelivery = false;
 #endif /* _FFR_DM_ONE */
 
 /* server features */
-#define SRV_NONE	0x0000	/* none... */
-#define SRV_OFFER_TLS	0x0001	/* offer STARTTLS */
-#define SRV_VRFY_CLT	0x0002	/* request a cert */
-#define SRV_OFFER_AUTH	0x0004	/* offer AUTH */
-#define SRV_OFFER_ETRN	0x0008	/* offer ETRN */
-#define SRV_OFFER_VRFY	0x0010	/* offer VRFY (not yet used) */
-#define SRV_OFFER_EXPN	0x0020	/* offer EXPN */
-#define SRV_OFFER_VERB	0x0040	/* offer VERB */
-#define SRV_OFFER_DSN	0x0080	/* offer DSN */
+#define SRV_NONE	0x00000000	/* none... */
+#define SRV_OFFER_TLS	0x00000001	/* offer STARTTLS */
+#define SRV_VRFY_CLT	0x00000002	/* request a cert */
+#define SRV_OFFER_AUTH	0x00000004	/* offer AUTH */
+#define SRV_OFFER_ETRN	0x00000008	/* offer ETRN */
+#define SRV_OFFER_VRFY	0x00000010	/* offer VRFY (not yet used) */
+#define SRV_OFFER_EXPN	0x00000020	/* offer EXPN */
+#define SRV_OFFER_VERB	0x00000040	/* offer VERB */
+#define SRV_OFFER_DSN	0x00000080	/* offer DSN */
 #if PIPELINING
-# define SRV_OFFER_PIPE	0x0100	/* offer PIPELINING */
+# define SRV_OFFER_PIPE	0x00000100	/* offer PIPELINING */
 # if _FFR_NO_PIPE
-#  define SRV_NO_PIPE	0x0200	/* disable PIPELINING, sleep if used */
+#  define SRV_NO_PIPE	0x00000200	/* disable PIPELINING, sleep if used */
 # endif /* _FFR_NO_PIPE */
 #endif /* PIPELINING */
-#define SRV_REQ_AUTH	0x0400	/* require AUTH */
-#define SRV_REQ_SEC	0x0800	/* require security - equiv to AuthOptions=p */
-#define SRV_TMP_FAIL	0x1000	/* ruleset caused a temporary failure */
+#define SRV_REQ_AUTH	0x00000400	/* require AUTH */
+#define SRV_REQ_SEC	0x00000800	/* require security - equiv to AuthOptions=p */
+#define SRV_TMP_FAIL	0x00001000	/* ruleset caused a temporary failure */
+#define SRV_REQ_CRLF	0x00010000	/* require CR LF as EOL */
+#define SRV_BARE_LF_421	0x00020000	/* bare LF - drop connection */
+#define SRV_BARE_CR_421	0x00040000	/* bare CR - drop connection */
 
-static unsigned int	srvfeatures __P((ENVELOPE *, char *, unsigned int));
+static unsigned long	srvfeatures __P((ENVELOPE *, char *, unsigned long));
 
 #define	STOP_ATTACK	((time_t) -1)
 static time_t	checksmtpattack __P((volatile unsigned int *, unsigned int,
@@ -812,7 +815,7 @@ smtp(nullserver, d_flags, e)
 	bool saveSuprErrs;
 	time_t tlsstart;
 #endif /* STARTTLS */
-	volatile unsigned int features;
+	volatile unsigned long features;
 #if PIPELINING
 # if _FFR_NO_PIPE
 	int np_log = 0;
@@ -898,6 +901,7 @@ smtp(nullserver, d_flags, e)
 		| (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
 						       : SRV_VRFY_CLT)
 #endif /* STARTTLS */
+		| SRV_REQ_CRLF | SRV_BARE_LF_421 | SRV_BARE_CR_421
 		;
 	if (nullserver == NULL)
 	{
@@ -3612,7 +3616,7 @@ smtp_data(smtp, e)
 	ENVELOPE *ee;
 	char *id;
 	char *oldid;
-	unsigned int features;
+	unsigned long features;
 	char buf[32];
 
 	SmtpPhase = "server DATA";
@@ -3744,7 +3748,11 @@ smtp_data(smtp, e)
 	SmtpPhase = "collect";
 	buffer_errors();
 
-	collect(InChannel, true, NULL, e, true);
+	collect(InChannel, SMTPMODE_LAX
+		| (bitset(SRV_BARE_LF_421, e->e_features) ? SMTPMODE_LF_421 : 0)
+		| (bitset(SRV_BARE_CR_421, e->e_features) ? SMTPMODE_CR_421 : 0)
+		| (bitset(SRV_REQ_CRLF, e->e_features) ? SMTPMODE_CRLF : 0),
+		NULL, e, true);
 
 	/* redefine message size */
 	(void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize));
@@ -5163,7 +5171,7 @@ initsrvtls(tls_ok)
 static struct
 {
 	char		srvf_opt;
-	unsigned int	srvf_flag;
+	unsigned long	srvf_flag;
 } srv_feat_table[] =
 {
 	{ 'A',	SRV_OFFER_AUTH	},
@@ -5171,27 +5179,30 @@ static struct
 	{ 'C',	SRV_REQ_SEC	},
 	{ 'D',	SRV_OFFER_DSN	},
 	{ 'E',	SRV_OFFER_ETRN	},
+	{ 'G',	SRV_BARE_LF_421	},
 	{ 'L',	SRV_REQ_AUTH	},
 #if PIPELINING
 # if _FFR_NO_PIPE
 	{ 'N',	SRV_NO_PIPE	},
 # endif /* _FFR_NO_PIPE */
+	{ 'O',	SRV_REQ_CRLF	},	/* eOl */
 	{ 'P',	SRV_OFFER_PIPE	},
 #endif /* PIPELINING */
 	{ 'R',	SRV_VRFY_CLT	},	/* same as V; not documented */
 	{ 'S',	SRV_OFFER_TLS	},
 /*	{ 'T',	SRV_TMP_FAIL	},	*/
+	{ 'U',	SRV_BARE_CR_421	},
 	{ 'V',	SRV_VRFY_CLT	},
 	{ 'X',	SRV_OFFER_EXPN	},
 /*	{ 'Y',	SRV_OFFER_VRFY	},	*/
 	{ '\0',	SRV_NONE	}
 };
 
-static unsigned int
+static unsigned long
 srvfeatures(e, clientname, features)
 	ENVELOPE *e;
 	char *clientname;
-	unsigned int features;
+	unsigned long features;
 {
 	int r, i, j;
 	char **pvp, c, opt;
@@ -5225,7 +5236,7 @@ srvfeatures(e, clientname, features)
 			{
 				if (LogLevel > 9)
 					sm_syslog(LOG_WARNING, e->e_id,
-						  "srvfeatures: unknown feature %s",
+						  "srv_features: unknown feature %s",
 						  pvp[i]);
 				break;
 			}
openSUSE Build Service is sponsored by