xref: /freebsd/contrib/sendmail/src/srvrsmtp.c (revision ee2ea5ceafed78a5bd9810beb9e3ca927180c226)
1 /*
2  * Copyright (c) 1998-2002 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13 
14 #include <sendmail.h>
15 #if MILTER
16 # include <libmilter/mfdef.h>
17 #endif /* MILTER */
18 
19 SM_RCSID("@(#)$Id: srvrsmtp.c,v 1.1.1.10 2002/04/10 03:04:52 gshapiro Exp $")
20 
21 #if SASL || STARTTLS
22 # include <sys/time.h>
23 # include "sfsasl.h"
24 #endif /* SASL || STARTTLS */
25 #if SASL
26 # define ENC64LEN(l)	(((l) + 2) * 4 / 3 + 1)
27 static int saslmechs __P((sasl_conn_t *, char **));
28 #endif /* SASL */
29 #if STARTTLS
30 # include <sysexits.h>
31 
32 static SSL_CTX	*srv_ctx = NULL;	/* TLS server context */
33 static SSL	*srv_ssl = NULL;	/* per connection context */
34 
35 static bool	tls_ok_srv = false;
36 
37 extern void	tls_set_verify __P((SSL_CTX *, SSL *, bool));
38 # define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \
39 				bitset(SRV_VRFY_CLT, features))
40 #endif /* STARTTLS */
41 
42 /* server features */
43 #define SRV_NONE	0x0000	/* none... */
44 #define SRV_OFFER_TLS	0x0001	/* offer STARTTLS */
45 #define SRV_VRFY_CLT	0x0002	/* request a cert */
46 #define SRV_OFFER_AUTH	0x0004	/* offer AUTH */
47 #define SRV_OFFER_ETRN	0x0008	/* offer ETRN */
48 #define SRV_OFFER_VRFY	0x0010	/* offer VRFY (not yet used) */
49 #define SRV_OFFER_EXPN	0x0020	/* offer EXPN */
50 #define SRV_OFFER_VERB	0x0040	/* offer VERB */
51 #define SRV_OFFER_DSN	0x0080	/* offer DSN */
52 #if PIPELINING
53 # define SRV_OFFER_PIPE	0x0100	/* offer PIPELINING */
54 # if _FFR_NO_PIPE
55 #  define SRV_NO_PIPE	0x0200	/* disable PIPELINING, sleep if used */
56 # endif /* _FFR_NO_PIPE */
57 #endif /* PIPELINING */
58 #define SRV_REQ_AUTH	0x0400	/* require AUTH */
59 #define SRV_TMP_FAIL	0x1000	/* ruleset caused a temporary failure */
60 
61 static unsigned int	srvfeatures __P((ENVELOPE *, char *, unsigned int));
62 
63 static time_t	checksmtpattack __P((volatile unsigned int *, int, bool,
64 				     char *, ENVELOPE *));
65 static void	mail_esmtp_args __P((char *, char *, ENVELOPE *));
66 static void	printvrfyaddr __P((ADDRESS *, bool, bool));
67 static void	rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *));
68 static char	*skipword __P((char *volatile, char *));
69 static void	setup_smtpd_io __P((void));
70 extern ENVELOPE	BlankEnvelope;
71 
72 #define SKIP_SPACE(s)	while (isascii(*s) && isspace(*s))	\
73 				(s)++
74 
75 /*
76 **  SMTP -- run the SMTP protocol.
77 **
78 **	Parameters:
79 **		nullserver -- if non-NULL, rejection message for
80 **			(almost) all SMTP commands.
81 **		d_flags -- daemon flags
82 **		e -- the envelope.
83 **
84 **	Returns:
85 **		never.
86 **
87 **	Side Effects:
88 **		Reads commands from the input channel and processes them.
89 */
90 
91 /*
92 **  Notice: The smtp server doesn't have a session context like the client
93 **	side has (mci). Therefore some data (session oriented) is allocated
94 **	or assigned to the "wrong" structure (esp. STARTTLS, AUTH).
95 **	This should be fixed in a successor version.
96 */
97 
98 struct cmd
99 {
100 	char	*cmd_name;	/* command name */
101 	int	cmd_code;	/* internal code, see below */
102 };
103 
104 /* values for cmd_code */
105 #define CMDERROR	0	/* bad command */
106 #define CMDMAIL	1	/* mail -- designate sender */
107 #define CMDRCPT	2	/* rcpt -- designate recipient */
108 #define CMDDATA	3	/* data -- send message text */
109 #define CMDRSET	4	/* rset -- reset state */
110 #define CMDVRFY	5	/* vrfy -- verify address */
111 #define CMDEXPN	6	/* expn -- expand address */
112 #define CMDNOOP	7	/* noop -- do nothing */
113 #define CMDQUIT	8	/* quit -- close connection and die */
114 #define CMDHELO	9	/* helo -- be polite */
115 #define CMDHELP	10	/* help -- give usage info */
116 #define CMDEHLO	11	/* ehlo -- extended helo (RFC 1425) */
117 #define CMDETRN	12	/* etrn -- flush queue */
118 #if SASL
119 # define CMDAUTH	13	/* auth -- SASL authenticate */
120 #endif /* SASL */
121 #if STARTTLS
122 # define CMDSTLS	14	/* STARTTLS -- start TLS session */
123 #endif /* STARTTLS */
124 /* non-standard commands */
125 #define CMDVERB	17	/* verb -- go into verbose mode */
126 /* unimplemented commands from RFC 821 */
127 #define CMDUNIMPL	19	/* unimplemented rfc821 commands */
128 /* use this to catch and log "door handle" attempts on your system */
129 #define CMDLOGBOGUS	23	/* bogus command that should be logged */
130 /* debugging-only commands, only enabled if SMTPDEBUG is defined */
131 #define CMDDBGQSHOW	24	/* showq -- show send queue */
132 #define CMDDBGDEBUG	25	/* debug -- set debug mode */
133 
134 /*
135 **  Note: If you change this list, remember to update 'helpfile'
136 */
137 
138 static struct cmd	CmdTab[] =
139 {
140 	{ "mail",	CMDMAIL		},
141 	{ "rcpt",	CMDRCPT		},
142 	{ "data",	CMDDATA		},
143 	{ "rset",	CMDRSET		},
144 	{ "vrfy",	CMDVRFY		},
145 	{ "expn",	CMDEXPN		},
146 	{ "help",	CMDHELP		},
147 	{ "noop",	CMDNOOP		},
148 	{ "quit",	CMDQUIT		},
149 	{ "helo",	CMDHELO		},
150 	{ "ehlo",	CMDEHLO		},
151 	{ "etrn",	CMDETRN		},
152 	{ "verb",	CMDVERB		},
153 	{ "send",	CMDUNIMPL	},
154 	{ "saml",	CMDUNIMPL	},
155 	{ "soml",	CMDUNIMPL	},
156 	{ "turn",	CMDUNIMPL	},
157 #if SASL
158 	{ "auth",	CMDAUTH,	},
159 #endif /* SASL */
160 #if STARTTLS
161 	{ "starttls",	CMDSTLS,	},
162 #endif /* STARTTLS */
163     /* remaining commands are here only to trap and log attempts to use them */
164 	{ "showq",	CMDDBGQSHOW	},
165 	{ "debug",	CMDDBGDEBUG	},
166 	{ "wiz",	CMDLOGBOGUS	},
167 
168 	{ NULL,		CMDERROR	}
169 };
170 
171 static char	*CurSmtpClient;		/* who's at the other end of channel */
172 
173 #ifndef MAXBADCOMMANDS
174 # define MAXBADCOMMANDS 25	/* maximum number of bad commands */
175 #endif /* ! MAXBADCOMMANDS */
176 #ifndef MAXNOOPCOMMANDS
177 # define MAXNOOPCOMMANDS 20	/* max "noise" commands before slowdown */
178 #endif /* ! MAXNOOPCOMMANDS */
179 #ifndef MAXHELOCOMMANDS
180 # define MAXHELOCOMMANDS 3	/* max HELO/EHLO commands before slowdown */
181 #endif /* ! MAXHELOCOMMANDS */
182 #ifndef MAXVRFYCOMMANDS
183 # define MAXVRFYCOMMANDS 6	/* max VRFY/EXPN commands before slowdown */
184 #endif /* ! MAXVRFYCOMMANDS */
185 #ifndef MAXETRNCOMMANDS
186 # define MAXETRNCOMMANDS 8	/* max ETRN commands before slowdown */
187 #endif /* ! MAXETRNCOMMANDS */
188 #ifndef MAXTIMEOUT
189 # define MAXTIMEOUT (4 * 60)	/* max timeout for bad commands */
190 #endif /* ! MAXTIMEOUT */
191 
192 #if SM_HEAP_CHECK
193 static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp",
194 	"@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $");
195 #endif /* SM_HEAP_CHECK */
196 
197 typedef struct
198 {
199 	bool	sm_gotmail;	/* mail command received */
200 	unsigned int sm_nrcpts;	/* number of successful RCPT commands */
201 #if _FFR_ADAPTIVE_EOL
202 WARNING: do NOT use this FFR, it is most likely broken
203 	bool	sm_crlf;	/* input in CRLF form? */
204 #endif /* _FFR_ADAPTIVE_EOL */
205 	bool	sm_discard;
206 #if MILTER
207 	bool	sm_milterize;
208 	bool	sm_milterlist;	/* any filters in the list? */
209 #endif /* MILTER */
210 #if _FFR_QUARANTINE
211 	char	*sm_quarmsg;	/* carry quarantining across messages */
212 #endif /* _FFR_QUARANTINE */
213 } SMTP_T;
214 
215 static void	smtp_data __P((SMTP_T *, ENVELOPE *));
216 
217 #define MSG_TEMPFAIL "451 4.7.1 Please try again later"
218 
219 #if MILTER
220 # define MILTER_ABORT(e)	milter_abort((e))
221 # define MILTER_REPLY(str)						\
222 	{								\
223 		int savelogusrerrs = LogUsrErrs;			\
224 									\
225 		switch (state)						\
226 		{							\
227 		  case SMFIR_REPLYCODE:					\
228 			if (MilterLogLevel > 3)				\
229 			{						\
230 				sm_syslog(LOG_INFO, e->e_id,		\
231 					  "Milter: %s=%s, reject=%s",	\
232 					  str, addr, response);		\
233 				LogUsrErrs = false;			\
234 			}						\
235 			usrerr(response);				\
236 			break;						\
237 									\
238 		  case SMFIR_REJECT:					\
239 			if (MilterLogLevel > 3)				\
240 			{						\
241 				sm_syslog(LOG_INFO, e->e_id,		\
242 					  "Milter: %s=%s, reject=550 5.7.1 Command rejected", \
243 					  str, addr);			\
244 				LogUsrErrs = false;			\
245 			}						\
246 			usrerr("550 5.7.1 Command rejected");		\
247 			break;						\
248 									\
249 		  case SMFIR_DISCARD:					\
250 			if (MilterLogLevel > 3)				\
251 				sm_syslog(LOG_INFO, e->e_id,		\
252 					  "Milter: %s=%s, discard",	\
253 					  str, addr);			\
254 			e->e_flags |= EF_DISCARD;			\
255 			break;						\
256 									\
257 		  case SMFIR_TEMPFAIL:					\
258 			if (MilterLogLevel > 3)				\
259 			{						\
260 				sm_syslog(LOG_INFO, e->e_id,		\
261 					  "Milter: %s=%s, reject=%s",	\
262 					  str, addr, MSG_TEMPFAIL);	\
263 				LogUsrErrs = false;			\
264 			}						\
265 			usrerr(MSG_TEMPFAIL);				\
266 			break;						\
267 		}							\
268 		LogUsrErrs = savelogusrerrs;				\
269 		if (response != NULL)					\
270 			sm_free(response); /* XXX */			\
271 	}
272 
273 #else /* MILTER */
274 # define MILTER_ABORT(e)
275 #endif /* MILTER */
276 
277 /* clear all SMTP state (for HELO/EHLO/RSET) */
278 #define CLEAR_STATE(cmd)					\
279 {								\
280 	/* abort milter filters */				\
281 	MILTER_ABORT(e);					\
282 								\
283 	if (smtp.sm_nrcpts > 0)					\
284 	{							\
285 		logundelrcpts(e, cmd, 10, false);		\
286 		smtp.sm_nrcpts = 0;				\
287 		macdefine(&e->e_macro, A_PERM,			\
288 			  macid("{nrcpts}"), "0");		\
289 	}							\
290 								\
291 	e->e_sendqueue = NULL;					\
292 	e->e_flags |= EF_CLRQUEUE;				\
293 								\
294 	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))	\
295 		logsender(e, NULL);				\
296 	e->e_flags &= ~EF_LOGSENDER;				\
297 								\
298 	/* clean up a bit */					\
299 	smtp.sm_gotmail = false;				\
300 	SuprErrs = true;					\
301 	dropenvelope(e, true, false);				\
302 	sm_rpool_free(e->e_rpool);				\
303 	e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL));	\
304 	CurEnv = e;						\
305 }
306 
307 /* sleep to flatten out connection load */
308 #define MIN_DELAY_LOG	15	/* wait before logging this again */
309 
310 /* is it worth setting the process title for 1s? */
311 #define DELAY_CONN(cmd)						\
312 	if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA)	\
313 	{							\
314 		time_t dnow;					\
315 								\
316 		sm_setproctitle(true, e,			\
317 				"%s: %s: delaying %s: load average: %d", \
318 				qid_printname(e), CurSmtpClient,	\
319 				cmd, DelayLA);	\
320 		if (LogLevel > 8 && (dnow = curtime()) > log_delay)	\
321 		{						\
322 			sm_syslog(LOG_INFO, e->e_id,		\
323 				  "delaying=%s, load average=%d >= %d",	\
324 				  cmd, CurrentLA, DelayLA);		\
325 			log_delay = dnow + MIN_DELAY_LOG;	\
326 		}						\
327 		(void) sleep(1);				\
328 		sm_setproctitle(true, e, "%s %s: %.80s",	\
329 				qid_printname(e), CurSmtpClient, inp);	\
330 	}
331 
332 
333 void
334 smtp(nullserver, d_flags, e)
335 	char *volatile nullserver;
336 	BITMAP256 d_flags;
337 	register ENVELOPE *volatile e;
338 {
339 	register char *volatile p;
340 	register struct cmd *volatile c = NULL;
341 	char *cmd;
342 	auto ADDRESS *vrfyqueue;
343 	ADDRESS *a;
344 	volatile bool gothello;		/* helo command received */
345 	bool vrfy;			/* set if this is a vrfy command */
346 	char *volatile protocol;	/* sending protocol */
347 	char *volatile sendinghost;	/* sending hostname */
348 	char *volatile peerhostname;	/* name of SMTP peer or "localhost" */
349 	auto char *delimptr;
350 	char *id;
351 	volatile unsigned int n_badcmds = 0;	/* count of bad commands */
352 	volatile unsigned int n_badrcpts = 0;	/* number of rejected RCPT */
353 	volatile unsigned int n_verifies = 0;	/* count of VRFY/EXPN */
354 	volatile unsigned int n_etrn = 0;	/* count of ETRN */
355 	volatile unsigned int n_noop = 0;	/* count of NOOP/VERB/etc */
356 	volatile unsigned int n_helo = 0;	/* count of HELO/EHLO */
357 	bool ok;
358 #if _FFR_ADAPTIVE_EOL
359 	volatile bool first;
360 #endif /* _FFR_ADAPTIVE_EOL */
361 	volatile bool tempfail = false;
362 	volatile time_t wt;		/* timeout after too many commands */
363 	volatile time_t previous;	/* time after checksmtpattack() */
364 	volatile bool lognullconnection = true;
365 	register char *q;
366 	SMTP_T smtp;
367 	char *addr;
368 	char *greetcode = "220";
369 	char *hostname;			/* my hostname ($j) */
370 	QUEUE_CHAR *new;
371 	int argno;
372 	char *args[MAXSMTPARGS];
373 	char inp[MAXLINE];
374 	char cmdbuf[MAXLINE];
375 #if SASL
376 	sasl_conn_t *conn;
377 	volatile bool sasl_ok;
378 	volatile unsigned int n_auth = 0;	/* count of AUTH commands */
379 	bool ismore;
380 	int result;
381 	volatile int authenticating;
382 	char *user;
383 	char *in, *out, *out2;
384 	const char *errstr;
385 	unsigned int inlen, out2len;
386 	unsigned int outlen;
387 	char *volatile auth_type;
388 	char *mechlist;
389 	volatile unsigned int n_mechs;
390 	unsigned int len;
391 	sasl_security_properties_t ssp;
392 	sasl_external_properties_t ext_ssf;
393 	sasl_ssf_t *ssf;
394 #endif /* SASL */
395 #if STARTTLS
396 	int r;
397 	int rfd, wfd;
398 	volatile bool tls_active = false;
399 # if _FFR_SMTP_SSL
400 	volatile bool smtps = false;
401 # endif /* _FFR_SMTP_SSL */
402 	bool saveQuickAbort;
403 	bool saveSuprErrs;
404 	time_t tlsstart;
405 #endif /* STARTTLS */
406 	volatile unsigned int features;
407 #if PIPELINING
408 # if _FFR_NO_PIPE
409 	int np_log = 0;
410 # endif /* _FFR_NO_PIPE */
411 #endif /* PIPELINING */
412 	volatile time_t log_delay = (time_t) 0;
413 
414 	smtp.sm_nrcpts = 0;
415 #if MILTER
416 	smtp.sm_milterize = (nullserver == NULL);
417 	smtp.sm_milterlist = false;
418 #endif /* MILTER */
419 
420 	/* setup I/O fd correctly for the SMTP server */
421 	setup_smtpd_io();
422 
423 #if SM_HEAP_CHECK
424 	if (sm_debug_active(&DebugLeakSmtp, 1))
425 	{
426 		sm_heap_newgroup();
427 		sm_dprintf("smtp() heap group #%d\n", sm_heap_group());
428 	}
429 #endif /* SM_HEAP_CHECK */
430 
431 	/* XXX the rpool should be set when e is initialized in main() */
432 	e->e_rpool = sm_rpool_new_x(NULL);
433 	e->e_macro.mac_rpool = e->e_rpool;
434 
435 	settime(e);
436 	sm_getla();
437 	peerhostname = RealHostName;
438 	if (peerhostname == NULL)
439 		peerhostname = "localhost";
440 	CurHostName = peerhostname;
441 	CurSmtpClient = macvalue('_', e);
442 	if (CurSmtpClient == NULL)
443 		CurSmtpClient = CurHostName;
444 
445 	/* check_relay may have set discard bit, save for later */
446 	smtp.sm_discard = bitset(EF_DISCARD, e->e_flags);
447 
448 #if PIPELINING
449 	/* auto-flush output when reading input */
450 	(void) sm_io_autoflush(InChannel, OutChannel);
451 #endif /* PIPELINING */
452 
453 	sm_setproctitle(true, e, "server %s startup", CurSmtpClient);
454 
455 	/* Set default features for server. */
456 	features = ((bitset(PRIV_NOETRN, PrivacyFlags) ||
457 		     bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN)
458 		| (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE)
459 		| (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE
460 			: (SRV_OFFER_EXPN
461 			  | (bitset(PRIV_NOVERB, PrivacyFlags)
462 			     ? SRV_NONE : SRV_OFFER_VERB)))
463 		| (bitset(PRIV_NORECEIPTS, PrivacyFlags) ? SRV_NONE
464 							 : SRV_OFFER_DSN)
465 #if SASL
466 		| (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH)
467 #endif /* SASL */
468 #if PIPELINING
469 		| SRV_OFFER_PIPE
470 #endif /* PIPELINING */
471 #if STARTTLS
472 		| (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS)
473 		| (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
474 						       : SRV_VRFY_CLT)
475 #endif /* STARTTLS */
476 		;
477 	if (nullserver == NULL)
478 	{
479 		features = srvfeatures(e, CurSmtpClient, features);
480 		if (bitset(SRV_TMP_FAIL, features))
481 		{
482 			if (LogLevel > 4)
483 				sm_syslog(LOG_ERR, NOQID,
484 					  "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled",
485 					  CurSmtpClient);
486 			nullserver = "450 4.3.0 Please try again later.";
487 		}
488 #if PIPELINING
489 # if _FFR_NO_PIPE
490 		else if (bitset(SRV_NO_PIPE, features))
491 		{
492 			/* for consistency */
493 			features &= ~SRV_OFFER_PIPE;
494 		}
495 # endif /* _FFR_NO_PIPE */
496 #endif /* PIPELINING */
497 	}
498 
499 	hostname = macvalue('j', e);
500 
501 
502 #if SASL
503 	sasl_ok = bitset(SRV_OFFER_AUTH, features);
504 	n_mechs = 0;
505 	authenticating = SASL_NOT_AUTH;
506 
507 	/* SASL server new connection */
508 	if (sasl_ok)
509 	{
510 # if SASL > 10505
511 		/* use empty realm: only works in SASL > 1.5.5 */
512 		result = sasl_server_new("smtp", hostname, "", NULL, 0, &conn);
513 # else /* SASL > 10505 */
514 		/* use no realm -> realm is set to hostname by SASL lib */
515 		result = sasl_server_new("smtp", hostname, NULL, NULL, 0,
516 					 &conn);
517 # endif /* SASL > 10505 */
518 		sasl_ok = result == SASL_OK;
519 		if (!sasl_ok)
520 		{
521 			if (LogLevel > 9)
522 				sm_syslog(LOG_WARNING, NOQID,
523 					  "AUTH error: sasl_server_new failed=%d",
524 					  result);
525 		}
526 	}
527 	if (sasl_ok)
528 	{
529 		/*
530 		**  SASL set properties for sasl
531 		**  set local/remote IP
532 		**  XXX only IPv4: Cyrus SASL doesn't support anything else
533 		**
534 		**  XXX where exactly are these used/required?
535 		**  Kerberos_v4
536 		*/
537 
538 # if NETINET
539 		in = macvalue(macid("{daemon_family}"), e);
540 		if (in != NULL && strcmp(in, "inet") == 0)
541 		{
542 			SOCKADDR_LEN_T addrsize;
543 			struct sockaddr_in saddr_l;
544 			struct sockaddr_in saddr_r;
545 
546 			addrsize = sizeof(struct sockaddr_in);
547 			if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
548 						      NULL),
549 					(struct sockaddr *)&saddr_r,
550 					&addrsize) == 0)
551 			{
552 				sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r);
553 				addrsize = sizeof(struct sockaddr_in);
554 				if (getsockname(sm_io_getinfo(InChannel,
555 							      SM_IO_WHAT_FD,
556 							      NULL),
557 						(struct sockaddr *)&saddr_l,
558 						&addrsize) == 0)
559 					sasl_setprop(conn, SASL_IP_LOCAL,
560 						     &saddr_l);
561 			}
562 		}
563 # endif /* NETINET */
564 
565 		auth_type = NULL;
566 		mechlist = NULL;
567 		user = NULL;
568 # if 0
569 		macdefine(&BlankEnvelope.e_macro, A_PERM,
570 			macid("{auth_author}"), NULL);
571 # endif /* 0 */
572 
573 		/* set properties */
574 		(void) memset(&ssp, '\0', sizeof ssp);
575 
576 		/* XXX should these be options settable via .cf ? */
577 		/* ssp.min_ssf = 0; is default due to memset() */
578 # if STARTTLS
579 # endif /* STARTTLS */
580 		{
581 			ssp.max_ssf = MaxSLBits;
582 			ssp.maxbufsize = MAXOUTLEN;
583 		}
584 		ssp.security_flags = SASLOpts & SASL_SEC_MASK;
585 		sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK;
586 
587 		if (sasl_ok)
588 		{
589 			/*
590 			**  external security strength factor;
591 			**	currently we have none so zero
592 			*/
593 
594 			ext_ssf.ssf = 0;
595 			ext_ssf.auth_id = NULL;
596 			sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
597 					       &ext_ssf) == SASL_OK;
598 		}
599 		if (sasl_ok)
600 			n_mechs = saslmechs(conn, &mechlist);
601 	}
602 #endif /* SASL */
603 
604 #if MILTER
605 	if (smtp.sm_milterize)
606 	{
607 		char state;
608 
609 		/* initialize mail filter connection */
610 		smtp.sm_milterlist = milter_init(e, &state);
611 		switch (state)
612 		{
613 		  case SMFIR_REJECT:
614 			if (MilterLogLevel > 3)
615 				sm_syslog(LOG_INFO, e->e_id,
616 					  "Milter: initialization failed, rejecting commands");
617 			greetcode = "554";
618 			nullserver = "Command rejected";
619 			smtp.sm_milterize = false;
620 			break;
621 
622 		  case SMFIR_TEMPFAIL:
623 			if (MilterLogLevel > 3)
624 				sm_syslog(LOG_INFO, e->e_id,
625 					  "Milter: initialization failed, temp failing commands");
626 			tempfail = true;
627 			smtp.sm_milterize = false;
628 			break;
629 		}
630 	}
631 
632 	if (smtp.sm_milterlist && smtp.sm_milterize &&
633 	    !bitset(EF_DISCARD, e->e_flags))
634 	{
635 		char state;
636 		char *response;
637 
638 		response = milter_connect(peerhostname, RealHostAddr,
639 					  e, &state);
640 		switch (state)
641 		{
642 		  case SMFIR_REPLYCODE:	/* REPLYCODE shouldn't happen */
643 		  case SMFIR_REJECT:
644 			if (MilterLogLevel > 3)
645 				sm_syslog(LOG_INFO, e->e_id,
646 					  "Milter: connect: host=%s, addr=%s, rejecting commands",
647 					  peerhostname,
648 					  anynet_ntoa(&RealHostAddr));
649 			greetcode = "554";
650 			nullserver = "Command rejected";
651 			smtp.sm_milterize = false;
652 			break;
653 
654 		  case SMFIR_TEMPFAIL:
655 			if (MilterLogLevel > 3)
656 				sm_syslog(LOG_INFO, e->e_id,
657 					  "Milter: connect: host=%s, addr=%s, temp failing commands",
658 					  peerhostname,
659 					  anynet_ntoa(&RealHostAddr));
660 			tempfail = true;
661 			smtp.sm_milterize = false;
662 			break;
663 		}
664 		if (response != NULL)
665 
666 			sm_free(response); /* XXX */
667 	}
668 #endif /* MILTER */
669 
670 #if STARTTLS
671 # if _FFR_SMTP_SSL
672 	/* If this an smtps connection, start TLS now */
673 	smtps = bitnset(D_SMTPS, d_flags);
674 	if (smtps)
675 		goto starttls;
676 
677   greeting:
678 
679 # endif /* _FFR_SMTP_SSL */
680 #endif /* STARTTLS */
681 
682 	/* output the first line, inserting "ESMTP" as second word */
683 	if (*greetcode == '5')
684 		(void) sm_snprintf(inp, sizeof inp, "%s not accepting messages",
685 				   hostname);
686 	else
687 		expand(SmtpGreeting, inp, sizeof inp, e);
688 
689 	p = strchr(inp, '\n');
690 	if (p != NULL)
691 		*p++ = '\0';
692 	id = strchr(inp, ' ');
693 	if (id == NULL)
694 		id = &inp[strlen(inp)];
695 	if (p == NULL)
696 		(void) sm_snprintf(cmdbuf, sizeof cmdbuf,
697 			 "%s %%.*s ESMTP%%s", greetcode);
698 	else
699 		(void) sm_snprintf(cmdbuf, sizeof cmdbuf,
700 			 "%s-%%.*s ESMTP%%s", greetcode);
701 	message(cmdbuf, (int) (id - inp), inp, id);
702 
703 	/* output remaining lines */
704 	while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL)
705 	{
706 		*p++ = '\0';
707 		if (isascii(*id) && isspace(*id))
708 			id++;
709 		(void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, "-%s");
710 		message(cmdbuf, id);
711 	}
712 	if (id != NULL)
713 	{
714 		if (isascii(*id) && isspace(*id))
715 			id++;
716 		(void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, " %s");
717 		message(cmdbuf, id);
718 	}
719 
720 	protocol = NULL;
721 	sendinghost = macvalue('s', e);
722 
723 #if _FFR_QUARANTINE
724 	/* If quarantining by a connect/ehlo action, save between messages */
725 	if (e->e_quarmsg == NULL)
726 		smtp.sm_quarmsg = NULL;
727 	else
728 		smtp.sm_quarmsg = newstr(e->e_quarmsg);
729 #endif /* _FFR_QUARANTINE */
730 
731 	/* sendinghost's storage must outlive the current envelope */
732 	if (sendinghost != NULL)
733 		sendinghost = sm_strdup_x(sendinghost);
734 #if _FFR_ADAPTIVE_EOL
735 	first = true;
736 #endif /* _FFR_ADAPTIVE_EOL */
737 	gothello = false;
738 	smtp.sm_gotmail = false;
739 	for (;;)
740 	{
741 	    SM_TRY
742 	    {
743 		QuickAbort = false;
744 		HoldErrs = false;
745 		SuprErrs = false;
746 		LogUsrErrs = false;
747 		OnlyOneError = true;
748 		e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
749 
750 		/* setup for the read */
751 		e->e_to = NULL;
752 		Errors = 0;
753 		FileName = NULL;
754 		(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
755 
756 		/* read the input line */
757 		SmtpPhase = "server cmd read";
758 		sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient);
759 #if SASL
760 		/*
761 		**  XXX SMTP AUTH requires accepting any length,
762 		**	at least for challenge/response
763 		*/
764 #endif /* SASL */
765 
766 		/* handle errors */
767 		if (sm_io_error(OutChannel) ||
768 		    (p = sfgets(inp, sizeof inp, InChannel,
769 				TimeOuts.to_nextcommand, SmtpPhase)) == NULL)
770 		{
771 			char *d;
772 
773 			d = macvalue(macid("{daemon_name}"), e);
774 			if (d == NULL)
775 				d = "stdin";
776 			/* end of file, just die */
777 			disconnect(1, e);
778 
779 #if MILTER
780 			/* close out milter filters */
781 			milter_quit(e);
782 #endif /* MILTER */
783 
784 			message("421 4.4.1 %s Lost input channel from %s",
785 				MyHostName, CurSmtpClient);
786 			if (LogLevel > (smtp.sm_gotmail ? 1 : 19))
787 				sm_syslog(LOG_NOTICE, e->e_id,
788 					  "lost input channel from %.100s to %s after %s",
789 					  CurSmtpClient, d,
790 					  (c == NULL || c->cmd_name == NULL) ? "startup" : c->cmd_name);
791 			/*
792 			**  If have not accepted mail (DATA), do not bounce
793 			**  bad addresses back to sender.
794 			*/
795 
796 			if (bitset(EF_CLRQUEUE, e->e_flags))
797 				e->e_sendqueue = NULL;
798 			goto doquit;
799 		}
800 
801 #if _FFR_ADAPTIVE_EOL
802 		if (first)
803 		{
804 			char *p;
805 
806 			smtp.sm_crlf = true;
807 			p = strchr(inp, '\n');
808 			if (p == NULL || p <= inp || p[-1] != '\r')
809 			{
810 				smtp.sm_crlf = false;
811 				if (tTd(66, 1) && LogLevel > 8)
812 				{
813 					/* how many bad guys are there? */
814 					sm_syslog(LOG_INFO, NOQID,
815 						  "%.100s did not use CRLF",
816 						  CurSmtpClient);
817 				}
818 			}
819 			first = false;
820 		}
821 #endif /* _FFR_ADAPTIVE_EOL */
822 
823 		/* clean up end of line */
824 		fixcrlf(inp, true);
825 
826 #if PIPELINING
827 # if _FFR_NO_PIPE
828 		/*
829 		**  if there is more input and pipelining is disabled:
830 		**	delay ... (and maybe discard the input?)
831 		**  XXX this doesn't really work, at least in tests using
832 		**  telnet SM_IO_IS_READABLE only returns 1 if there were
833 		**  more than 2 input lines available.
834 		*/
835 
836 		if (bitset(SRV_NO_PIPE, features) &&
837 		    sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL))
838 		{
839 			if (++np_log < 3)
840 				sm_syslog(LOG_INFO, NOQID,
841 					  "unauthorized PIPELINING, sleeping");
842 			sleep(1);
843 		}
844 
845 # endif /* _FFR_NO_PIPE */
846 #endif /* PIPELINING */
847 
848 #if SASL
849 		if (authenticating == SASL_PROC_AUTH)
850 		{
851 # if 0
852 			if (*inp == '\0')
853 			{
854 				authenticating = SASL_NOT_AUTH;
855 				message("501 5.5.2 missing input");
856 				continue;
857 			}
858 # endif /* 0 */
859 			if (*inp == '*' && *(inp + 1) == '\0')
860 			{
861 				authenticating = SASL_NOT_AUTH;
862 
863 				/* rfc 2254 4. */
864 				message("501 5.0.0 AUTH aborted");
865 				continue;
866 			}
867 
868 			/* could this be shorter? XXX */
869 			out = xalloc(strlen(inp));
870 			result = sasl_decode64(inp, strlen(inp), out, &outlen);
871 			if (result != SASL_OK)
872 			{
873 				authenticating = SASL_NOT_AUTH;
874 
875 				/* rfc 2254 4. */
876 				message("501 5.5.4 cannot decode AUTH parameter %s",
877 					inp);
878 				continue;
879 			}
880 
881 			result = sasl_server_step(conn,	out, outlen,
882 						  &out, &outlen, &errstr);
883 
884 			/* get an OK if we're done */
885 			if (result == SASL_OK)
886 			{
887   authenticated:
888 				message("235 2.0.0 OK Authenticated");
889 				authenticating = SASL_IS_AUTH;
890 				macdefine(&BlankEnvelope.e_macro, A_TEMP,
891 					macid("{auth_type}"), auth_type);
892 
893 				result = sasl_getprop(conn, SASL_USERNAME,
894 						      (void **)&user);
895 				if (result != SASL_OK)
896 				{
897 					user = "";
898 					macdefine(&BlankEnvelope.e_macro,
899 						  A_PERM,
900 						  macid("{auth_authen}"), NULL);
901 				}
902 				else
903 				{
904 					macdefine(&BlankEnvelope.e_macro,
905 						  A_TEMP,
906 						  macid("{auth_authen}"), user);
907 				}
908 
909 # if 0
910 				/* get realm? */
911 				sasl_getprop(conn, SASL_REALM, (void **) &data);
912 # endif /* 0 */
913 
914 				/* get security strength (features) */
915 				result = sasl_getprop(conn, SASL_SSF,
916 						      (void **) &ssf);
917 				if (result != SASL_OK)
918 				{
919 					macdefine(&BlankEnvelope.e_macro,
920 						  A_PERM,
921 						  macid("{auth_ssf}"), "0");
922 					ssf = NULL;
923 				}
924 				else
925 				{
926 					char pbuf[8];
927 
928 					(void) sm_snprintf(pbuf, sizeof pbuf,
929 							   "%u", *ssf);
930 					macdefine(&BlankEnvelope.e_macro,
931 						  A_TEMP,
932 						  macid("{auth_ssf}"), pbuf);
933 					if (tTd(95, 8))
934 						sm_dprintf("AUTH auth_ssf: %u\n",
935 							   *ssf);
936 				}
937 
938 				/*
939 				**  Only switch to encrypted connection
940 				**  if a security layer has been negotiated
941 				*/
942 
943 				if (ssf != NULL && *ssf > 0)
944 				{
945 					/*
946 					**  Convert I/O layer to use SASL.
947 					**  If the call fails, the connection
948 					**  is aborted.
949 					*/
950 
951 					if (sfdcsasl(&InChannel, &OutChannel,
952 						     conn) == 0)
953 					{
954 						/* restart dialogue */
955 						n_helo = 0;
956 # if PIPELINING
957 						(void) sm_io_autoflush(InChannel,
958 								       OutChannel);
959 # endif /* PIPELINING */
960 					}
961 					else
962 						syserr("503 5.3.3 SASL TLS failed");
963 				}
964 
965 				/* NULL pointer ok since it's our function */
966 				if (LogLevel > 8)
967 					sm_syslog(LOG_INFO, NOQID,
968 						  "AUTH=server, relay=%.100s, authid=%.128s, mech=%.16s, bits=%d",
969 						  CurSmtpClient,
970 						  shortenstring(user, 128),
971 						  auth_type, *ssf);
972 			}
973 			else if (result == SASL_CONTINUE)
974 			{
975 				len = ENC64LEN(outlen);
976 				out2 = xalloc(len);
977 				result = sasl_encode64(out, outlen, out2, len,
978 						       &out2len);
979 				if (result != SASL_OK)
980 				{
981 					/* correct code? XXX */
982 					/* 454 Temp. authentication failure */
983 					message("454 4.5.4 Internal error: unable to encode64");
984 					if (LogLevel > 5)
985 						sm_syslog(LOG_WARNING, e->e_id,
986 							  "AUTH encode64 error [%d for \"%s\"]",
987 							  result, out);
988 					/* start over? */
989 					authenticating = SASL_NOT_AUTH;
990 				}
991 				else
992 				{
993 					message("334 %s", out2);
994 					if (tTd(95, 2))
995 						sm_dprintf("AUTH continue: msg='%s' len=%u\n",
996 							   out2, out2len);
997 				}
998 			}
999 			else
1000 			{
1001 				/* not SASL_OK or SASL_CONT */
1002 				message("500 5.7.0 authentication failed");
1003 				if (LogLevel > 9)
1004 					sm_syslog(LOG_WARNING, e->e_id,
1005 						  "AUTH failure (%s): %s (%d) %s",
1006 						  auth_type,
1007 						  sasl_errstring(result, NULL,
1008 								 NULL),
1009 						  result,
1010 						  errstr == NULL ? "" : errstr);
1011 				authenticating = SASL_NOT_AUTH;
1012 			}
1013 		}
1014 		else
1015 		{
1016 			/* don't want to do any of this if authenticating */
1017 #endif /* SASL */
1018 
1019 		/* echo command to transcript */
1020 		if (e->e_xfp != NULL)
1021 			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
1022 					     "<<< %s\n", inp);
1023 
1024 		if (LogLevel > 14)
1025 			sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp);
1026 
1027 		/* break off command */
1028 		for (p = inp; isascii(*p) && isspace(*p); p++)
1029 			continue;
1030 		cmd = cmdbuf;
1031 		while (*p != '\0' &&
1032 		       !(isascii(*p) && isspace(*p)) &&
1033 		       cmd < &cmdbuf[sizeof cmdbuf - 2])
1034 			*cmd++ = *p++;
1035 		*cmd = '\0';
1036 
1037 		/* throw away leading whitespace */
1038 		SKIP_SPACE(p);
1039 
1040 		/* decode command */
1041 		for (c = CmdTab; c->cmd_name != NULL; c++)
1042 		{
1043 			if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0)
1044 				break;
1045 		}
1046 
1047 		/* reset errors */
1048 		errno = 0;
1049 
1050 		/* check whether a "non-null" command has been used */
1051 		switch (c->cmd_code)
1052 		{
1053 #if SASL
1054 		  case CMDAUTH:
1055 			/* avoid information leak; take first two words? */
1056 			q = "AUTH";
1057 			break;
1058 #endif /* SASL */
1059 
1060 		  case CMDMAIL:
1061 		  case CMDEXPN:
1062 		  case CMDVRFY:
1063 		  case CMDETRN:
1064 			lognullconnection = false;
1065 			/* FALLTHROUGH */
1066 		  default:
1067 			q = inp;
1068 			break;
1069 		}
1070 
1071 		if (e->e_id == NULL)
1072 			sm_setproctitle(true, e, "%s: %.80s",
1073 					CurSmtpClient, q);
1074 		else
1075 			sm_setproctitle(true, e, "%s %s: %.80s",
1076 					qid_printname(e),
1077 					CurSmtpClient, q);
1078 
1079 		/*
1080 		**  Process command.
1081 		**
1082 		**	If we are running as a null server, return 550
1083 		**	to almost everything.
1084 		*/
1085 
1086 		if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags))
1087 		{
1088 			switch (c->cmd_code)
1089 			{
1090 			  case CMDQUIT:
1091 			  case CMDHELO:
1092 			  case CMDEHLO:
1093 			  case CMDNOOP:
1094 			  case CMDRSET:
1095 				/* process normally */
1096 				break;
1097 
1098 			  case CMDETRN:
1099 				if (bitnset(D_ETRNONLY, d_flags) &&
1100 				    nullserver == NULL)
1101 					break;
1102 				DELAY_CONN("ETRN");
1103 				/* FALLTHROUGH */
1104 
1105 			  default:
1106 #if MAXBADCOMMANDS > 0
1107 				/* theoretically this could overflow */
1108 				if (nullserver != NULL &&
1109 				    ++n_badcmds > MAXBADCOMMANDS)
1110 				{
1111 					message("421 4.7.0 %s Too many bad commands; closing connection",
1112 						MyHostName);
1113 
1114 					/* arrange to ignore send list */
1115 					e->e_sendqueue = NULL;
1116 					goto doquit;
1117 				}
1118 #endif /* MAXBADCOMMANDS > 0 */
1119 				if (nullserver != NULL)
1120 				{
1121 					if (ISSMTPREPLY(nullserver))
1122 						usrerr(nullserver);
1123 					else
1124 						usrerr("550 5.0.0 %s",
1125 						       nullserver);
1126 				}
1127 				else
1128 					usrerr("452 4.4.5 Insufficient disk space; try again later");
1129 				continue;
1130 			}
1131 		}
1132 
1133 		switch (c->cmd_code)
1134 		{
1135 #if SASL
1136 		  case CMDAUTH: /* sasl */
1137 			DELAY_CONN("AUTH");
1138 			if (!sasl_ok || n_mechs <= 0)
1139 			{
1140 				message("503 5.3.3 AUTH not available");
1141 				break;
1142 			}
1143 			if (authenticating == SASL_IS_AUTH)
1144 			{
1145 				message("503 5.5.0 Already Authenticated");
1146 				break;
1147 			}
1148 			if (smtp.sm_gotmail)
1149 			{
1150 				message("503 5.5.0 AUTH not permitted during a mail transaction");
1151 				break;
1152 			}
1153 			if (tempfail)
1154 			{
1155 				if (LogLevel > 9)
1156 					sm_syslog(LOG_INFO, e->e_id,
1157 						  "SMTP AUTH command (%.100s) from %.100s tempfailed (due to previous checks)",
1158 						  p, CurSmtpClient);
1159 				usrerr("454 4.7.1 Please try again later");
1160 				break;
1161 			}
1162 
1163 			ismore = false;
1164 
1165 			/* crude way to avoid crack attempts */
1166 			(void) checksmtpattack(&n_auth, n_mechs + 1, true,
1167 					       "AUTH", e);
1168 
1169 			/* make sure mechanism (p) is a valid string */
1170 			for (q = p; *q != '\0' && isascii(*q); q++)
1171 			{
1172 				if (isspace(*q))
1173 				{
1174 					*q = '\0';
1175 					while (*++q != '\0' &&
1176 					       isascii(*q) && isspace(*q))
1177 						continue;
1178 					*(q - 1) = '\0';
1179 					ismore = (*q != '\0');
1180 					break;
1181 				}
1182 			}
1183 
1184 			/* check whether mechanism is available */
1185 			if (iteminlist(p, mechlist, " ") == NULL)
1186 			{
1187 				message("503 5.3.3 AUTH mechanism %.32s not available",
1188 					p);
1189 				break;
1190 			}
1191 
1192 			if (ismore)
1193 			{
1194 				/* could this be shorter? XXX */
1195 				in = sm_rpool_malloc(e->e_rpool, strlen(q));
1196 				result = sasl_decode64(q, strlen(q), in,
1197 						       &inlen);
1198 				if (result != SASL_OK)
1199 				{
1200 					message("501 5.5.4 cannot BASE64 decode '%s'",
1201 						q);
1202 					if (LogLevel > 5)
1203 						sm_syslog(LOG_WARNING, e->e_id,
1204 							  "AUTH decode64 error [%d for \"%s\"]",
1205 							  result, q);
1206 					/* start over? */
1207 					authenticating = SASL_NOT_AUTH;
1208 					in = NULL;
1209 					inlen = 0;
1210 					break;
1211 				}
1212 			}
1213 			else
1214 			{
1215 				in = NULL;
1216 				inlen = 0;
1217 			}
1218 
1219 			/* see if that auth type exists */
1220 			result = sasl_server_start(conn, p, in, inlen,
1221 						   &out, &outlen, &errstr);
1222 
1223 			if (result != SASL_OK && result != SASL_CONTINUE)
1224 			{
1225 				message("500 5.7.0 authentication failed");
1226 				if (LogLevel > 9)
1227 					sm_syslog(LOG_ERR, e->e_id,
1228 						  "AUTH failure (%s): %s (%d) %s",
1229 						  p,
1230 						  sasl_errstring(result, NULL,
1231 								 NULL),
1232 						  result,
1233 						  errstr);
1234 				break;
1235 			}
1236 			auth_type = newstr(p);
1237 
1238 			if (result == SASL_OK)
1239 			{
1240 				/* ugly, but same code */
1241 				goto authenticated;
1242 				/* authenticated by the initial response */
1243 			}
1244 
1245 			/* len is at least 2 */
1246 			len = ENC64LEN(outlen);
1247 			out2 = xalloc(len);
1248 			result = sasl_encode64(out, outlen, out2, len,
1249 					       &out2len);
1250 
1251 			if (result != SASL_OK)
1252 			{
1253 				message("454 4.5.4 Temporary authentication failure");
1254 				if (LogLevel > 5)
1255 					sm_syslog(LOG_WARNING, e->e_id,
1256 						  "AUTH encode64 error [%d for \"%s\"]",
1257 						  result, out);
1258 
1259 				/* start over? */
1260 				authenticating = SASL_NOT_AUTH;
1261 			}
1262 			else
1263 			{
1264 				message("334 %s", out2);
1265 				authenticating = SASL_PROC_AUTH;
1266 			}
1267 			break;
1268 #endif /* SASL */
1269 
1270 #if STARTTLS
1271 		  case CMDSTLS: /* starttls */
1272 			DELAY_CONN("STARTTLS");
1273 			if (*p != '\0')
1274 			{
1275 				message("501 5.5.2 Syntax error (no parameters allowed)");
1276 				break;
1277 			}
1278 			if (!bitset(SRV_OFFER_TLS, features))
1279 			{
1280 				message("503 5.5.0 TLS not available");
1281 				break;
1282 			}
1283 			if (!tls_ok_srv)
1284 			{
1285 				message("454 4.3.3 TLS not available after start");
1286 				break;
1287 			}
1288 			if (smtp.sm_gotmail)
1289 			{
1290 				message("503 5.5.0 TLS not permitted during a mail transaction");
1291 				break;
1292 			}
1293 			if (tempfail)
1294 			{
1295 				if (LogLevel > 9)
1296 					sm_syslog(LOG_INFO, e->e_id,
1297 						  "SMTP STARTTLS command (%.100s) from %.100s tempfailed (due to previous checks)",
1298 						  p, CurSmtpClient);
1299 				usrerr("454 4.7.1 Please try again later");
1300 				break;
1301 			}
1302 # if _FFR_SMTP_SSL
1303   starttls:
1304 # endif /* _FFR_SMTP_SSL */
1305 # if TLS_NO_RSA
1306 			/*
1307 			**  XXX do we need a temp key ?
1308 			*/
1309 # else /* TLS_NO_RSA */
1310 # endif /* TLS_NO_RSA */
1311 
1312 # if TLS_VRFY_PER_CTX
1313 			/*
1314 			**  Note: this sets the verification globally
1315 			**  (per SSL_CTX)
1316 			**  it's ok since it applies only to one transaction
1317 			*/
1318 
1319 			TLS_VERIFY_CLIENT();
1320 # endif /* TLS_VRFY_PER_CTX */
1321 
1322 			if (srv_ssl != NULL)
1323 				SSL_clear(srv_ssl);
1324 			else if ((srv_ssl = SSL_new(srv_ctx)) == NULL)
1325 			{
1326 				message("454 4.3.3 TLS not available: error generating SSL handle");
1327 # if _FFR_SMTP_SSL
1328 				goto tls_done;
1329 # else /* _FFR_SMTP_SSL */
1330 				break;
1331 # endif /* _FFR_SMTP_SSL */
1332 			}
1333 
1334 # if !TLS_VRFY_PER_CTX
1335 			/*
1336 			**  this could be used if it were possible to set
1337 			**  verification per SSL (connection)
1338 			**  not just per SSL_CTX (global)
1339 			*/
1340 
1341 			TLS_VERIFY_CLIENT();
1342 # endif /* !TLS_VRFY_PER_CTX */
1343 
1344 			rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
1345 			wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
1346 
1347 			if (rfd < 0 || wfd < 0 ||
1348 			    SSL_set_rfd(srv_ssl, rfd) <= 0 ||
1349 			    SSL_set_wfd(srv_ssl, wfd) <= 0)
1350 			{
1351 				message("454 4.3.3 TLS not available: error set fd");
1352 				SSL_free(srv_ssl);
1353 				srv_ssl = NULL;
1354 # if _FFR_SMTP_SSL
1355 				goto tls_done;
1356 # else /* _FFR_SMTP_SSL */
1357 				break;
1358 # endif /* _FFR_SMTP_SSL */
1359 			}
1360 # if _FFR_SMTP_SSL
1361 			if (!smtps)
1362 # endif /* _FFR_SMTP_SSL */
1363 				message("220 2.0.0 Ready to start TLS");
1364 # if PIPELINING
1365 			(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
1366 # endif /* PIPELINING */
1367 
1368 			SSL_set_accept_state(srv_ssl);
1369 
1370 #  define SSL_ACC(s)	SSL_accept(s)
1371 
1372 			tlsstart = curtime();
1373   ssl_retry:
1374 			if ((r = SSL_ACC(srv_ssl)) <= 0)
1375 			{
1376 				int i;
1377 				bool timedout;
1378 				time_t left;
1379 				time_t now = curtime();
1380 				struct timeval tv;
1381 
1382 				/* what to do in this case? */
1383 				i = SSL_get_error(srv_ssl, r);
1384 
1385 				/*
1386 				**  For SSL_ERROR_WANT_{READ,WRITE}:
1387 				**  There is no SSL record available yet
1388 				**  or there is only a partial SSL record
1389 				**  removed from the network (socket) buffer
1390 				**  into the SSL buffer. The SSL_accept will
1391 				**  only succeed when a full SSL record is
1392 				**  available (assuming a "real" error
1393 				**  doesn't happen). To handle when a "real"
1394 				**  error does happen the select is set for
1395 				**  exceptions too.
1396 				**  The connection may be re-negotiated
1397 				**  during this time so both read and write
1398 				**  "want errors" need to be handled.
1399 				**  A select() exception loops back so that
1400 				**  a proper SSL error message can be gotten.
1401 				*/
1402 
1403 				left = TimeOuts.to_starttls - (now - tlsstart);
1404 				timedout = left <= 0;
1405 				if (!timedout)
1406 				{
1407 					tv.tv_sec = left;
1408 					tv.tv_usec = 0;
1409 				}
1410 
1411 				/* XXX what about SSL_pending() ? */
1412 				if (!timedout && i == SSL_ERROR_WANT_READ)
1413 				{
1414 					fd_set ssl_maskr, ssl_maskx;
1415 
1416 					FD_ZERO(&ssl_maskr);
1417 					FD_SET(rfd, &ssl_maskr);
1418 					FD_ZERO(&ssl_maskx);
1419 					FD_SET(rfd, &ssl_maskx);
1420 					if (select(rfd + 1, &ssl_maskr, NULL,
1421 						   &ssl_maskx, &tv) > 0)
1422 						goto ssl_retry;
1423 				}
1424 				if (!timedout && i == SSL_ERROR_WANT_WRITE)
1425 				{
1426 					fd_set ssl_maskw, ssl_maskx;
1427 
1428 					FD_ZERO(&ssl_maskw);
1429 					FD_SET(wfd, &ssl_maskw);
1430 					FD_ZERO(&ssl_maskx);
1431 					FD_SET(rfd, &ssl_maskx);
1432 					if (select(wfd + 1, NULL, &ssl_maskw,
1433 						   &ssl_maskx, &tv) > 0)
1434 						goto ssl_retry;
1435 				}
1436 				if (LogLevel > 5)
1437 				{
1438 					sm_syslog(LOG_WARNING, NOQID,
1439 						  "STARTTLS=server, error: accept failed=%d, SSL_error=%d, timedout=%d",
1440 						  r, i, (int) timedout);
1441 					if (LogLevel > 8)
1442 						tlslogerr("server");
1443 				}
1444 				tls_ok_srv = false;
1445 				SSL_free(srv_ssl);
1446 				srv_ssl = NULL;
1447 
1448 				/*
1449 				**  according to the next draft of
1450 				**  RFC 2487 the connection should be dropped
1451 				*/
1452 
1453 				/* arrange to ignore any current send list */
1454 				e->e_sendqueue = NULL;
1455 				goto doquit;
1456 			}
1457 
1458 			/* ignore return code for now, it's in {verify} */
1459 			(void) tls_get_info(srv_ssl, true,
1460 					    CurSmtpClient,
1461 					    &BlankEnvelope.e_macro,
1462 					    bitset(SRV_VRFY_CLT, features));
1463 
1464 			/*
1465 			**  call Stls_client to find out whether
1466 			**  to accept the connection from the client
1467 			*/
1468 
1469 			saveQuickAbort = QuickAbort;
1470 			saveSuprErrs = SuprErrs;
1471 			SuprErrs = true;
1472 			QuickAbort = false;
1473 			if (rscheck("tls_client",
1474 				     macvalue(macid("{verify}"), e),
1475 				     "STARTTLS", e, true, true, 5,
1476 				     NULL, NOQID) != EX_OK ||
1477 			    Errors > 0)
1478 			{
1479 				extern char MsgBuf[];
1480 
1481 				if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf))
1482 					nullserver = newstr(MsgBuf);
1483 				else
1484 					nullserver = "503 5.7.0 Authentication required.";
1485 			}
1486 			QuickAbort = saveQuickAbort;
1487 			SuprErrs = saveSuprErrs;
1488 
1489 			tls_ok_srv = false;	/* don't offer STARTTLS again */
1490 			n_helo = 0;
1491 # if SASL
1492 			if (sasl_ok)
1493 			{
1494 				char *s;
1495 
1496 				s = macvalue(macid("{cipher_bits}"), e);
1497 				if (s != NULL && (ext_ssf.ssf = atoi(s)) > 0)
1498 				{
1499 					ext_ssf.auth_id = macvalue(macid("{cert_subject}"),
1500 								   e);
1501 					sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
1502 							       &ext_ssf) == SASL_OK;
1503 					mechlist = NULL;
1504 					if (sasl_ok)
1505 						n_mechs = saslmechs(conn,
1506 								    &mechlist);
1507 				}
1508 			}
1509 # endif /* SASL */
1510 
1511 			/* switch to secure connection */
1512 			if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0)
1513 			{
1514 				tls_active = true;
1515 # if PIPELINING
1516 				(void) sm_io_autoflush(InChannel, OutChannel);
1517 # endif /* PIPELINING */
1518 			}
1519 			else
1520 			{
1521 				/*
1522 				**  XXX this is an internal error
1523 				**  how to deal with it?
1524 				**  we can't generate an error message
1525 				**  since the other side switched to an
1526 				**  encrypted layer, but we could not...
1527 				**  just "hang up"?
1528 				*/
1529 
1530 				nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer";
1531 				syserr("STARTTLS: can't switch to encrypted layer");
1532 			}
1533 # if _FFR_SMTP_SSL
1534 		  tls_done:
1535 			if (smtps)
1536 			{
1537 				if (tls_active)
1538 					goto greeting;
1539 				else
1540 					goto doquit;
1541 			}
1542 # endif /* _FFR_SMTP_SSL */
1543 			break;
1544 #endif /* STARTTLS */
1545 
1546 		  case CMDHELO:		/* hello -- introduce yourself */
1547 		  case CMDEHLO:		/* extended hello */
1548 			DELAY_CONN("EHLO");
1549 			if (c->cmd_code == CMDEHLO)
1550 			{
1551 				protocol = "ESMTP";
1552 				SmtpPhase = "server EHLO";
1553 			}
1554 			else
1555 			{
1556 				protocol = "SMTP";
1557 				SmtpPhase = "server HELO";
1558 			}
1559 
1560 			/* avoid denial-of-service */
1561 			(void) checksmtpattack(&n_helo, MAXHELOCOMMANDS, true,
1562 					       "HELO/EHLO", e);
1563 
1564 #if 0
1565 			/* RFC2821 4.1.4 allows duplicate HELO/EHLO */
1566 			/* check for duplicate HELO/EHLO per RFC 1651 4.2 */
1567 			if (gothello)
1568 			{
1569 				usrerr("503 %s Duplicate HELO/EHLO",
1570 				       MyHostName);
1571 				break;
1572 			}
1573 #endif /* 0 */
1574 
1575 			/* check for valid domain name (re 1123 5.2.5) */
1576 			if (*p == '\0' && !AllowBogusHELO)
1577 			{
1578 				usrerr("501 %s requires domain address",
1579 					cmdbuf);
1580 				break;
1581 			}
1582 
1583 			/* check for long domain name (hides Received: info) */
1584 			if (strlen(p) > MAXNAME)
1585 			{
1586 				usrerr("501 Invalid domain name");
1587 				if (LogLevel > 9)
1588 					sm_syslog(LOG_INFO, CurEnv->e_id,
1589 						  "invalid domain name (too long) from %.100s",
1590 						  CurSmtpClient);
1591 				break;
1592 			}
1593 
1594 			for (q = p; *q != '\0'; q++)
1595 			{
1596 				if (!isascii(*q))
1597 					break;
1598 				if (isalnum(*q))
1599 					continue;
1600 				if (isspace(*q))
1601 				{
1602 					*q = '\0';
1603 					break;
1604 				}
1605 				if (strchr("[].-_#", *q) == NULL)
1606 					break;
1607 			}
1608 
1609 			if (*q == '\0')
1610 			{
1611 				q = "pleased to meet you";
1612 				sendinghost = sm_strdup_x(p);
1613 			}
1614 			else if (!AllowBogusHELO)
1615 			{
1616 				usrerr("501 Invalid domain name");
1617 				if (LogLevel > 9)
1618 					sm_syslog(LOG_INFO, CurEnv->e_id,
1619 						  "invalid domain name (%.100s) from %.100s",
1620 						  p, CurSmtpClient);
1621 				break;
1622 			}
1623 			else
1624 			{
1625 				q = "accepting invalid domain name";
1626 			}
1627 
1628 			if (gothello)
1629 			{
1630 				CLEAR_STATE(cmdbuf);
1631 
1632 #if _FFR_QUARANTINE
1633 				/* restore connection quarantining */
1634 				if (smtp.sm_quarmsg == NULL)
1635 				{
1636 					e->e_quarmsg = NULL;
1637 					macdefine(&e->e_macro, A_PERM,
1638 						  macid("{quarantine}"), "");
1639 				}
1640 				else
1641 				{
1642 					e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
1643 									 smtp.sm_quarmsg);
1644 					macdefine(&e->e_macro, A_PERM,
1645 						  macid("{quarantine}"),
1646 						  e->e_quarmsg);
1647 				}
1648 #endif /* _FFR_QUARANTINE */
1649 			}
1650 
1651 #if MILTER
1652 			if (smtp.sm_milterlist && smtp.sm_milterize &&
1653 			    !bitset(EF_DISCARD, e->e_flags))
1654 			{
1655 				char state;
1656 				char *response;
1657 
1658 				response = milter_helo(p, e, &state);
1659 				switch (state)
1660 				{
1661 				  case SMFIR_REPLYCODE:
1662 					if (MilterLogLevel > 3)
1663 						sm_syslog(LOG_INFO, e->e_id,
1664 							  "Milter: helo=%s, reject=%s",
1665 							  p, response);
1666 					nullserver = newstr(response);
1667 					smtp.sm_milterize = false;
1668 					break;
1669 
1670 				  case SMFIR_REJECT:
1671 					if (MilterLogLevel > 3)
1672 						sm_syslog(LOG_INFO, e->e_id,
1673 							  "Milter: helo=%s, reject=Command rejected",
1674 							  p);
1675 					nullserver = "Command rejected";
1676 					smtp.sm_milterize = false;
1677 					break;
1678 
1679 				  case SMFIR_TEMPFAIL:
1680 					if (MilterLogLevel > 3)
1681 						sm_syslog(LOG_INFO, e->e_id,
1682 							  "Milter: helo=%s, reject=%s",
1683 							  p, MSG_TEMPFAIL);
1684 					tempfail = true;
1685 					smtp.sm_milterize = false;
1686 					break;
1687 				}
1688 				if (response != NULL)
1689 					sm_free(response);
1690 
1691 # if _FFR_QUARANTINE
1692 				/*
1693 				**  If quarantining by a connect/ehlo action,
1694 				**  save between messages
1695 				*/
1696 
1697 				if (smtp.sm_quarmsg == NULL &&
1698 				    e->e_quarmsg != NULL)
1699 					smtp.sm_quarmsg = newstr(e->e_quarmsg);
1700 # endif /* _FFR_QUARANTINE */
1701 			}
1702 #endif /* MILTER */
1703 			gothello = true;
1704 
1705 			/* print HELO response message */
1706 			if (c->cmd_code != CMDEHLO)
1707 			{
1708 				message("250 %s Hello %s, %s",
1709 					MyHostName, CurSmtpClient, q);
1710 				break;
1711 			}
1712 
1713 			message("250-%s Hello %s, %s",
1714 				MyHostName, CurSmtpClient, q);
1715 
1716 			/* offer ENHSC even for nullserver */
1717 			if (nullserver != NULL)
1718 			{
1719 				message("250 ENHANCEDSTATUSCODES");
1720 				break;
1721 			}
1722 
1723 			/*
1724 			**  print EHLO features list
1725 			**
1726 			**  Note: If you change this list,
1727 			**	  remember to update 'helpfile'
1728 			*/
1729 
1730 			message("250-ENHANCEDSTATUSCODES");
1731 #if PIPELINING
1732 			if (bitset(SRV_OFFER_PIPE, features))
1733 				message("250-PIPELINING");
1734 #endif /* PIPELINING */
1735 			if (bitset(SRV_OFFER_EXPN, features))
1736 			{
1737 				message("250-EXPN");
1738 				if (bitset(SRV_OFFER_VERB, features))
1739 					message("250-VERB");
1740 			}
1741 #if MIME8TO7
1742 			message("250-8BITMIME");
1743 #endif /* MIME8TO7 */
1744 			if (MaxMessageSize > 0)
1745 				message("250-SIZE %ld", MaxMessageSize);
1746 			else
1747 				message("250-SIZE");
1748 #if DSN
1749 			if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features))
1750 				message("250-DSN");
1751 #endif /* DSN */
1752 			if (bitset(SRV_OFFER_ETRN, features))
1753 				message("250-ETRN");
1754 #if SASL
1755 			if (sasl_ok && mechlist != NULL && *mechlist != '\0')
1756 				message("250-AUTH %s", mechlist);
1757 #endif /* SASL */
1758 #if STARTTLS
1759 			if (tls_ok_srv && bitset(SRV_OFFER_TLS, features))
1760 				message("250-STARTTLS");
1761 #endif /* STARTTLS */
1762 			if (DeliverByMin > 0)
1763 				message("250-DELIVERBY %ld",
1764 					(long) DeliverByMin);
1765 			else if (DeliverByMin == 0)
1766 				message("250-DELIVERBY");
1767 
1768 			/* < 0: no deliver-by */
1769 
1770 			message("250 HELP");
1771 			break;
1772 
1773 		  case CMDMAIL:		/* mail -- designate sender */
1774 			SmtpPhase = "server MAIL";
1775 			DELAY_CONN("MAIL");
1776 
1777 			/* check for validity of this command */
1778 			if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
1779 			{
1780 				usrerr("503 5.0.0 Polite people say HELO first");
1781 				break;
1782 			}
1783 			if (smtp.sm_gotmail)
1784 			{
1785 				usrerr("503 5.5.0 Sender already specified");
1786 				break;
1787 			}
1788 #if SASL
1789 			if (bitset(SRV_REQ_AUTH, features) &&
1790 			    authenticating != SASL_IS_AUTH)
1791 			{
1792 				usrerr("530 5.7.0 Authentication required");
1793 				break;
1794 			}
1795 #endif /* SASL */
1796 
1797 			p = skipword(p, "from");
1798 			if (p == NULL)
1799 				break;
1800 			if (tempfail)
1801 			{
1802 				if (LogLevel > 9)
1803 					sm_syslog(LOG_INFO, e->e_id,
1804 						  "SMTP MAIL command (%.100s) from %.100s tempfailed (due to previous checks)",
1805 						  p, CurSmtpClient);
1806 				usrerr(MSG_TEMPFAIL);
1807 				break;
1808 			}
1809 
1810 			/* make sure we know who the sending host is */
1811 			if (sendinghost == NULL)
1812 				sendinghost = peerhostname;
1813 
1814 
1815 #if SM_HEAP_CHECK
1816 			if (sm_debug_active(&DebugLeakSmtp, 1))
1817 			{
1818 				sm_heap_newgroup();
1819 				sm_dprintf("smtp() heap group #%d\n",
1820 					sm_heap_group());
1821 			}
1822 #endif /* SM_HEAP_CHECK */
1823 
1824 			if (Errors > 0)
1825 				goto undo_no_pm;
1826 			if (!gothello)
1827 			{
1828 				auth_warning(e, "%s didn't use HELO protocol",
1829 					     CurSmtpClient);
1830 			}
1831 #ifdef PICKY_HELO_CHECK
1832 			if (sm_strcasecmp(sendinghost, peerhostname) != 0 &&
1833 			    (sm_strcasecmp(peerhostname, "localhost") != 0 ||
1834 			     sm_strcasecmp(sendinghost, MyHostName) != 0))
1835 			{
1836 				auth_warning(e, "Host %s claimed to be %s",
1837 					     CurSmtpClient, sendinghost);
1838 			}
1839 #endif /* PICKY_HELO_CHECK */
1840 
1841 			if (protocol == NULL)
1842 				protocol = "SMTP";
1843 			macdefine(&e->e_macro, A_PERM, 'r', protocol);
1844 			macdefine(&e->e_macro, A_PERM, 's', sendinghost);
1845 
1846 			if (Errors > 0)
1847 				goto undo_no_pm;
1848 			smtp.sm_nrcpts = 0;
1849 			n_badrcpts = 0;
1850 			macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0");
1851 			macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0");
1852 			e->e_flags |= EF_CLRQUEUE;
1853 			sm_setproctitle(true, e, "%s %s: %.80s",
1854 					qid_printname(e),
1855 					CurSmtpClient, inp);
1856 
1857 			/* do the processing */
1858 		    SM_TRY
1859 		    {
1860 			extern char *FullName;
1861 
1862 			QuickAbort = true;
1863 			SM_FREE_CLR(FullName);
1864 
1865 			/* must parse sender first */
1866 			delimptr = NULL;
1867 			setsender(p, e, &delimptr, ' ', false);
1868 			if (delimptr != NULL && *delimptr != '\0')
1869 				*delimptr++ = '\0';
1870 			if (Errors > 0)
1871 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
1872 
1873 			/* Successfully set e_from, allow logging */
1874 			e->e_flags |= EF_LOGSENDER;
1875 
1876 			/* put resulting triple from parseaddr() into macros */
1877 			if (e->e_from.q_mailer != NULL)
1878 				 macdefine(&e->e_macro, A_PERM,
1879 					macid("{mail_mailer}"),
1880 					e->e_from.q_mailer->m_name);
1881 			else
1882 				 macdefine(&e->e_macro, A_PERM,
1883 					macid("{mail_mailer}"), NULL);
1884 			if (e->e_from.q_host != NULL)
1885 				macdefine(&e->e_macro, A_PERM,
1886 					macid("{mail_host}"),
1887 					e->e_from.q_host);
1888 			else
1889 				macdefine(&e->e_macro, A_PERM,
1890 					macid("{mail_host}"), "localhost");
1891 			if (e->e_from.q_user != NULL)
1892 				macdefine(&e->e_macro, A_PERM,
1893 					macid("{mail_addr}"),
1894 					e->e_from.q_user);
1895 			else
1896 				macdefine(&e->e_macro, A_PERM,
1897 					macid("{mail_addr}"), NULL);
1898 			if (Errors > 0)
1899 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
1900 
1901 			/* check for possible spoofing */
1902 			if (RealUid != 0 && OpMode == MD_SMTP &&
1903 			    !wordinclass(RealUserName, 't') &&
1904 			    (!bitnset(M_LOCALMAILER,
1905 				      e->e_from.q_mailer->m_flags) ||
1906 			     strcmp(e->e_from.q_user, RealUserName) != 0))
1907 			{
1908 				auth_warning(e, "%s owned process doing -bs",
1909 					RealUserName);
1910 			}
1911 
1912 			/* now parse ESMTP arguments */
1913 			e->e_msgsize = 0;
1914 			addr = p;
1915 			argno = 0;
1916 			args[argno++] = p;
1917 			p = delimptr;
1918 			while (p != NULL && *p != '\0')
1919 			{
1920 				char *kp;
1921 				char *vp = NULL;
1922 				char *equal = NULL;
1923 
1924 				/* locate the beginning of the keyword */
1925 				SKIP_SPACE(p);
1926 				if (*p == '\0')
1927 					break;
1928 				kp = p;
1929 
1930 				/* skip to the value portion */
1931 				while ((isascii(*p) && isalnum(*p)) || *p == '-')
1932 					p++;
1933 				if (*p == '=')
1934 				{
1935 					equal = p;
1936 					*p++ = '\0';
1937 					vp = p;
1938 
1939 					/* skip to the end of the value */
1940 					while (*p != '\0' && *p != ' ' &&
1941 					       !(isascii(*p) && iscntrl(*p)) &&
1942 					       *p != '=')
1943 						p++;
1944 				}
1945 
1946 				if (*p != '\0')
1947 					*p++ = '\0';
1948 
1949 				if (tTd(19, 1))
1950 					sm_dprintf("MAIL: got arg %s=\"%s\"\n", kp,
1951 						vp == NULL ? "<null>" : vp);
1952 
1953 				mail_esmtp_args(kp, vp, e);
1954 				if (equal != NULL)
1955 					*equal = '=';
1956 				args[argno++] = kp;
1957 				if (argno >= MAXSMTPARGS - 1)
1958 					usrerr("501 5.5.4 Too many parameters");
1959 				if (Errors > 0)
1960 					sm_exc_raisenew_x(&EtypeQuickAbort, 1);
1961 			}
1962 			args[argno] = NULL;
1963 			if (Errors > 0)
1964 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
1965 
1966 #if SASL
1967 # if _FFR_AUTH_PASSING
1968 			/* set the default AUTH= if the sender didn't */
1969 			if (e->e_auth_param == NULL)
1970 			{
1971 				/* XXX only do this for an MSA? */
1972 				e->e_auth_param = macvalue(macid("{auth_authen}"),
1973 							   e);
1974 				if (e->e_auth_param == NULL)
1975 					e->e_auth_param = "<>";
1976 
1977 				/*
1978 				**  XXX should we invoke Strust_auth now?
1979 				**  authorizing as the client that just
1980 				**  authenticated, so we'll trust implicitly
1981 				*/
1982 			}
1983 # endif /* _FFR_AUTH_PASSING */
1984 #endif /* SASL */
1985 
1986 			/* do config file checking of the sender */
1987 			macdefine(&e->e_macro, A_PERM,
1988 				macid("{addr_type}"), "e s");
1989 #if _FFR_MAIL_MACRO
1990 			/* make the "real" sender address available */
1991 			macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"),
1992 				  e->e_from.q_paddr);
1993 #endif /* _FFR_MAIL_MACRO */
1994 			if (rscheck("check_mail", addr,
1995 				    NULL, e, true, true, 3, NULL,
1996 				    e->e_id) != EX_OK ||
1997 			    Errors > 0)
1998 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
1999 			macdefine(&e->e_macro, A_PERM,
2000 				  macid("{addr_type}"), NULL);
2001 
2002 			if (MaxMessageSize > 0 &&
2003 			    (e->e_msgsize > MaxMessageSize ||
2004 			     e->e_msgsize < 0))
2005 			{
2006 				usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)",
2007 					MaxMessageSize);
2008 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2009 			}
2010 
2011 			/*
2012 			**  XXX always check whether there is at least one fs
2013 			**  with enough space?
2014 			**  However, this may not help much: the queue group
2015 			**  selection may later on select a FS that hasn't
2016 			**  enough space.
2017 			*/
2018 
2019 			if ((NumFileSys == 1 || NumQueue == 1) &&
2020 			    !enoughdiskspace(e->e_msgsize, e)
2021 #if _FFR_ANY_FREE_FS
2022 			    && !filesys_free(e->e_msgsize)
2023 #endif /* _FFR_ANY_FREE_FS */
2024 			   )
2025 			{
2026 				/*
2027 				**  We perform this test again when the
2028 				**  queue directory is selected, in collect.
2029 				*/
2030 
2031 				usrerr("452 4.4.5 Insufficient disk space; try again later");
2032 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2033 			}
2034 			if (Errors > 0)
2035 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2036 
2037 			LogUsrErrs = true;
2038 #if MILTER
2039 			if (smtp.sm_milterlist && smtp.sm_milterize &&
2040 			    !bitset(EF_DISCARD, e->e_flags))
2041 			{
2042 				char state;
2043 				char *response;
2044 
2045 				response = milter_envfrom(args, e, &state);
2046 				MILTER_REPLY("from");
2047 			}
2048 #endif /* MILTER */
2049 			if (Errors > 0)
2050 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2051 
2052 			message("250 2.1.0 Sender ok");
2053 			smtp.sm_gotmail = true;
2054 		    }
2055 		    SM_EXCEPT(exc, "[!F]*")
2056 		    {
2057 			/*
2058 			**  An error occurred while processing a MAIL command.
2059 			**  Jump to the common error handling code.
2060 			*/
2061 
2062 			sm_exc_free(exc);
2063 			goto undo_no_pm;
2064 		    }
2065 		    SM_END_TRY
2066 			break;
2067 
2068 		  undo_no_pm:
2069 			e->e_flags &= ~EF_PM_NOTIFY;
2070 		  undo:
2071 			break;
2072 
2073 		  case CMDRCPT:		/* rcpt -- designate recipient */
2074 			DELAY_CONN("RCPT");
2075 			if (!smtp.sm_gotmail)
2076 			{
2077 				usrerr("503 5.0.0 Need MAIL before RCPT");
2078 				break;
2079 			}
2080 			SmtpPhase = "server RCPT";
2081 		    SM_TRY
2082 		    {
2083 			QuickAbort = true;
2084 			LogUsrErrs = true;
2085 
2086 			/* limit flooding of our machine */
2087 			if (MaxRcptPerMsg > 0 &&
2088 			    smtp.sm_nrcpts >= MaxRcptPerMsg)
2089 			{
2090 				/* sleep(1); / * slow down? */
2091 				usrerr("452 4.5.3 Too many recipients");
2092 				goto rcpt_done;
2093 			}
2094 
2095 			if (e->e_sendmode != SM_DELIVER)
2096 				e->e_flags |= EF_VRFYONLY;
2097 
2098 #if MILTER
2099 			/*
2100 			**  If the filter will be deleting recipients,
2101 			**  don't expand them at RCPT time (in the call
2102 			**  to recipient()).  If they are expanded, it
2103 			**  is impossible for removefromlist() to figure
2104 			**  out the expanded members of the original
2105 			**  recipient and mark them as QS_DONTSEND.
2106 			*/
2107 
2108 			if (milter_can_delrcpts())
2109 				e->e_flags |= EF_VRFYONLY;
2110 #endif /* MILTER */
2111 
2112 			p = skipword(p, "to");
2113 			if (p == NULL)
2114 				goto rcpt_done;
2115 			macdefine(&e->e_macro, A_PERM,
2116 				macid("{addr_type}"), "e r");
2117 			a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr,
2118 				      e, true);
2119 			macdefine(&e->e_macro, A_PERM,
2120 				macid("{addr_type}"), NULL);
2121 			if (BadRcptThrottle > 0 &&
2122 			    n_badrcpts >= BadRcptThrottle)
2123 			{
2124 				if (LogLevel > 5 &&
2125 				    n_badrcpts == BadRcptThrottle)
2126 				{
2127 					sm_syslog(LOG_INFO, e->e_id,
2128 						  "%.100s: Possible SMTP RCPT flood, throttling.",
2129 						  CurSmtpClient);
2130 
2131 					/* To avoid duplicated message */
2132 					n_badrcpts++;
2133 				}
2134 
2135 				/*
2136 				**  Don't use exponential backoff for now.
2137 				**  Some servers will open more connections
2138 				**  and actually overload the receiver even
2139 				**  more.
2140 				*/
2141 
2142 				(void) sleep(1);
2143 			}
2144 			if (Errors > 0)
2145 				goto rcpt_done;
2146 			if (a == NULL)
2147 			{
2148 				usrerr("501 5.0.0 Missing recipient");
2149 				goto rcpt_done;
2150 			}
2151 
2152 			if (delimptr != NULL && *delimptr != '\0')
2153 				*delimptr++ = '\0';
2154 
2155 			/* put resulting triple from parseaddr() into macros */
2156 			if (a->q_mailer != NULL)
2157 				macdefine(&e->e_macro, A_PERM,
2158 					macid("{rcpt_mailer}"),
2159 					a->q_mailer->m_name);
2160 			else
2161 				macdefine(&e->e_macro, A_PERM,
2162 					macid("{rcpt_mailer}"), NULL);
2163 			if (a->q_host != NULL)
2164 				macdefine(&e->e_macro, A_PERM,
2165 					macid("{rcpt_host}"), a->q_host);
2166 			else
2167 				macdefine(&e->e_macro, A_PERM,
2168 					macid("{rcpt_host}"), "localhost");
2169 			if (a->q_user != NULL)
2170 				macdefine(&e->e_macro, A_PERM,
2171 					macid("{rcpt_addr}"), a->q_user);
2172 			else
2173 				macdefine(&e->e_macro, A_PERM,
2174 					macid("{rcpt_addr}"), NULL);
2175 			if (Errors > 0)
2176 				goto rcpt_done;
2177 
2178 			/* now parse ESMTP arguments */
2179 			addr = p;
2180 			argno = 0;
2181 			args[argno++] = p;
2182 			p = delimptr;
2183 			while (p != NULL && *p != '\0')
2184 			{
2185 				char *kp;
2186 				char *vp = NULL;
2187 				char *equal = NULL;
2188 
2189 				/* locate the beginning of the keyword */
2190 				SKIP_SPACE(p);
2191 				if (*p == '\0')
2192 					break;
2193 				kp = p;
2194 
2195 				/* skip to the value portion */
2196 				while ((isascii(*p) && isalnum(*p)) || *p == '-')
2197 					p++;
2198 				if (*p == '=')
2199 				{
2200 					equal = p;
2201 					*p++ = '\0';
2202 					vp = p;
2203 
2204 					/* skip to the end of the value */
2205 					while (*p != '\0' && *p != ' ' &&
2206 					       !(isascii(*p) && iscntrl(*p)) &&
2207 					       *p != '=')
2208 						p++;
2209 				}
2210 
2211 				if (*p != '\0')
2212 					*p++ = '\0';
2213 
2214 				if (tTd(19, 1))
2215 					sm_dprintf("RCPT: got arg %s=\"%s\"\n", kp,
2216 						vp == NULL ? "<null>" : vp);
2217 
2218 				rcpt_esmtp_args(a, kp, vp, e);
2219 				if (equal != NULL)
2220 					*equal = '=';
2221 				args[argno++] = kp;
2222 				if (argno >= MAXSMTPARGS - 1)
2223 					usrerr("501 5.5.4 Too many parameters");
2224 				if (Errors > 0)
2225 					break;
2226 			}
2227 			args[argno] = NULL;
2228 			if (Errors > 0)
2229 				goto rcpt_done;
2230 
2231 			/* do config file checking of the recipient */
2232 			macdefine(&e->e_macro, A_PERM,
2233 				macid("{addr_type}"), "e r");
2234 			if (rscheck("check_rcpt", addr,
2235 				    NULL, e, true, true, 3, NULL,
2236 				    e->e_id) != EX_OK ||
2237 			    Errors > 0)
2238 				goto rcpt_done;
2239 			macdefine(&e->e_macro, A_PERM,
2240 				macid("{addr_type}"), NULL);
2241 
2242 #if MILTER
2243 			if (smtp.sm_milterlist && smtp.sm_milterize &&
2244 			    !bitset(EF_DISCARD, e->e_flags))
2245 			{
2246 				char state;
2247 				char *response;
2248 
2249 				response = milter_envrcpt(args, e, &state);
2250 				MILTER_REPLY("to");
2251 			}
2252 #endif /* MILTER */
2253 
2254 			macdefine(&e->e_macro, A_PERM,
2255 				macid("{rcpt_mailer}"), NULL);
2256 			macdefine(&e->e_macro, A_PERM,
2257 				macid("{rcpt_relay}"), NULL);
2258 			macdefine(&e->e_macro, A_PERM,
2259 				macid("{rcpt_addr}"), NULL);
2260 			macdefine(&e->e_macro, A_PERM,
2261 				macid("{dsn_notify}"), NULL);
2262 			if (Errors > 0)
2263 				goto rcpt_done;
2264 
2265 			/* save in recipient list after ESMTP mods */
2266 			a = recipient(a, &e->e_sendqueue, 0, e);
2267 			if (Errors > 0)
2268 				goto rcpt_done;
2269 
2270 			/* no errors during parsing, but might be a duplicate */
2271 			e->e_to = a->q_paddr;
2272 			if (!QS_IS_BADADDR(a->q_state))
2273 			{
2274 				if (smtp.sm_nrcpts == 0)
2275 					initsys(e);
2276 				message("250 2.1.5 Recipient ok%s",
2277 					QS_IS_QUEUEUP(a->q_state) ?
2278 						" (will queue)" : "");
2279 				smtp.sm_nrcpts++;
2280 			}
2281 			else
2282 			{
2283 				/* punt -- should keep message in ADDRESS.... */
2284 				usrerr("550 5.1.1 Addressee unknown");
2285 			}
2286 		    rcpt_done:
2287 			if (Errors > 0)
2288 				++n_badrcpts;
2289 		    }
2290 		    SM_EXCEPT(exc, "[!F]*")
2291 		    {
2292 			/* An exception occurred while processing RCPT */
2293 			e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
2294 			++n_badrcpts;
2295 		    }
2296 		    SM_END_TRY
2297 			break;
2298 
2299 		  case CMDDATA:		/* data -- text of mail */
2300 			DELAY_CONN("DATA");
2301 			smtp_data(&smtp, e);
2302 			break;
2303 
2304 		  case CMDRSET:		/* rset -- reset state */
2305 			if (tTd(94, 100))
2306 				message("451 4.0.0 Test failure");
2307 			else
2308 				message("250 2.0.0 Reset state");
2309 			CLEAR_STATE(cmdbuf);
2310 #if _FFR_QUARANTINE
2311 			/* restore connection quarantining */
2312 			if (smtp.sm_quarmsg == NULL)
2313 			{
2314 				e->e_quarmsg = NULL;
2315 				macdefine(&e->e_macro, A_PERM,
2316 					  macid("{quarantine}"), "");
2317 			}
2318 			else
2319 			{
2320 				e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
2321 								 smtp.sm_quarmsg);
2322 				macdefine(&e->e_macro, A_PERM,
2323 					  macid("{quarantine}"), e->e_quarmsg);
2324 			}
2325 #endif /* _FFR_QUARANTINE */
2326 			break;
2327 
2328 		  case CMDVRFY:		/* vrfy -- verify address */
2329 		  case CMDEXPN:		/* expn -- expand address */
2330 			vrfy = c->cmd_code == CMDVRFY;
2331 			DELAY_CONN(vrfy ? "VRFY" : "EXPN");
2332 			if (tempfail)
2333 			{
2334 				if (LogLevel > 9)
2335 					sm_syslog(LOG_INFO, e->e_id,
2336 						  "SMTP %s command (%.100s) from %.100s tempfailed (due to previous checks)",
2337 						  vrfy ? "VRFY" : "EXPN",
2338 						  p, CurSmtpClient);
2339 
2340 				/* RFC 821 doesn't allow 4xy reply code */
2341 				usrerr("550 5.7.1 Please try again later");
2342 				break;
2343 			}
2344 			wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS,
2345 					     false, vrfy ? "VRFY" : "EXPN", e);
2346 			previous = curtime();
2347 			if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
2348 				   PrivacyFlags))
2349 			{
2350 				if (vrfy)
2351 					message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
2352 				else
2353 					message("502 5.7.0 Sorry, we do not allow this operation");
2354 				if (LogLevel > 5)
2355 					sm_syslog(LOG_INFO, e->e_id,
2356 						  "%.100s: %s [rejected]",
2357 						  CurSmtpClient,
2358 						  shortenstring(inp, MAXSHORTSTR));
2359 				break;
2360 			}
2361 			else if (!gothello &&
2362 				 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
2363 						PrivacyFlags))
2364 			{
2365 				usrerr("503 5.0.0 I demand that you introduce yourself first");
2366 				break;
2367 			}
2368 			if (Errors > 0)
2369 				break;
2370 			if (LogLevel > 5)
2371 				sm_syslog(LOG_INFO, e->e_id, "%.100s: %s",
2372 					  CurSmtpClient,
2373 					  shortenstring(inp, MAXSHORTSTR));
2374 		    SM_TRY
2375 		    {
2376 			QuickAbort = true;
2377 			vrfyqueue = NULL;
2378 			if (vrfy)
2379 				e->e_flags |= EF_VRFYONLY;
2380 			while (*p != '\0' && isascii(*p) && isspace(*p))
2381 				p++;
2382 			if (*p == '\0')
2383 			{
2384 				usrerr("501 5.5.2 Argument required");
2385 			}
2386 			else
2387 			{
2388 				/* do config file checking of the address */
2389 				if (rscheck(vrfy ? "check_vrfy" : "check_expn",
2390 					    p, NULL, e, true, false, 3, NULL,
2391 					    NOQID) != EX_OK ||
2392 				    Errors > 0)
2393 					sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2394 				(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
2395 			}
2396 			if (wt > 0)
2397 			{
2398 				time_t t;
2399 
2400 				t = wt - (curtime() - previous);
2401 				if (t > 0)
2402 					(void) sleep(t);
2403 			}
2404 			if (Errors > 0)
2405 				sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2406 			if (vrfyqueue == NULL)
2407 			{
2408 				usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN");
2409 			}
2410 			while (vrfyqueue != NULL)
2411 			{
2412 				if (!QS_IS_UNDELIVERED(vrfyqueue->q_state))
2413 				{
2414 					vrfyqueue = vrfyqueue->q_next;
2415 					continue;
2416 				}
2417 
2418 				/* see if there is more in the vrfy list */
2419 				a = vrfyqueue;
2420 				while ((a = a->q_next) != NULL &&
2421 				       (!QS_IS_UNDELIVERED(a->q_state)))
2422 					continue;
2423 				printvrfyaddr(vrfyqueue, a == NULL, vrfy);
2424 				vrfyqueue = a;
2425 			}
2426 		    }
2427 		    SM_EXCEPT(exc, "[!F]*")
2428 		    {
2429 			/*
2430 			**  An exception occurred while processing VRFY/EXPN
2431 			*/
2432 
2433 			sm_exc_free(exc);
2434 			goto undo;
2435 		    }
2436 		    SM_END_TRY
2437 			break;
2438 
2439 		  case CMDETRN:		/* etrn -- force queue flush */
2440 			DELAY_CONN("ETRN");
2441 
2442 			/* Don't leak queue information via debug flags */
2443 			if (!bitset(SRV_OFFER_ETRN, features) || UseMSP ||
2444 			    (RealUid != 0 && RealUid != TrustedUid &&
2445 			     OpMode == MD_SMTP))
2446 			{
2447 				/* different message for MSA ? */
2448 				message("502 5.7.0 Sorry, we do not allow this operation");
2449 				if (LogLevel > 5)
2450 					sm_syslog(LOG_INFO, e->e_id,
2451 						  "%.100s: %s [rejected]",
2452 						  CurSmtpClient,
2453 						  shortenstring(inp, MAXSHORTSTR));
2454 				break;
2455 			}
2456 			if (tempfail)
2457 			{
2458 				if (LogLevel > 9)
2459 					sm_syslog(LOG_INFO, e->e_id,
2460 						  "SMTP ETRN command (%.100s) from %.100s tempfailed (due to previous checks)",
2461 						  p, CurSmtpClient);
2462 				usrerr(MSG_TEMPFAIL);
2463 				break;
2464 			}
2465 
2466 			if (strlen(p) <= 0)
2467 			{
2468 				usrerr("500 5.5.2 Parameter required");
2469 				break;
2470 			}
2471 
2472 			/* crude way to avoid denial-of-service attacks */
2473 			(void) checksmtpattack(&n_etrn, MAXETRNCOMMANDS, true,
2474 					     "ETRN", e);
2475 
2476 			/*
2477 			**  Do config file checking of the parameter.
2478 			**  Even though we have srv_features now, we still
2479 			**  need this ruleset because the former is called
2480 			**  when the connection has been established, while
2481 			**  this ruleset is called when the command is
2482 			**  actually issued and therefore has all information
2483 			**  available to make a decision.
2484 			*/
2485 
2486 			if (rscheck("check_etrn", p, NULL, e, true, false, 3,
2487 				    NULL, NOQID) != EX_OK || Errors > 0)
2488 				break;
2489 
2490 			if (LogLevel > 5)
2491 				sm_syslog(LOG_INFO, e->e_id,
2492 					  "%.100s: ETRN %s", CurSmtpClient,
2493 					  shortenstring(p, MAXSHORTSTR));
2494 
2495 			id = p;
2496 			if (*id == '#')
2497 			{
2498 				int wgrp;
2499 
2500 				id++;
2501 				wgrp = name2qid(id);
2502 				if (!ISVALIDQGRP(wgrp))
2503 				{
2504 					usrerr("459 4.5.4 Queue %s unknown",
2505 					       id);
2506 					break;
2507 				}
2508 				ok = run_work_group(wgrp, true, false,
2509 						    false, true);
2510 				if (ok && Errors == 0)
2511 					message("250 2.0.0 Queuing for queue group %s started", id);
2512 				break;
2513 			}
2514 
2515 			if (*id == '@')
2516 				id++;
2517 			else
2518 				*--id = '@';
2519 
2520 			new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR));
2521 			if (new == NULL)
2522 			{
2523 				syserr("500 5.5.0 ETRN out of memory");
2524 				break;
2525 			}
2526 			new->queue_match = id;
2527 			new->queue_negate = false;
2528 			new->queue_next = NULL;
2529 			QueueLimitRecipient = new;
2530 			ok = runqueue(true, false, false, true);
2531 			sm_free(QueueLimitRecipient); /* XXX */
2532 			QueueLimitRecipient = NULL;
2533 			if (ok && Errors == 0)
2534 				message("250 2.0.0 Queuing for node %s started", p);
2535 			break;
2536 
2537 		  case CMDHELP:		/* help -- give user info */
2538 			DELAY_CONN("HELP");
2539 			help(p, e);
2540 			break;
2541 
2542 		  case CMDNOOP:		/* noop -- do nothing */
2543 			DELAY_CONN("NOOP");
2544 			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true,
2545 					       "NOOP", e);
2546 			message("250 2.0.0 OK");
2547 			break;
2548 
2549 		  case CMDQUIT:		/* quit -- leave mail */
2550 			message("221 2.0.0 %s closing connection", MyHostName);
2551 #if PIPELINING
2552 			(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
2553 #endif /* PIPELINING */
2554 
2555 			if (smtp.sm_nrcpts > 0)
2556 				logundelrcpts(e, "aborted by sender", 9, false);
2557 
2558 			/* arrange to ignore any current send list */
2559 			e->e_sendqueue = NULL;
2560 
2561 #if STARTTLS
2562 			/* shutdown TLS connection */
2563 			if (tls_active)
2564 			{
2565 				(void) endtls(srv_ssl, "server");
2566 				tls_active = false;
2567 			}
2568 #endif /* STARTTLS */
2569 #if SASL
2570 			if (authenticating == SASL_IS_AUTH)
2571 			{
2572 				sasl_dispose(&conn);
2573 				authenticating = SASL_NOT_AUTH;
2574 				/* XXX sasl_done(); this is a child */
2575 			}
2576 #endif /* SASL */
2577 
2578 doquit:
2579 			/* avoid future 050 messages */
2580 			disconnect(1, e);
2581 
2582 #if MILTER
2583 			/* close out milter filters */
2584 			milter_quit(e);
2585 #endif /* MILTER */
2586 
2587 			if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
2588 				logsender(e, NULL);
2589 			e->e_flags &= ~EF_LOGSENDER;
2590 
2591 			if (lognullconnection && LogLevel > 5)
2592 			{
2593 				char *d;
2594 
2595 				d = macvalue(macid("{daemon_name}"), e);
2596 				if (d == NULL)
2597 					d = "stdin";
2598 
2599 				/*
2600 				**  even though this id is "bogus", it makes
2601 				**  it simpler to "grep" related events, e.g.,
2602 				**  timeouts for the same connection.
2603 				*/
2604 
2605 				sm_syslog(LOG_INFO, e->e_id,
2606 					  "%.100s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s",
2607 					  CurSmtpClient, d);
2608 			}
2609 #if PROFILING
2610 			return;
2611 #endif /* PROFILING */
2612 			finis(true, true, ExitStat);
2613 			/* NOTREACHED */
2614 
2615 		  case CMDVERB:		/* set verbose mode */
2616 			DELAY_CONN("VERB");
2617 			if (bitset(PRIV_NOEXPN, PrivacyFlags) ||
2618 			    !bitset(SRV_OFFER_VERB, features) ||
2619 			    bitset(PRIV_NOVERB, PrivacyFlags))
2620 			{
2621 				/* this would give out the same info */
2622 				message("502 5.7.0 Verbose unavailable");
2623 				break;
2624 			}
2625 			(void) checksmtpattack(&n_noop, MAXNOOPCOMMANDS, true,
2626 					       "VERB", e);
2627 			Verbose = 1;
2628 			set_delivery_mode(SM_DELIVER, e);
2629 			message("250 2.0.0 Verbose mode");
2630 			break;
2631 
2632 #if SMTPDEBUG
2633 		  case CMDDBGQSHOW:	/* show queues */
2634 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
2635 					     "Send Queue=");
2636 			printaddr(e->e_sendqueue, true);
2637 			break;
2638 
2639 		  case CMDDBGDEBUG:	/* set debug mode */
2640 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
2641 			tTflag(p);
2642 			message("200 2.0.0 Debug set");
2643 			break;
2644 
2645 #else /* SMTPDEBUG */
2646 		  case CMDDBGQSHOW:	/* show queues */
2647 		  case CMDDBGDEBUG:	/* set debug mode */
2648 #endif /* SMTPDEBUG */
2649 		  case CMDLOGBOGUS:	/* bogus command */
2650 			DELAY_CONN("Bogus");
2651 			if (LogLevel > 0)
2652 				sm_syslog(LOG_CRIT, e->e_id,
2653 					  "\"%s\" command from %.100s (%.100s)",
2654 					  c->cmd_name, CurSmtpClient,
2655 					  anynet_ntoa(&RealHostAddr));
2656 			/* FALLTHROUGH */
2657 
2658 		  case CMDERROR:	/* unknown command */
2659 #if MAXBADCOMMANDS > 0
2660 			if (++n_badcmds > MAXBADCOMMANDS)
2661 			{
2662 				message("421 4.7.0 %s Too many bad commands; closing connection",
2663 					MyHostName);
2664 
2665 				/* arrange to ignore any current send list */
2666 				e->e_sendqueue = NULL;
2667 				goto doquit;
2668 			}
2669 #endif /* MAXBADCOMMANDS > 0 */
2670 
2671 			usrerr("500 5.5.1 Command unrecognized: \"%s\"",
2672 			       shortenstring(inp, MAXSHORTSTR));
2673 			break;
2674 
2675 		  case CMDUNIMPL:
2676 			DELAY_CONN("Unimpl");
2677 			usrerr("502 5.5.1 Command not implemented: \"%s\"",
2678 			       shortenstring(inp, MAXSHORTSTR));
2679 			break;
2680 
2681 		  default:
2682 			DELAY_CONN("default");
2683 			errno = 0;
2684 			syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code);
2685 			break;
2686 		}
2687 #if SASL
2688 		}
2689 #endif /* SASL */
2690 	    }
2691 	    SM_EXCEPT(exc, "[!F]*")
2692 	    {
2693 		/*
2694 		**  The only possible exception is "E:mta.quickabort".
2695 		**  There is nothing to do except fall through and loop.
2696 		*/
2697 	    }
2698 	    SM_END_TRY
2699 	}
2700 }
2701 /*
2702 **  SMTP_DATA -- implement the SMTP DATA command.
2703 **
2704 **	Parameters:
2705 **		smtp -- status of SMTP connection.
2706 **		e -- envelope.
2707 **
2708 **	Returns:
2709 **		none.
2710 **
2711 **	Side Effects:
2712 **		possibly sends message.
2713 */
2714 
2715 static void
2716 smtp_data(smtp, e)
2717 	SMTP_T *smtp;
2718 	ENVELOPE *e;
2719 {
2720 #if MILTER
2721 	bool milteraccept;
2722 #endif /* MILTER */
2723 	bool aborting;
2724 	bool doublequeue;
2725 	ADDRESS *a;
2726 	ENVELOPE *ee;
2727 	char *id;
2728 	char buf[32];
2729 
2730 	SmtpPhase = "server DATA";
2731 	if (!smtp->sm_gotmail)
2732 	{
2733 		usrerr("503 5.0.0 Need MAIL command");
2734 		return;
2735 	}
2736 	else if (smtp->sm_nrcpts <= 0)
2737 	{
2738 		usrerr("503 5.0.0 Need RCPT (recipient)");
2739 		return;
2740 	}
2741 	(void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts);
2742 	if (rscheck("check_data", buf, NULL, e,
2743 		    true, false, 3, NULL, e->e_id) != EX_OK)
2744 		return;
2745 
2746 	/* put back discard bit */
2747 	if (smtp->sm_discard)
2748 		e->e_flags |= EF_DISCARD;
2749 
2750 	/* check to see if we need to re-expand aliases */
2751 	/* also reset QS_BADADDR on already-diagnosted addrs */
2752 	doublequeue = false;
2753 	for (a = e->e_sendqueue; a != NULL; a = a->q_next)
2754 	{
2755 		if (QS_IS_VERIFIED(a->q_state) &&
2756 		    !bitset(EF_DISCARD, e->e_flags))
2757 		{
2758 			/* need to re-expand aliases */
2759 			doublequeue = true;
2760 		}
2761 		if (QS_IS_BADADDR(a->q_state))
2762 		{
2763 			/* make this "go away" */
2764 			a->q_state = QS_DONTSEND;
2765 		}
2766 	}
2767 
2768 	/* collect the text of the message */
2769 	SmtpPhase = "collect";
2770 	buffer_errors();
2771 
2772 #if _FFR_ADAPTIVE_EOL
2773 	/* triggers error in collect, disabled for now */
2774 	if (smtp->sm_crlf)
2775 		e->e_flags |= EF_NL_NOT_EOL;
2776 #endif /* _FFR_ADAPTIVE_EOL */
2777 
2778 	collect(InChannel, true, NULL, e);
2779 
2780 	/* redefine message size */
2781 	(void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
2782 	macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
2783 
2784 #if _FFR_CHECK_EOM
2785 	/* rscheck() will set Errors or EF_DISCARD if it trips */
2786 	(void) rscheck("check_eom", buf, NULL, e, false,
2787 		       true, 3, NULL, e->e_id);
2788 #endif /* _FFR_CHECK_EOM */
2789 
2790 #if MILTER
2791 	milteraccept = true;
2792 	if (smtp->sm_milterlist && smtp->sm_milterize &&
2793 	    Errors <= 0 &&
2794 	    !bitset(EF_DISCARD, e->e_flags))
2795 	{
2796 		char state;
2797 		char *response;
2798 
2799 		response = milter_data(e, &state);
2800 		switch (state)
2801 		{
2802 		  case SMFIR_REPLYCODE:
2803 			if (MilterLogLevel > 3)
2804 				sm_syslog(LOG_INFO, e->e_id,
2805 					  "Milter: data, reject=%s",
2806 					  response);
2807 			milteraccept = false;
2808 			usrerr(response);
2809 			break;
2810 
2811 		  case SMFIR_REJECT:
2812 			milteraccept = false;
2813 			if (MilterLogLevel > 3)
2814 				sm_syslog(LOG_INFO, e->e_id,
2815 					  "Milter: data, reject=554 5.7.1 Command rejected");
2816 			usrerr("554 5.7.1 Command rejected");
2817 			break;
2818 
2819 		  case SMFIR_DISCARD:
2820 			if (MilterLogLevel > 3)
2821 				sm_syslog(LOG_INFO, e->e_id,
2822 					  "Milter: data, discard");
2823 			milteraccept = false;
2824 			e->e_flags |= EF_DISCARD;
2825 			break;
2826 
2827 		  case SMFIR_TEMPFAIL:
2828 			if (MilterLogLevel > 3)
2829 				sm_syslog(LOG_INFO, e->e_id,
2830 					  "Milter: data, reject=%s",
2831 					  MSG_TEMPFAIL);
2832 			milteraccept = false;
2833 			usrerr(MSG_TEMPFAIL);
2834 			break;
2835 		}
2836 		if (response != NULL)
2837 			sm_free(response);
2838 	}
2839 
2840 	/* Milter may have changed message size */
2841 	(void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize);
2842 	macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
2843 
2844 	/* abort message filters that didn't get the body & log msg is OK */
2845 	if (smtp->sm_milterlist && smtp->sm_milterize)
2846 	{
2847 		milter_abort(e);
2848 		if (milteraccept && MilterLogLevel > 9)
2849 			sm_syslog(LOG_INFO, e->e_id, "Milter accept: message");
2850 	}
2851 #endif /* MILTER */
2852 
2853 #if _FFR_QUARANTINE
2854 	/* Check if quarantining stats should be updated */
2855 	if (e->e_quarmsg != NULL)
2856 		markstats(e, NULL, STATS_QUARANTINE);
2857 #endif /* _FFR_QUARANTINE */
2858 
2859 	/*
2860 	**  If a header/body check (header checks or milter)
2861 	**  set EF_DISCARD, don't queueup the message --
2862 	**  that would lose the EF_DISCARD bit and deliver
2863 	**  the message.
2864 	*/
2865 
2866 	if (bitset(EF_DISCARD, e->e_flags))
2867 		doublequeue = false;
2868 
2869 	aborting = Errors > 0;
2870 	if (!aborting &&
2871 #if _FFR_QUARANTINE
2872 	    (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) &&
2873 #endif /* _FFR_QUARANTINE */
2874 	    !split_by_recipient(e))
2875 		aborting = bitset(EF_FATALERRS, e->e_flags);
2876 
2877 	if (aborting)
2878 	{
2879 		/* Log who the mail would have gone to */
2880 		logundelrcpts(e, e->e_message, 8, false);
2881 		flush_errors(true);
2882 		buffer_errors();
2883 		goto abortmessage;
2884 	}
2885 
2886 	/* from now on, we have to operate silently */
2887 	buffer_errors();
2888 
2889 #if 0
2890 	/*
2891 	**  Clear message, it may contain an error from the SMTP dialogue.
2892 	**  This error must not show up in the queue.
2893 	**	Some error message should show up, e.g., alias database
2894 	**	not available, but others shouldn't, e.g., from check_rcpt.
2895 	*/
2896 
2897 	e->e_message = NULL;
2898 #endif /* 0 */
2899 
2900 	/*
2901 	**  Arrange to send to everyone.
2902 	**	If sending to multiple people, mail back
2903 	**		errors rather than reporting directly.
2904 	**	In any case, don't mail back errors for
2905 	**		anything that has happened up to
2906 	**		now (the other end will do this).
2907 	**	Truncate our transcript -- the mail has gotten
2908 	**		to us successfully, and if we have
2909 	**		to mail this back, it will be easier
2910 	**		on the reader.
2911 	**	Then send to everyone.
2912 	**	Finally give a reply code.  If an error has
2913 	**		already been given, don't mail a
2914 	**		message back.
2915 	**	We goose error returns by clearing error bit.
2916 	*/
2917 
2918 	SmtpPhase = "delivery";
2919 	(void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL);
2920 	id = e->e_id;
2921 
2922 #if NAMED_BIND
2923 	_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
2924 	_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
2925 #endif /* NAMED_BIND */
2926 
2927 	for (ee = e; ee != NULL; ee = ee->e_sibling)
2928 	{
2929 		/* make sure we actually do delivery */
2930 		ee->e_flags &= ~EF_CLRQUEUE;
2931 
2932 		/* from now on, operate silently */
2933 		ee->e_errormode = EM_MAIL;
2934 
2935 		if (doublequeue)
2936 		{
2937 			/* make sure it is in the queue */
2938 			queueup(ee, false, true);
2939 		}
2940 		else
2941 		{
2942 			/* send to all recipients */
2943 			sendall(ee, SM_DEFAULT);
2944 		}
2945 		ee->e_to = NULL;
2946 	}
2947 
2948 	/* issue success message */
2949 	message("250 2.0.0 %s Message accepted for delivery", id);
2950 
2951 	/* if we just queued, poke it */
2952 	if (doublequeue)
2953 	{
2954 		bool anything_to_send = false;
2955 
2956 		sm_getla();
2957 		for (ee = e; ee != NULL; ee = ee->e_sibling)
2958 		{
2959 			if (WILL_BE_QUEUED(ee->e_sendmode))
2960 				continue;
2961 			if (shouldqueue(ee->e_msgpriority, ee->e_ctime))
2962 			{
2963 				ee->e_sendmode = SM_QUEUE;
2964 				continue;
2965 			}
2966 #if _FFR_QUARANTINE
2967 			else if (QueueMode != QM_QUARANTINE &&
2968 				 ee->e_quarmsg != NULL)
2969 			{
2970 				ee->e_sendmode = SM_QUEUE;
2971 				continue;
2972 			}
2973 #endif /* _FFR_QUARANTINE */
2974 			anything_to_send = true;
2975 
2976 			/* close all the queue files */
2977 			closexscript(ee);
2978 			if (ee->e_dfp != NULL)
2979 			{
2980 				(void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT);
2981 				ee->e_dfp = NULL;
2982 			}
2983 			unlockqueue(ee);
2984 		}
2985 		if (anything_to_send)
2986 		{
2987 #if PIPELINING
2988 			/*
2989 			**  XXX if we don't do this, we get 250 twice
2990 			**	because it is also flushed in the child.
2991 			*/
2992 
2993 			(void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
2994 #endif /* PIPELINING */
2995 			(void) doworklist(e, true, true);
2996 		}
2997 	}
2998 
2999   abortmessage:
3000 	if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
3001 		logsender(e, NULL);
3002 	e->e_flags &= ~EF_LOGSENDER;
3003 
3004 	/* clean up a bit */
3005 	smtp->sm_gotmail = false;
3006 
3007 	/*
3008 	**  Call dropenvelope if and only if the envelope is *not*
3009 	**  being processed by the child process forked by doworklist().
3010 	*/
3011 
3012 	if (aborting || bitset(EF_DISCARD, e->e_flags))
3013 		dropenvelope(e, true, false);
3014 	else
3015 	{
3016 		for (ee = e; ee != NULL; ee = ee->e_sibling)
3017 		{
3018 #if _FFR_QUARANTINE
3019 			if (!doublequeue &&
3020 			    QueueMode != QM_QUARANTINE &&
3021 			    ee->e_quarmsg != NULL)
3022 			{
3023 				dropenvelope(ee, true, false);
3024 				continue;
3025 			}
3026 #endif /* _FFR_QUARANTINE */
3027 			if (WILL_BE_QUEUED(ee->e_sendmode))
3028 				dropenvelope(ee, true, false);
3029 		}
3030 	}
3031 	sm_rpool_free(e->e_rpool);
3032 
3033 	/*
3034 	**  At this point, e == &MainEnvelope, but if we did splitting,
3035 	**  then CurEnv may point to an envelope structure that was just
3036 	**  freed with the rpool.  So reset CurEnv *before* calling
3037 	**  newenvelope.
3038 	*/
3039 
3040 	CurEnv = e;
3041 	newenvelope(e, e, sm_rpool_new_x(NULL));
3042 	e->e_flags = BlankEnvelope.e_flags;
3043 
3044 #if _FFR_QUARANTINE
3045 	/* restore connection quarantining */
3046 	if (smtp->sm_quarmsg == NULL)
3047 	{
3048 		e->e_quarmsg = NULL;
3049 		macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
3050 	}
3051 	else
3052 	{
3053 		e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg);
3054 		macdefine(&e->e_macro, A_PERM,
3055 			  macid("{quarantine}"), e->e_quarmsg);
3056 	}
3057 #endif /* _FFR_QUARANTINE */
3058 }
3059 /*
3060 **  LOGUNDELRCPTS -- log undelivered (or all) recipients.
3061 **
3062 **	Parameters:
3063 **		e -- envelope.
3064 **		msg -- message for Stat=
3065 **		level -- log level.
3066 **		all -- log all recipients.
3067 **
3068 **	Returns:
3069 **		none.
3070 **
3071 **	Side Effects:
3072 **		logs undelivered (or all) recipients
3073 */
3074 
3075 void
3076 logundelrcpts(e, msg, level, all)
3077 	ENVELOPE *e;
3078 	char *msg;
3079 	int level;
3080 	bool all;
3081 {
3082 	ADDRESS *a;
3083 
3084 	if (LogLevel <= level || msg == NULL || *msg == '\0')
3085 		return;
3086 
3087 	/* Clear $h so relay= doesn't get mislogged by logdelivery() */
3088 	macdefine(&e->e_macro, A_PERM, 'h', NULL);
3089 
3090 	/* Log who the mail would have gone to */
3091 	for (a = e->e_sendqueue; a != NULL; a = a->q_next)
3092 	{
3093 		if (!QS_IS_UNDELIVERED(a->q_state) && !all)
3094 			continue;
3095 		e->e_to = a->q_paddr;
3096 		logdelivery(NULL, NULL, a->q_status, msg, NULL,
3097 			    (time_t) 0, e);
3098 	}
3099 	e->e_to = NULL;
3100 }
3101 /*
3102 **  CHECKSMTPATTACK -- check for denial-of-service attack by repetition
3103 **
3104 **	Parameters:
3105 **		pcounter -- pointer to a counter for this command.
3106 **		maxcount -- maximum value for this counter before we
3107 **			slow down.
3108 **		waitnow -- sleep now (in this routine)?
3109 **		cname -- command name for logging.
3110 **		e -- the current envelope.
3111 **
3112 **	Returns:
3113 **		time to wait.
3114 **
3115 **	Side Effects:
3116 **		Slows down if we seem to be under attack.
3117 */
3118 
3119 static time_t
3120 checksmtpattack(pcounter, maxcount, waitnow, cname, e)
3121 	volatile unsigned int *pcounter;
3122 	int maxcount;
3123 	bool waitnow;
3124 	char *cname;
3125 	ENVELOPE *e;
3126 {
3127 	if (maxcount <= 0)	/* no limit */
3128 		return (time_t) 0;
3129 
3130 	if (++(*pcounter) >= maxcount)
3131 	{
3132 		time_t s;
3133 
3134 		if (*pcounter == maxcount && LogLevel > 5)
3135 		{
3136 			sm_syslog(LOG_INFO, e->e_id,
3137 				  "%.100s: possible SMTP attack: command=%.40s, count=%u",
3138 				  CurSmtpClient, cname, *pcounter);
3139 		}
3140 		s = 1 << (*pcounter - maxcount);
3141 		if (s >= MAXTIMEOUT || s <= 0)
3142 			s = MAXTIMEOUT;
3143 
3144 		/* sleep at least 1 second before returning */
3145 		(void) sleep(*pcounter / maxcount);
3146 		s -= *pcounter / maxcount;
3147 		if (waitnow)
3148 		{
3149 			(void) sleep(s);
3150 			return 0;
3151 		}
3152 		return s;
3153 	}
3154 	return (time_t) 0;
3155 }
3156 /*
3157 **  SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server
3158 **
3159 **	Parameters:
3160 **		none.
3161 **
3162 **	Returns:
3163 **		nothing.
3164 **
3165 **	Side Effects:
3166 **		may change I/O fd.
3167 */
3168 
3169 static void
3170 setup_smtpd_io()
3171 {
3172 	int inchfd, outchfd, outfd;
3173 
3174 	inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
3175 	outchfd  = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
3176 	outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL);
3177 	if (outchfd != outfd)
3178 	{
3179 		/* arrange for debugging output to go to remote host */
3180 		(void) dup2(outchfd, outfd);
3181 	}
3182 
3183 	/*
3184 	**  if InChannel and OutChannel are stdin/stdout
3185 	**  and connected to ttys
3186 	**  and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT,
3187 	**  then "chain" them together.
3188 	*/
3189 
3190 	if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO &&
3191 	    isatty(inchfd) && isatty(outchfd))
3192 	{
3193 		int inmode, outmode;
3194 
3195 		inmode = fcntl(inchfd, F_GETFL, 0);
3196 		if (inmode == -1)
3197 		{
3198 			if (LogLevel > 11)
3199 				sm_syslog(LOG_INFO, NOQID,
3200 					"fcntl(inchfd, F_GETFL) failed: %s",
3201 					sm_errstring(errno));
3202 			return;
3203 		}
3204 		outmode = fcntl(outchfd, F_GETFL, 0);
3205 		if (outmode == -1)
3206 		{
3207 			if (LogLevel > 11)
3208 				sm_syslog(LOG_INFO, NOQID,
3209 					"fcntl(outchfd, F_GETFL) failed: %s",
3210 					sm_errstring(errno));
3211 			return;
3212 		}
3213 		if (bitset(O_NONBLOCK, inmode) ||
3214 		    bitset(O_NONBLOCK, outmode) ||
3215 		    fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1)
3216 			return;
3217 		outmode = fcntl(outchfd, F_GETFL, 0);
3218 		if (outmode != -1 && bitset(O_NONBLOCK, outmode))
3219 		{
3220 			/* changing InChannel also changes OutChannel */
3221 			sm_io_automode(OutChannel, InChannel);
3222 			if (tTd(97, 4) && LogLevel > 9)
3223 				sm_syslog(LOG_INFO, NOQID,
3224 					  "set automode for I (%d)/O (%d) in SMTP server",
3225 					  inchfd, outchfd);
3226 		}
3227 
3228 		/* undo change of inchfd */
3229 		(void) fcntl(inchfd, F_SETFL, inmode);
3230 	}
3231 }
3232 /*
3233 **  SKIPWORD -- skip a fixed word.
3234 **
3235 **	Parameters:
3236 **		p -- place to start looking.
3237 **		w -- word to skip.
3238 **
3239 **	Returns:
3240 **		p following w.
3241 **		NULL on error.
3242 **
3243 **	Side Effects:
3244 **		clobbers the p data area.
3245 */
3246 
3247 static char *
3248 skipword(p, w)
3249 	register char *volatile p;
3250 	char *w;
3251 {
3252 	register char *q;
3253 	char *firstp = p;
3254 
3255 	/* find beginning of word */
3256 	SKIP_SPACE(p);
3257 	q = p;
3258 
3259 	/* find end of word */
3260 	while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
3261 		p++;
3262 	while (isascii(*p) && isspace(*p))
3263 		*p++ = '\0';
3264 	if (*p != ':')
3265 	{
3266 	  syntax:
3267 		usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"",
3268 			shortenstring(firstp, MAXSHORTSTR));
3269 		return NULL;
3270 	}
3271 	*p++ = '\0';
3272 	SKIP_SPACE(p);
3273 
3274 	if (*p == '\0')
3275 		goto syntax;
3276 
3277 	/* see if the input word matches desired word */
3278 	if (sm_strcasecmp(q, w))
3279 		goto syntax;
3280 
3281 	return p;
3282 }
3283 /*
3284 **  MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
3285 **
3286 **	Parameters:
3287 **		kp -- the parameter key.
3288 **		vp -- the value of that parameter.
3289 **		e -- the envelope.
3290 **
3291 **	Returns:
3292 **		none.
3293 */
3294 
3295 static void
3296 mail_esmtp_args(kp, vp, e)
3297 	char *kp;
3298 	char *vp;
3299 	ENVELOPE *e;
3300 {
3301 	if (sm_strcasecmp(kp, "size") == 0)
3302 	{
3303 		if (vp == NULL)
3304 		{
3305 			usrerr("501 5.5.2 SIZE requires a value");
3306 			/* NOTREACHED */
3307 		}
3308 		macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp);
3309 		errno = 0;
3310 		e->e_msgsize = strtol(vp, (char **) NULL, 10);
3311 		if (e->e_msgsize == LONG_MAX && errno == ERANGE)
3312 		{
3313 			usrerr("552 5.2.3 Message size exceeds maximum value");
3314 			/* NOTREACHED */
3315 		}
3316 		if (e->e_msgsize < 0)
3317 		{
3318 			usrerr("552 5.2.3 Message size invalid");
3319 			/* NOTREACHED */
3320 		}
3321 	}
3322 	else if (sm_strcasecmp(kp, "body") == 0)
3323 	{
3324 		if (vp == NULL)
3325 		{
3326 			usrerr("501 5.5.2 BODY requires a value");
3327 			/* NOTREACHED */
3328 		}
3329 		else if (sm_strcasecmp(vp, "8bitmime") == 0)
3330 		{
3331 			SevenBitInput = false;
3332 		}
3333 		else if (sm_strcasecmp(vp, "7bit") == 0)
3334 		{
3335 			SevenBitInput = true;
3336 		}
3337 		else
3338 		{
3339 			usrerr("501 5.5.4 Unknown BODY type %s", vp);
3340 			/* NOTREACHED */
3341 		}
3342 		e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp);
3343 	}
3344 	else if (sm_strcasecmp(kp, "envid") == 0)
3345 	{
3346 		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
3347 		{
3348 			usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN");
3349 			/* NOTREACHED */
3350 		}
3351 		if (vp == NULL)
3352 		{
3353 			usrerr("501 5.5.2 ENVID requires a value");
3354 			/* NOTREACHED */
3355 		}
3356 		if (!xtextok(vp))
3357 		{
3358 			usrerr("501 5.5.4 Syntax error in ENVID parameter value");
3359 			/* NOTREACHED */
3360 		}
3361 		if (e->e_envid != NULL)
3362 		{
3363 			usrerr("501 5.5.0 Duplicate ENVID parameter");
3364 			/* NOTREACHED */
3365 		}
3366 		e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp);
3367 		macdefine(&e->e_macro, A_PERM,
3368 			macid("{dsn_envid}"), e->e_envid);
3369 	}
3370 	else if (sm_strcasecmp(kp, "ret") == 0)
3371 	{
3372 		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
3373 		{
3374 			usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN");
3375 			/* NOTREACHED */
3376 		}
3377 		if (vp == NULL)
3378 		{
3379 			usrerr("501 5.5.2 RET requires a value");
3380 			/* NOTREACHED */
3381 		}
3382 		if (bitset(EF_RET_PARAM, e->e_flags))
3383 		{
3384 			usrerr("501 5.5.0 Duplicate RET parameter");
3385 			/* NOTREACHED */
3386 		}
3387 		e->e_flags |= EF_RET_PARAM;
3388 		if (sm_strcasecmp(vp, "hdrs") == 0)
3389 			e->e_flags |= EF_NO_BODY_RETN;
3390 		else if (sm_strcasecmp(vp, "full") != 0)
3391 		{
3392 			usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp);
3393 			/* NOTREACHED */
3394 		}
3395 		macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp);
3396 	}
3397 #if SASL
3398 	else if (sm_strcasecmp(kp, "auth") == 0)
3399 	{
3400 		int len;
3401 		char *q;
3402 		char *auth_param;	/* the value of the AUTH=x */
3403 		bool saveQuickAbort = QuickAbort;
3404 		bool saveSuprErrs = SuprErrs;
3405 		bool saveExitStat = ExitStat;
3406 		char pbuf[256];
3407 
3408 		if (vp == NULL)
3409 		{
3410 			usrerr("501 5.5.2 AUTH= requires a value");
3411 			/* NOTREACHED */
3412 		}
3413 		if (e->e_auth_param != NULL)
3414 		{
3415 			usrerr("501 5.5.0 Duplicate AUTH parameter");
3416 			/* NOTREACHED */
3417 		}
3418 		if ((q = strchr(vp, ' ')) != NULL)
3419 			len = q - vp + 1;
3420 		else
3421 			len = strlen(vp) + 1;
3422 		auth_param = xalloc(len);
3423 		(void) sm_strlcpy(auth_param, vp, len);
3424 		if (!xtextok(auth_param))
3425 		{
3426 			usrerr("501 5.5.4 Syntax error in AUTH parameter value");
3427 			/* just a warning? */
3428 			/* NOTREACHED */
3429 		}
3430 
3431 		/* XXX this might be cut off */
3432 		(void) sm_strlcpy(pbuf, xuntextify(auth_param), sizeof pbuf);
3433 		/* xalloc() the buffer instead? */
3434 
3435 		/* XXX define this always or only if trusted? */
3436 		macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), pbuf);
3437 
3438 		/*
3439 		**  call Strust_auth to find out whether
3440 		**  auth_param is acceptable (trusted)
3441 		**  we shouldn't trust it if not authenticated
3442 		**  (required by RFC, leave it to ruleset?)
3443 		*/
3444 
3445 		SuprErrs = true;
3446 		QuickAbort = false;
3447 		if (strcmp(auth_param, "<>") != 0 &&
3448 		     (rscheck("trust_auth", pbuf, NULL, e, true, false, 9,
3449 			      NULL, NOQID) != EX_OK || Errors > 0))
3450 		{
3451 			if (tTd(95, 8))
3452 			{
3453 				q = e->e_auth_param;
3454 				sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n",
3455 					pbuf, (q == NULL) ? "" : q);
3456 			}
3457 
3458 			/* not trusted */
3459 			e->e_auth_param = "<>";
3460 # if _FFR_AUTH_PASSING
3461 			macdefine(&BlankEnvelope.e_macro, A_PERM,
3462 				  macid("{auth_author}"), NULL);
3463 # endif /* _FFR_AUTH_PASSING */
3464 		}
3465 		else
3466 		{
3467 			if (tTd(95, 8))
3468 				sm_dprintf("auth=\"%.100s\" trusted\n", pbuf);
3469 			e->e_auth_param = sm_rpool_strdup_x(e->e_rpool,
3470 							    auth_param);
3471 		}
3472 		sm_free(auth_param); /* XXX */
3473 
3474 		/* reset values */
3475 		Errors = 0;
3476 		QuickAbort = saveQuickAbort;
3477 		SuprErrs = saveSuprErrs;
3478 		ExitStat = saveExitStat;
3479 	}
3480 #endif /* SASL */
3481 #define PRTCHAR(c)	((isascii(c) && isprint(c)) ? (c) : '?')
3482 
3483 	/*
3484 	**  "by" is only accepted if DeliverByMin >= 0.
3485 	**  We maybe could add this to the list of server_features.
3486 	*/
3487 
3488 	else if (sm_strcasecmp(kp, "by") == 0 && DeliverByMin >= 0)
3489 	{
3490 		char *s;
3491 
3492 		if (vp == NULL)
3493 		{
3494 			usrerr("501 5.5.2 BY= requires a value");
3495 			/* NOTREACHED */
3496 		}
3497 		errno = 0;
3498 		e->e_deliver_by = strtol(vp, &s, 10);
3499 		if (e->e_deliver_by == LONG_MIN ||
3500 		    e->e_deliver_by == LONG_MAX ||
3501 		    e->e_deliver_by > 999999999l ||
3502 		    e->e_deliver_by < -999999999l)
3503 		{
3504 			usrerr("501 5.5.2 BY=%s out of range", vp);
3505 			/* NOTREACHED */
3506 		}
3507 		if (s == NULL || *s != ';')
3508 		{
3509 			usrerr("501 5.5.2 BY= missing ';'");
3510 			/* NOTREACHED */
3511 		}
3512 		e->e_dlvr_flag = 0;
3513 		++s;	/* XXX: spaces allowed? */
3514 		SKIP_SPACE(s);
3515 		switch (tolower(*s))
3516 		{
3517 		  case 'n':
3518 			e->e_dlvr_flag = DLVR_NOTIFY;
3519 			break;
3520 		  case 'r':
3521 			e->e_dlvr_flag = DLVR_RETURN;
3522 			if (e->e_deliver_by <= 0)
3523 			{
3524 				usrerr("501 5.5.4 mode R requires BY time > 0");
3525 				/* NOTREACHED */
3526 			}
3527 			if (DeliverByMin > 0 && e->e_deliver_by > 0 &&
3528 			    e->e_deliver_by < DeliverByMin)
3529 			{
3530 				usrerr("555 5.5.2 time %ld less than %ld",
3531 					e->e_deliver_by, (long) DeliverByMin);
3532 				/* NOTREACHED */
3533 			}
3534 			break;
3535 		  default:
3536 			usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s));
3537 			/* NOTREACHED */
3538 		}
3539 		++s;	/* XXX: spaces allowed? */
3540 		SKIP_SPACE(s);
3541 		switch (tolower(*s))
3542 		{
3543 		  case 't':
3544 			e->e_dlvr_flag |= DLVR_TRACE;
3545 			break;
3546 		  case '\0':
3547 			break;
3548 		  default:
3549 			usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s));
3550 			/* NOTREACHED */
3551 		}
3552 
3553 		/* XXX: check whether more characters follow? */
3554 	}
3555 	else
3556 	{
3557 		usrerr("555 5.5.4 %s parameter unrecognized", kp);
3558 		/* NOTREACHED */
3559 	}
3560 }
3561 /*
3562 **  RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
3563 **
3564 **	Parameters:
3565 **		a -- the address corresponding to the To: parameter.
3566 **		kp -- the parameter key.
3567 **		vp -- the value of that parameter.
3568 **		e -- the envelope.
3569 **
3570 **	Returns:
3571 **		none.
3572 */
3573 
3574 static void
3575 rcpt_esmtp_args(a, kp, vp, e)
3576 	ADDRESS *a;
3577 	char *kp;
3578 	char *vp;
3579 	ENVELOPE *e;
3580 {
3581 	if (sm_strcasecmp(kp, "notify") == 0)
3582 	{
3583 		char *p;
3584 
3585 		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
3586 		{
3587 			usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN");
3588 			/* NOTREACHED */
3589 		}
3590 		if (vp == NULL)
3591 		{
3592 			usrerr("501 5.5.2 NOTIFY requires a value");
3593 			/* NOTREACHED */
3594 		}
3595 		a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
3596 		a->q_flags |= QHASNOTIFY;
3597 		macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp);
3598 
3599 		if (sm_strcasecmp(vp, "never") == 0)
3600 			return;
3601 		for (p = vp; p != NULL; vp = p)
3602 		{
3603 			p = strchr(p, ',');
3604 			if (p != NULL)
3605 				*p++ = '\0';
3606 			if (sm_strcasecmp(vp, "success") == 0)
3607 				a->q_flags |= QPINGONSUCCESS;
3608 			else if (sm_strcasecmp(vp, "failure") == 0)
3609 				a->q_flags |= QPINGONFAILURE;
3610 			else if (sm_strcasecmp(vp, "delay") == 0)
3611 				a->q_flags |= QPINGONDELAY;
3612 			else
3613 			{
3614 				usrerr("501 5.5.4 Bad argument \"%s\"  to NOTIFY",
3615 					vp);
3616 				/* NOTREACHED */
3617 			}
3618 		}
3619 	}
3620 	else if (sm_strcasecmp(kp, "orcpt") == 0)
3621 	{
3622 		if (bitset(PRIV_NORECEIPTS, PrivacyFlags))
3623 		{
3624 			usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN");
3625 			/* NOTREACHED */
3626 		}
3627 		if (vp == NULL)
3628 		{
3629 			usrerr("501 5.5.2 ORCPT requires a value");
3630 			/* NOTREACHED */
3631 		}
3632 		if (strchr(vp, ';') == NULL || !xtextok(vp))
3633 		{
3634 			usrerr("501 5.5.4 Syntax error in ORCPT parameter value");
3635 			/* NOTREACHED */
3636 		}
3637 		if (a->q_orcpt != NULL)
3638 		{
3639 			usrerr("501 5.5.0 Duplicate ORCPT parameter");
3640 			/* NOTREACHED */
3641 		}
3642 		a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp);
3643 	}
3644 	else
3645 	{
3646 		usrerr("555 5.5.4 %s parameter unrecognized", kp);
3647 		/* NOTREACHED */
3648 	}
3649 }
3650 /*
3651 **  PRINTVRFYADDR -- print an entry in the verify queue
3652 **
3653 **	Parameters:
3654 **		a -- the address to print.
3655 **		last -- set if this is the last one.
3656 **		vrfy -- set if this is a VRFY command.
3657 **
3658 **	Returns:
3659 **		none.
3660 **
3661 **	Side Effects:
3662 **		Prints the appropriate 250 codes.
3663 */
3664 #define OFFF	(3 + 1 + 5 + 1)	/* offset in fmt: SMTP reply + enh. code */
3665 
3666 static void
3667 printvrfyaddr(a, last, vrfy)
3668 	register ADDRESS *a;
3669 	bool last;
3670 	bool vrfy;
3671 {
3672 	char fmtbuf[30];
3673 
3674 	if (vrfy && a->q_mailer != NULL &&
3675 	    !bitnset(M_VRFY250, a->q_mailer->m_flags))
3676 		(void) sm_strlcpy(fmtbuf, "252", sizeof fmtbuf);
3677 	else
3678 		(void) sm_strlcpy(fmtbuf, "250", sizeof fmtbuf);
3679 	fmtbuf[3] = last ? ' ' : '-';
3680 	(void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4);
3681 	if (a->q_fullname == NULL)
3682 	{
3683 		if ((a->q_mailer == NULL ||
3684 		     a->q_mailer->m_addrtype == NULL ||
3685 		     sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
3686 		    strchr(a->q_user, '@') == NULL)
3687 			(void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>",
3688 				       sizeof fmtbuf - OFFF);
3689 		else
3690 			(void) sm_strlcpy(&fmtbuf[OFFF], "<%s>",
3691 				       sizeof fmtbuf - OFFF);
3692 		message(fmtbuf, a->q_user, MyHostName);
3693 	}
3694 	else
3695 	{
3696 		if ((a->q_mailer == NULL ||
3697 		     a->q_mailer->m_addrtype == NULL ||
3698 		     sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) &&
3699 		    strchr(a->q_user, '@') == NULL)
3700 			(void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>",
3701 				       sizeof fmtbuf - OFFF);
3702 		else
3703 			(void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>",
3704 				       sizeof fmtbuf - OFFF);
3705 		message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
3706 	}
3707 }
3708 
3709 #if SASL
3710 /*
3711 **  SASLMECHS -- get list of possible AUTH mechanisms
3712 **
3713 **	Parameters:
3714 **		conn -- SASL connection info.
3715 **		mechlist -- output parameter for list of mechanisms.
3716 **
3717 **	Returns:
3718 **		number of mechs.
3719 */
3720 
3721 static int
3722 saslmechs(conn, mechlist)
3723 	sasl_conn_t *conn;
3724 	char **mechlist;
3725 {
3726 	int len, num, result;
3727 
3728 	/* "user" is currently unused */
3729 	result = sasl_listmech(conn, "user", /* XXX */
3730 			       "", " ", "", mechlist,
3731 			       (unsigned int *)&len, (unsigned int *)&num);
3732 	if (result != SASL_OK)
3733 	{
3734 		if (LogLevel > 9)
3735 			sm_syslog(LOG_WARNING, NOQID,
3736 				  "AUTH error: listmech=%d, num=%d",
3737 				  result, num);
3738 		num = 0;
3739 	}
3740 	if (num > 0)
3741 	{
3742 		if (LogLevel > 11)
3743 			sm_syslog(LOG_INFO, NOQID,
3744 				  "AUTH: available mech=%s, allowed mech=%s",
3745 				  *mechlist, AuthMechanisms);
3746 		*mechlist = intersect(AuthMechanisms, *mechlist, NULL);
3747 	}
3748 	else
3749 	{
3750 		*mechlist = NULL;	/* be paranoid... */
3751 		if (result == SASL_OK && LogLevel > 9)
3752 			sm_syslog(LOG_WARNING, NOQID,
3753 				  "AUTH warning: no mechanisms");
3754 	}
3755 	return num;
3756 }
3757 /*
3758 **  PROXY_POLICY -- define proxy policy for AUTH
3759 **
3760 **	Parameters:
3761 **		context -- unused.
3762 **		auth_identity -- authentication identity.
3763 **		requested_user -- authorization identity.
3764 **		user -- allowed user (output).
3765 **		errstr -- possible error string (output).
3766 **
3767 **	Returns:
3768 **		ok?
3769 */
3770 
3771 int
3772 proxy_policy(context, auth_identity, requested_user, user, errstr)
3773 	void *context;
3774 	const char *auth_identity;
3775 	const char *requested_user;
3776 	const char **user;
3777 	const char **errstr;
3778 {
3779 	if (user == NULL || auth_identity == NULL)
3780 		return SASL_FAIL;
3781 	*user = newstr(auth_identity);
3782 	return SASL_OK;
3783 }
3784 #endif /* SASL */
3785 
3786 #if STARTTLS
3787 /*
3788 **  INITSRVTLS -- initialize server side TLS
3789 **
3790 **	Parameters:
3791 **		tls_ok -- should tls initialization be done?
3792 **
3793 **	Returns:
3794 **		succeeded?
3795 **
3796 **	Side Effects:
3797 **		sets tls_ok_srv which is a static variable in this module.
3798 **		Do NOT remove assignments to it!
3799 */
3800 
3801 bool
3802 initsrvtls(tls_ok)
3803 	bool tls_ok;
3804 {
3805 	if (!tls_ok)
3806 		return false;
3807 
3808 	/* do NOT remove assignment */
3809 	tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, true, SrvCERTfile,
3810 			     Srvkeyfile, CACERTpath, CACERTfile, DHParams);
3811 	return tls_ok_srv;
3812 }
3813 #endif /* STARTTLS */
3814 /*
3815 **  SRVFEATURES -- get features for SMTP server
3816 **
3817 **	Parameters:
3818 **		e -- envelope (should be session context).
3819 **		clientname -- name of client.
3820 **		features -- default features for this invocation.
3821 **
3822 **	Returns:
3823 **		server features.
3824 */
3825 
3826 /* table with options: it uses just one character, how about strings? */
3827 static struct
3828 {
3829 	char		srvf_opt;
3830 	unsigned int	srvf_flag;
3831 } srv_feat_table[] =
3832 {
3833 	{ 'A',	SRV_OFFER_AUTH	},
3834 	{ 'B',	SRV_OFFER_VERB	},
3835 	{ 'D',	SRV_OFFER_DSN	},
3836 	{ 'E',	SRV_OFFER_ETRN	},
3837 	{ 'L',	SRV_REQ_AUTH	},	/* not documented in 8.12 */
3838 #if PIPELINING
3839 # if _FFR_NO_PIPE
3840 	{ 'N',	SRV_NO_PIPE	},
3841 # endif /* _FFR_NO_PIPE */
3842 	{ 'P',	SRV_OFFER_PIPE	},
3843 #endif /* PIPELINING */
3844 	{ 'R',	SRV_VRFY_CLT	},
3845 	{ 'S',	SRV_OFFER_TLS	},
3846 /*	{ 'T',	SRV_TMP_FAIL	},	*/
3847 	{ 'V',	SRV_VRFY_CLT	},
3848 	{ 'X',	SRV_OFFER_EXPN	},
3849 /*	{ 'Y',	SRV_OFFER_VRFY	},	*/
3850 	{ '\0',	SRV_NONE	}
3851 };
3852 
3853 static unsigned int
3854 srvfeatures(e, clientname, features)
3855 	ENVELOPE *e;
3856 	char *clientname;
3857 	unsigned int features;
3858 {
3859 	int r, i, j;
3860 	char **pvp, c, opt;
3861 	char pvpbuf[PSBUFSIZE];
3862 
3863 	pvp = NULL;
3864 	r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf,
3865 		  sizeof(pvpbuf));
3866 	if (r != EX_OK)
3867 		return features;
3868 	if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
3869 		return features;
3870 	if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
3871 		return SRV_TMP_FAIL;
3872 
3873 	/*
3874 	**  General rule (see sendmail.h, d_flags):
3875 	**  lower case: required/offered, upper case: Not required/available
3876 	**
3877 	**  Since we can change some features per daemon, we have both
3878 	**  cases here: turn on/off a feature.
3879 	*/
3880 
3881 	for (i = 1; pvp[i] != NULL; i++)
3882 	{
3883 		c = pvp[i][0];
3884 		j = 0;
3885 		for (;;)
3886 		{
3887 			if ((opt = srv_feat_table[j].srvf_opt) == '\0')
3888 			{
3889 				if (LogLevel > 9)
3890 					sm_syslog(LOG_WARNING, e->e_id,
3891 						  "srvfeatures: unknown feature %s",
3892 						  pvp[i]);
3893 				break;
3894 			}
3895 			if (c == opt)
3896 			{
3897 				features &= ~(srv_feat_table[j].srvf_flag);
3898 				break;
3899 			}
3900 			if (c == tolower(opt))
3901 			{
3902 				features |= srv_feat_table[j].srvf_flag;
3903 				break;
3904 			}
3905 			++j;
3906 		}
3907 	}
3908 	return features;
3909 }
3910 
3911 /*
3912 **  HELP -- implement the HELP command.
3913 **
3914 **	Parameters:
3915 **		topic -- the topic we want help for.
3916 **		e -- envelope.
3917 **
3918 **	Returns:
3919 **		none.
3920 **
3921 **	Side Effects:
3922 **		outputs the help file to message output.
3923 */
3924 #define HELPVSTR	"#vers	"
3925 #define HELPVERSION	2
3926 
3927 void
3928 help(topic, e)
3929 	char *topic;
3930 	ENVELOPE *e;
3931 {
3932 	register SM_FILE_T *hf;
3933 	register char *p;
3934 	int len;
3935 	bool noinfo;
3936 	bool first = true;
3937 	long sff = SFF_OPENASROOT|SFF_REGONLY;
3938 	char buf[MAXLINE];
3939 	char inp[MAXLINE];
3940 	static int foundvers = -1;
3941 	extern char Version[];
3942 
3943 	if (DontLockReadFiles)
3944 		sff |= SFF_NOLOCK;
3945 	if (!bitnset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail))
3946 		sff |= SFF_SAFEDIRPATH;
3947 
3948 	if (HelpFile == NULL ||
3949 	    (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL)
3950 	{
3951 		/* no help */
3952 		errno = 0;
3953 		message("502 5.3.0 Sendmail %s -- HELP not implemented",
3954 			Version);
3955 		return;
3956 	}
3957 
3958 	if (topic == NULL || *topic == '\0')
3959 	{
3960 		topic = "smtp";
3961 		noinfo = false;
3962 	}
3963 	else
3964 	{
3965 		makelower(topic);
3966 		noinfo = true;
3967 	}
3968 
3969 	len = strlen(topic);
3970 
3971 	while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL)
3972 	{
3973 		if (buf[0] == '#')
3974 		{
3975 			if (foundvers < 0 &&
3976 			    strncmp(buf, HELPVSTR, strlen(HELPVSTR)) == 0)
3977 			{
3978 				int h;
3979 
3980 				if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d",
3981 						 &h) == 1)
3982 					foundvers = h;
3983 			}
3984 			continue;
3985 		}
3986 		if (strncmp(buf, topic, len) == 0)
3987 		{
3988 			if (first)
3989 			{
3990 				first = false;
3991 
3992 				/* print version if no/old vers# in file */
3993 				if (foundvers < 2 && !noinfo)
3994 					message("214-2.0.0 This is Sendmail version %s", Version);
3995 			}
3996 			p = strpbrk(buf, " \t");
3997 			if (p == NULL)
3998 				p = buf + strlen(buf) - 1;
3999 			else
4000 				p++;
4001 			fixcrlf(p, true);
4002 			if (foundvers >= 2)
4003 			{
4004 				translate_dollars(p);
4005 				expand(p, inp, sizeof inp, e);
4006 				p = inp;
4007 			}
4008 			message("214-2.0.0 %s", p);
4009 			noinfo = false;
4010 		}
4011 	}
4012 
4013 	if (noinfo)
4014 		message("504 5.3.0 HELP topic \"%.10s\" unknown", topic);
4015 	else
4016 		message("214 2.0.0 End of HELP info");
4017 
4018 	if (foundvers != 0 && foundvers < HELPVERSION)
4019 	{
4020 		if (LogLevel > 1)
4021 			sm_syslog(LOG_WARNING, e->e_id,
4022 				  "%s too old (require version %d)",
4023 				  HelpFile, HELPVERSION);
4024 
4025 		/* avoid log next time */
4026 		foundvers = 0;
4027 	}
4028 
4029 	(void) sm_io_close(hf, SM_TIME_DEFAULT);
4030 }
4031