xref: /netbsd-src/external/ibm-public/postfix/dist/src/postscreen/postscreen_smtpd.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: postscreen_smtpd.c,v 1.1.1.3 2013/09/25 19:06:33 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	postscreen_smtpd 3
6 /* SUMMARY
7 /*	postscreen built-in SMTP server engine
8 /* SYNOPSIS
9 /*	#include <postscreen.h>
10 /*
11 /*	void	psc_smtpd_pre_jail_init(void)
12 /*
13 /*	void	psc_smtpd_init(void)
14 /*
15 /*	void	psc_smtpd_tests(state)
16 /*	PSC_STATE *state;
17 /*
18 /*	void	PSC_SMTPD_X21(state, final_reply)
19 /*	PSC_STATE *state;
20 /*	const char *final_reply;
21 /* DESCRIPTION
22 /*	psc_smtpd_pre_jail_init() performs one-time per-process
23 /*	initialization during the "before chroot" execution phase.
24 /*
25 /*	psc_smtpd_init() performs one-time per-process initialization.
26 /*
27 /*	psc_smtpd_tests() starts up an SMTP server engine for deep
28 /*	protocol tests and for collecting helo/sender/recipient
29 /*	information.
30 /*
31 /*	PSC_SMTPD_X21() redirects the SMTP client to an SMTP server
32 /*	engine, which sends the specified final reply at the first
33 /*	legitimate opportunity without doing any protocol tests.
34 /*
35 /*	Unlike the Postfix SMTP server, this engine does not announce
36 /*	PIPELINING support. This exposes spambots that pipeline
37 /*	their commands anyway. Like the Postfix SMTP server, this
38 /*	engine will accept input with bare newline characters. To
39 /*	pass the "pipelining" and "bare newline" test, the client
40 /*	has to properly speak SMTP all the way to the RCPT TO
41 /*	command. These tests fail if the client violates the protocol
42 /*	at any stage.
43 /*
44 /*	No support is announced for AUTH, XCLIENT or XFORWARD.
45 /*	Clients that need this should be whitelisted or should talk
46 /*	directly to the submission service.
47 /*
48 /*	The engine rejects RCPT TO and VRFY commands with the
49 /*	state->rcpt_reply response which depends on program history,
50 /*	rejects ETRN with a generic response, and closes the
51 /*	connection after QUIT.
52 /*
53 /*	Since this engine defers or rejects all non-junk commands,
54 /*	there is no point maintaining separate counters for "error"
55 /*	commands and "junk" commands.  Instead, the engine maintains
56 /*	a per-session command counter, and terminates the session
57 /*	with a 421 reply when the command count exceeds the limit.
58 /*
59 /*	We limit the command count, as well as the total time to
60 /*	receive a command. This limits the time per client more
61 /*	effectively than would be possible with read() timeouts.
62 /*
63 /*	There is no concern about getting blocked on output.  The
64 /*	psc_send() routine uses non-blocking output, and discards
65 /*	output that the client is not willing to receive.
66 /* PROTOCOL INSPECTION VERSUS CONTENT INSPECTION
67 /*	The goal of postscreen is to keep spambots away from Postfix.
68 /*	To recognize spambots, postscreen measures properties of
69 /*	the client IP address and of the client SMTP protocol
70 /*	implementation.  These client properties don't change with
71 /*	each delivery attempt.  Therefore it is possible to make a
72 /*	long-term decision after a single measurement.  For example,
73 /*	allow a good client to skip the DNSBL test for 24 hours,
74 /*	or to skip the pipelining test for one week.
75 /*
76 /*	If postscreen were to measure properties of message content
77 /*	(MIME compliance, etc.) then it would measure properties
78 /*	that may change with each delivery attempt.  Here, it would
79 /*	be wrong to make a long-term decision after a single
80 /*	measurement. Instead, postscreen would need to develop a
81 /*	ranking based on the content of multiple messages from the
82 /*	same client.
83 /*
84 /*	Many spambots avoid spamming the same site repeatedly.
85 /*	Thus, postscreen must make decisions after a single
86 /*	measurement. Message content is not a good indicator for
87 /*	making long-term decisions after single measurements, and
88 /*	that is why postscreen does not inspect message content.
89 /* REJECTING RCPT TO VERSUS SENDING LIVE SOCKETS TO SMTPD(8)
90 /*	When post-handshake protocol tests are enabled, postscreen
91 /*	rejects the RCPT TO command from a good client, and forces
92 /*	it to deliver mail in a later session. This is why
93 /*	post-handshake protocol tests have a longer expiration time
94 /*	than pre-handshake tests.
95 /*
96 /*	Instead, postscreen could send the network socket to smtpd(8)
97 /*	and ship the session history (including TLS and other SMTP
98 /*	or non-SMTP attributes) as auxiliary data. The Postfix SMTP
99 /*	server would then use new code to replay the session history,
100 /*	and would use existing code to validate the client, helo,
101 /*	sender and recipient address.
102 /*
103 /*	Such an approach would increase the implementation and
104 /*	maintenance effort, because:
105 /*
106 /*	1) New replay code would be needed in smtpd(8), such that
107 /*	the HELO, EHLO, and MAIL command handlers can delay their
108 /*	error responses until the RCPT TO reply.
109 /*
110 /*	2) postscreen(8) would have to implement more of smtpd(8)'s
111 /*	syntax checks, to avoid confusing delayed "syntax error"
112 /*	and other error responses syntax error responses while
113 /*	replaying history.
114 /*
115 /*	3) New code would be needed in postscreen(8) and smtpd(8)
116 /*	to send and receive the session history (including TLS and
117 /*	other SMTP or non-SMTP attributes) as auxiliary data while
118 /*	sending the network socket from postscreen(8) to smtpd(8).
119 /* REJECTING RCPT TO VERSUS PROXYING LIVE SESSIONS TO SMTPD(8)
120 /*	An alternative would be to proxy the session history to a
121 /*	real Postfix SMTP process, presumably passing TLS and other
122 /*	attributes via an extended XCLIENT implementation. That
123 /*	would require all the work described in 2) above, plus
124 /*	duplication of all the features of the smtpd(8) TLS engine,
125 /*	plus additional XCLIENT support for a lot more attributes.
126 /* LICENSE
127 /* .ad
128 /* .fi
129 /*	The Secure Mailer license must be distributed with this software.
130 /* AUTHOR(S)
131 /*	Wietse Venema
132 /*	IBM T.J. Watson Research
133 /*	P.O. Box 704
134 /*	Yorktown Heights, NY 10598, USA
135 /*--*/
136 
137 /* System library. */
138 
139 #include <sys_defs.h>
140 #include <string.h>
141 #include <ctype.h>
142 
143 #ifdef STRCASECMP_IN_STRINGS_H
144 #include <strings.h>
145 #endif
146 
147 /* Utility library. */
148 
149 #include <msg.h>
150 #include <stringops.h>
151 #include <mymalloc.h>
152 #include <iostuff.h>
153 #include <vstring.h>
154 
155 /* Global library. */
156 
157 #include <mail_params.h>
158 #include <mail_proto.h>
159 #include <is_header.h>
160 #include <string_list.h>
161 #include <maps.h>
162 #include <ehlo_mask.h>
163 #include <lex_822.h>
164 
165 /* TLS library. */
166 
167 #include <tls.h>
168 
169 /* Application-specific. */
170 
171 #include <postscreen.h>
172 
173  /*
174   * Plan for future body processing. See smtp-sink.c. For now, we have no
175   * per-session push-back except for the single-character push-back that
176   * VSTREAM guarantees after we read one character.
177   */
178 #define PSC_SMTPD_HAVE_PUSH_BACK(state)	(0)
179 #define PSC_SMTPD_PUSH_BACK_CHAR(state, ch) \
180 	vstream_ungetc((state)->smtp_client_stream, (ch))
181 #define PSC_SMTPD_NEXT_CHAR(state) \
182 	VSTREAM_GETC((state)->smtp_client_stream)
183 
184 #define PSC_SMTPD_BUFFER_EMPTY(state) \
185 	(!PSC_SMTPD_HAVE_PUSH_BACK(state) \
186 	&& vstream_peek((state)->smtp_client_stream) <= 0)
187 
188 #define PSC_SMTPD_PEEK_DATA(state) \
189 	vstream_peek_data((state)->smtp_client_stream)
190 #define PSC_SMTPD_PEEK_LEN(state) \
191 	vstream_peek((state)->smtp_client_stream)
192 
193  /*
194   * Dynamic reply strings. To minimize overhead we format these once.
195   */
196 static char *psc_smtpd_greeting;	/* smtp banner */
197 static char *psc_smtpd_helo_reply;	/* helo reply */
198 static char *psc_smtpd_ehlo_reply_plain;/* multi-line ehlo reply, non-TLS */
199 static char *psc_smtpd_ehlo_reply_tls;	/* multi-line ehlo reply, with TLS */
200 static char *psc_smtpd_timeout_reply;	/* timeout reply */
201 static char *psc_smtpd_421_reply;	/* generic final_reply value */
202 
203  /*
204   * Forward declaration, needed by PSC_CLEAR_EVENT_REQUEST.
205   */
206 static void psc_smtpd_time_event(int, char *);
207 static void psc_smtpd_read_event(int, char *);
208 
209  /*
210   * Encapsulation. The STARTTLS, EHLO and AUTH command handlers temporarily
211   * suspend SMTP command events, send an asynchronous proxy request, and
212   * resume SMTP command events after receiving the asynchrounous proxy
213   * response (the EHLO handler must asynchronously talk to the auth server
214   * before it can announce the SASL mechanism list; the list can depend on
215   * the client IP address and on the presence on TLS encryption).
216   */
217 #define PSC_RESUME_SMTP_CMD_EVENTS(state) do { \
218 	PSC_READ_EVENT_REQUEST2(vstream_fileno((state)->smtp_client_stream), \
219 			       psc_smtpd_read_event, psc_smtpd_time_event, \
220 			       (char *) (state), PSC_EFF_CMD_TIME_LIMIT); \
221 	if (!PSC_SMTPD_BUFFER_EMPTY(state)) \
222 	    psc_smtpd_read_event(EVENT_READ, (char *) state); \
223     } while (0)
224 
225 #define PSC_SUSPEND_SMTP_CMD_EVENTS(state) \
226     PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
227 			   psc_smtpd_time_event, (char *) (state));
228 
229  /*
230   * Make control characters and other non-text visible.
231   */
232 #define PSC_SMTPD_ESCAPE_TEXT(dest, src, src_len, max_len) do { \
233 	ssize_t _s_len = (src_len); \
234 	ssize_t _m_len = (max_len); \
235 	(void) escape((dest), (src), _s_len < _m_len ? _s_len : _m_len); \
236     } while (0)
237 
238  /*
239   * Command parser support.
240   */
241 #define PSC_SMTPD_NEXT_TOKEN(ptr) mystrtok(&(ptr), " ")
242 
243  /*
244   * EHLO keyword filter
245   */
246 static MAPS *psc_ehlo_discard_maps;
247 static int psc_ehlo_discard_mask;
248 
249  /*
250   * Command editing filter.
251   */
252 static DICT *psc_cmd_filter;
253 
254  /*
255   * Encapsulation. We must not forget turn off input/timer events when we
256   * terminate the SMTP protocol engine.
257   *
258   * It would be safer to turn off input/timer events after each event, and to
259   * turn on input/timer events again when we want more input. But experience
260   * with the Postfix smtp-source and smtp-sink tools shows that this would
261   * noticeably increase the run-time cost.
262   */
263 #define PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply) do { \
264 	PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
265 				   (event), (char *) (state)); \
266 	PSC_DROP_SESSION_STATE((state), (reply)); \
267     } while (0);
268 
269 #define PSC_CLEAR_EVENT_HANGUP(state, event) do { \
270 	PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
271 				   (event), (char *) (state)); \
272 	psc_hangup_event(state); \
273     } while (0);
274 
275 /* psc_helo_cmd - record HELO and respond */
276 
277 static int psc_helo_cmd(PSC_STATE *state, char *args)
278 {
279     char   *helo_name = PSC_SMTPD_NEXT_TOKEN(args);
280 
281     /*
282      * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them.
283      */
284     if (helo_name == 0)
285 	return (PSC_SEND_REPLY(state, "501 Syntax: HELO hostname\r\n"));
286 
287     PSC_STRING_UPDATE(state->helo_name, helo_name);
288     PSC_STRING_RESET(state->sender);
289     /* Don't downgrade state->protocol, in case some test depends on this. */
290     return (PSC_SEND_REPLY(state, psc_smtpd_helo_reply));
291 }
292 
293 /* psc_smtpd_format_ehlo_reply - format EHLO response */
294 
295 static void psc_smtpd_format_ehlo_reply(VSTRING *buf, int discard_mask
296 				   /* , const char *sasl_mechanism_list */ )
297 {
298     const char *myname = "psc_smtpd_format_ehlo_reply";
299     int     saved_len = 0;
300 
301     if (msg_verbose)
302 	msg_info("%s: discard_mask %s", myname, str_ehlo_mask(discard_mask));
303 
304 #define PSC_EHLO_APPEND(save, buf, fmt) do { \
305 	(save) = LEN(buf); \
306 	vstring_sprintf_append((buf), (fmt)); \
307     } while (0)
308 
309 #define PSC_EHLO_APPEND1(save, buf, fmt, arg1) do { \
310 	(save) = LEN(buf); \
311 	vstring_sprintf_append((buf), (fmt), (arg1)); \
312     } while (0)
313 
314     vstring_sprintf(psc_temp, "250-%s\r\n", var_myhostname);
315     if ((discard_mask & EHLO_MASK_SIZE) == 0) {
316 	if (var_message_limit)
317 	    PSC_EHLO_APPEND1(saved_len, psc_temp, "250-SIZE %lu\r\n",
318 			     (unsigned long) var_message_limit);
319 	else
320 	    PSC_EHLO_APPEND(saved_len, psc_temp, "250-SIZE\r\n");
321     }
322     if ((discard_mask & EHLO_MASK_VRFY) == 0 && var_disable_vrfy_cmd == 0)
323 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-VRFY\r\n");
324     if ((discard_mask & EHLO_MASK_ETRN) == 0)
325 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-ETRN\r\n");
326     if ((discard_mask & EHLO_MASK_STARTTLS) == 0 && var_psc_use_tls)
327 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-STARTTLS\r\n");
328 #ifdef TODO_SASL_AUTH
329     if ((discard_mask & EHLO_MASK_AUTH) == 0 && sasl_mechanism_list
330 	&& (!var_psc_tls_auth_only || (discard_mask & EHLO_MASK_STARTTLS))) {
331 	PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH %s", sasl_mechanism_list);
332 	if (var_broken_auth_clients)
333 	    PSC_EHLO_APPEND1(saved_len, psc_temp, "AUTH=%s", sasl_mechanism_list);
334     }
335 #endif
336     if ((discard_mask & EHLO_MASK_ENHANCEDSTATUSCODES) == 0)
337 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-ENHANCEDSTATUSCODES\r\n");
338     if ((discard_mask & EHLO_MASK_8BITMIME) == 0)
339 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-8BITMIME\r\n");
340     if ((discard_mask & EHLO_MASK_DSN) == 0)
341 	PSC_EHLO_APPEND(saved_len, psc_temp, "250-DSN\r\n");
342     STR(psc_temp)[saved_len + 3] = ' ';
343 }
344 
345 /* psc_ehlo_cmd - record EHLO and respond */
346 
347 static int psc_ehlo_cmd(PSC_STATE *state, char *args)
348 {
349     char   *helo_name = PSC_SMTPD_NEXT_TOKEN(args);
350     const char *ehlo_words;
351     int     discard_mask;
352     char   *reply;
353 
354     /*
355      * smtpd(8) incompatibility: we ignore extra words; smtpd(8) saves them.
356      */
357     if (helo_name == 0)
358 	return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
359 
360     PSC_STRING_UPDATE(state->helo_name, helo_name);
361     PSC_STRING_RESET(state->sender);
362     state->protocol = MAIL_PROTO_ESMTP;
363 
364     /*
365      * smtpd(8) compatibility: dynamic reply filtering.
366      */
367     if (psc_ehlo_discard_maps != 0
368 	&& (ehlo_words = psc_maps_find(psc_ehlo_discard_maps,
369 				       state->smtp_client_addr, 0)) != 0
370 	&& (discard_mask = ehlo_mask(ehlo_words)) != psc_ehlo_discard_mask) {
371 	if (discard_mask && !(discard_mask & EHLO_MASK_SILENT))
372 	    msg_info("[%s]%s: discarding EHLO keywords: %s",
373 		  PSC_CLIENT_ADDR_PORT(state), str_ehlo_mask(discard_mask));
374 	if (state->flags & PSC_STATE_FLAG_USING_TLS)
375 	    discard_mask |= EHLO_MASK_STARTTLS;
376 	psc_smtpd_format_ehlo_reply(psc_temp, discard_mask);
377 	reply = STR(psc_temp);
378 	state->ehlo_discard_mask = discard_mask;
379     } else if (psc_ehlo_discard_maps && psc_ehlo_discard_maps->error) {
380 	msg_fatal("%s lookup error for %s",
381 		  psc_ehlo_discard_maps->title, state->smtp_client_addr);
382     } else if (state->flags & PSC_STATE_FLAG_USING_TLS) {
383 	reply = psc_smtpd_ehlo_reply_tls;
384 	state->ehlo_discard_mask = psc_ehlo_discard_mask | EHLO_MASK_STARTTLS;
385     } else {
386 	reply = psc_smtpd_ehlo_reply_plain;
387 	state->ehlo_discard_mask = psc_ehlo_discard_mask;
388     }
389     return (PSC_SEND_REPLY(state, reply));
390 }
391 
392 /* psc_starttls_resume - resume the SMTP protocol after tlsproxy activation */
393 
394 static void psc_starttls_resume(int unused_event, char *context)
395 {
396     const char *myname = "psc_starttls_resume";
397     PSC_STATE *state = (PSC_STATE *) context;
398 
399     /*
400      * Reset SMTP server state if STARTTLS was successful.
401      */
402     if (state->flags & PSC_STATE_FLAG_USING_TLS) {
403 	/* Purge the push-back buffer, when implemented. */
404 	PSC_STRING_RESET(state->helo_name);
405 	PSC_STRING_RESET(state->sender);
406 #ifdef TODO_SASL_AUTH
407 	/* Reset SASL AUTH state. Dovecot responses may change. */
408 #endif
409     }
410 
411     /*
412      * Resume read/timeout events. If we still have unread input, resume the
413      * command processor immediately.
414      */
415     PSC_RESUME_SMTP_CMD_EVENTS(state);
416 }
417 
418 /* psc_starttls_cmd - activate the tlsproxy server */
419 
420 static int psc_starttls_cmd(PSC_STATE *state, char *args)
421 {
422     const char *myname = "psc_starttls_cmd";
423 
424     /*
425      * smtpd(8) incompatibility: we can't send a 4XX reply that TLS is
426      * unavailable when tlsproxy(8) detects the problem too late.
427      */
428     if (PSC_SMTPD_NEXT_TOKEN(args) != 0)
429 	return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
430     if (state->flags & PSC_STATE_FLAG_USING_TLS)
431 	return (PSC_SEND_REPLY(state,
432 			       "554 5.5.1 Error: TLS already active\r\n"));
433     if (var_psc_use_tls == 0 || (state->ehlo_discard_mask & EHLO_MASK_STARTTLS))
434 	return (PSC_SEND_REPLY(state,
435 			   "502 5.5.1 Error: command not implemented\r\n"));
436 
437     /*
438      * Suspend the SMTP protocol until psc_starttls_resume() is called.
439      */
440     PSC_SUSPEND_SMTP_CMD_EVENTS(state);
441     psc_starttls_open(state, psc_starttls_resume);
442     return (0);
443 }
444 
445 /* psc_extract_addr - extract MAIL/RCPT address, unquoted form */
446 
447 static char *psc_extract_addr(VSTRING *result, const char *string)
448 {
449     const unsigned char *cp = (const unsigned char *) string;
450     char   *addr;
451     char   *colon;
452     int     stop_at;
453     int     inquote = 0;
454 
455     /*
456      * smtpd(8) incompatibility: we allow more invalid address forms, and we
457      * don't validate recipients. We are not going to deliver them so we
458      * won't have to worry about deliverability. This may have to change when
459      * we pass the socket to a real SMTP server and replay message envelope
460      * commands.
461      */
462 
463     /* Skip SP characters. */
464     while (*cp && *cp == ' ')
465 	cp++;
466 
467     /* Choose the terminator for <addr> or bare addr. */
468     if (*cp == '<') {
469 	cp++;
470 	stop_at = '>';
471     } else {
472 	stop_at = ' ';
473     }
474 
475     /* Skip to terminator or end. */
476     VSTRING_RESET(result);
477     for ( /* void */ ; *cp; cp++) {
478 	if (!inquote && *cp == stop_at)
479 	    break;
480 	if (*cp == '"') {
481 	    inquote = !inquote;
482 	} else {
483 	    if (*cp == '\\' && *++cp == 0)
484 		break;
485 	    VSTRING_ADDCH(result, *cp);
486 	}
487     }
488     VSTRING_TERMINATE(result);
489 
490     /*
491      * smtpd(8) compatibility: truncate deprecated route address form. This
492      * is primarily to simplify logfile analysis.
493      */
494     addr = STR(result);
495     if (*addr == '@' && (colon = strchr(addr, ':')) != 0)
496 	addr = colon + 1;
497     return (addr);
498 }
499 
500 /* psc_mail_cmd - record MAIL and respond */
501 
502 static int psc_mail_cmd(PSC_STATE *state, char *args)
503 {
504     char   *colon;
505     char   *addr;
506 
507     /*
508      * smtpd(8) incompatibility: we never reject the sender, and we ignore
509      * additional arguments.
510      */
511     if (var_psc_helo_required && state->helo_name == 0)
512 	return (PSC_SEND_REPLY(state,
513 			       "503 5.5.1 Error: send HELO/EHLO first\r\n"));
514     if (state->sender != 0)
515 	return (PSC_SEND_REPLY(state,
516 			       "503 5.5.1 Error: nested MAIL command\r\n"));
517     if (args == 0 || (colon = strchr(args, ':')) == 0)
518 	return (PSC_SEND_REPLY(state,
519 			       "501 5.5.4 Syntax: MAIL FROM:<address>\r\n"));
520     if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0)
521 	return (PSC_SEND_REPLY(state,
522 			       "501 5.1.7 Bad sender address syntax\r\n"));
523     PSC_STRING_UPDATE(state->sender, addr);
524     return (PSC_SEND_REPLY(state, "250 2.1.0 Ok\r\n"));
525 }
526 
527 /* psc_soften_reply - copy and soft-bounce a reply */
528 
529 static char *psc_soften_reply(const char *reply)
530 {
531     static VSTRING *buf = 0;
532 
533     if (buf == 0)
534 	buf = vstring_alloc(100);
535     vstring_strcpy(buf, reply);
536     if (reply[0] == '5')
537 	STR(buf)[0] = '4';
538     if (reply[4] == '5')
539 	STR(buf)[4] = '4';
540     return (STR(buf));
541 }
542 
543 /* psc_rcpt_cmd record RCPT and respond */
544 
545 static int psc_rcpt_cmd(PSC_STATE *state, char *args)
546 {
547     char   *colon;
548     char   *addr;
549 
550     /*
551      * smtpd(8) incompatibility: we reject all recipients, and ignore
552      * additional arguments.
553      */
554     if (state->sender == 0)
555 	return (PSC_SEND_REPLY(state,
556 			       "503 5.5.1 Error: need MAIL command\r\n"));
557     if (args == 0 || (colon = strchr(args, ':')) == 0)
558 	return (PSC_SEND_REPLY(state,
559 			       "501 5.5.4 Syntax: RCPT TO:<address>\r\n"));
560     if ((addr = psc_extract_addr(psc_temp, colon + 1)) == 0)
561 	return (PSC_SEND_REPLY(state,
562 			     "501 5.1.3 Bad recipient address syntax\r\n"));
563     msg_info("NOQUEUE: reject: RCPT from [%s]:%s: %.*s; "
564 	     "from=<%s>, to=<%s>, proto=%s, helo=<%s>",
565 	     PSC_CLIENT_ADDR_PORT(state),
566 	     (int) strlen(state->rcpt_reply) - 2,
567 	     var_soft_bounce == 0 ? state->rcpt_reply :
568 	     psc_soften_reply(state->rcpt_reply),
569 	     state->sender, addr, state->protocol,
570 	     state->helo_name ? state->helo_name : "");
571     return (PSC_SEND_REPLY(state, state->rcpt_reply));
572 }
573 
574 /* psc_data_cmd - respond to DATA and disconnect */
575 
576 static int psc_data_cmd(PSC_STATE *state, char *args)
577 {
578 
579     /*
580      * smtpd(8) incompatibility: we reject all requests.
581      */
582     if (PSC_SMTPD_NEXT_TOKEN(args) != 0)
583 	return (PSC_SEND_REPLY(state,
584 			       "501 5.5.4 Syntax: DATA\r\n"));
585     if (state->sender == 0)
586 	return (PSC_SEND_REPLY(state,
587 			       "503 5.5.1 Error: need RCPT command\r\n"));
588 
589     /*
590      * We really would like to hang up the connection as early as possible,
591      * so that we dont't have to deal with broken zombies that fall silent at
592      * the first reject response. For now we rely on stress-dependent command
593      * read timeouts.
594      *
595      * If we proceed into the data phase, enforce over-all DATA time limit.
596      */
597     return (PSC_SEND_REPLY(state,
598 			   "554 5.5.1 Error: no valid recipients\r\n"));
599 }
600 
601 /* psc_rset_cmd - reset, send 250 OK */
602 
603 static int psc_rset_cmd(PSC_STATE *state, char *unused_args)
604 {
605     PSC_STRING_RESET(state->sender);
606     return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
607 }
608 
609 /* psc_noop_cmd - respond to something */
610 
611 static int psc_noop_cmd(PSC_STATE *state, char *unused_args)
612 {
613     return (PSC_SEND_REPLY(state, "250 2.0.0 Ok\r\n"));
614 }
615 
616 /* psc_vrfy_cmd - respond to VRFY */
617 
618 static int psc_vrfy_cmd(PSC_STATE *state, char *args)
619 {
620 
621     /*
622      * smtpd(8) incompatibility: we reject all requests, and ignore
623      * additional arguments.
624      */
625     if (PSC_SMTPD_NEXT_TOKEN(args) == 0)
626 	return (PSC_SEND_REPLY(state,
627 			       "501 5.5.4 Syntax: VRFY address\r\n"));
628     if (var_psc_disable_vrfy)
629 	return (PSC_SEND_REPLY(state,
630 			       "502 5.5.1 VRFY command is disabled\r\n"));
631     return (PSC_SEND_REPLY(state, state->rcpt_reply));
632 }
633 
634 /* psc_etrn_cmd - reset, send 250 OK */
635 
636 static int psc_etrn_cmd(PSC_STATE *state, char *args)
637 {
638 
639     /*
640      * smtpd(8) incompatibility: we reject all requests, and ignore
641      * additional arguments.
642      */
643     if (var_psc_helo_required && state->helo_name == 0)
644 	return (PSC_SEND_REPLY(state,
645 			       "503 5.5.1 Error: send HELO/EHLO first\r\n"));
646     if (PSC_SMTPD_NEXT_TOKEN(args) == 0)
647 	return (PSC_SEND_REPLY(state,
648 			       "500 Syntax: ETRN domain\r\n"));
649     return (PSC_SEND_REPLY(state, "458 Unable to queue messages\r\n"));
650 }
651 
652 /* psc_quit_cmd - respond to QUIT and disconnect */
653 
654 static int psc_quit_cmd(PSC_STATE *state, char *unused_args)
655 {
656     const char *myname = "psc_quit_cmd";
657 
658     PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
659 				       "221 2.0.0 Bye\r\n");
660     /* Caution: state is now a dangling pointer. */
661     return (0);
662 }
663 
664 /* psc_smtpd_time_event - handle per-session time limit */
665 
666 static void psc_smtpd_time_event(int event, char *context)
667 {
668     const char *myname = "psc_smtpd_time_event";
669     PSC_STATE *state = (PSC_STATE *) context;
670 
671     if (msg_verbose > 1)
672 	msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
673 		 myname, psc_post_queue_length, psc_check_queue_length,
674 		 event, vstream_fileno(state->smtp_client_stream),
675 		 state->smtp_client_addr, state->smtp_client_port,
676 		 psc_print_state_flags(state->flags, myname));
677 
678     msg_info("COMMAND TIME LIMIT from [%s]:%s after %s",
679 	     PSC_CLIENT_ADDR_PORT(state), state->where);
680     PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
681 				       psc_smtpd_timeout_reply);
682 }
683 
684  /*
685   * The table of all SMTP commands that we know.
686   */
687 typedef struct {
688     const char *name;
689     int     (*action) (PSC_STATE *, char *);
690     int     flags;			/* see below */
691 } PSC_SMTPD_COMMAND;
692 
693 #define PSC_SMTPD_CMD_FLAG_NONE		(0)	/* no flags (i.e. disabled) */
694 #define PSC_SMTPD_CMD_FLAG_ENABLE	(1<<0)	/* command is enabled */
695 #define PSC_SMTPD_CMD_FLAG_DESTROY	(1<<1)	/* dangling pointer alert */
696 #define PSC_SMTPD_CMD_FLAG_PRE_TLS	(1<<2)	/* allowed with mandatory TLS */
697 #define PSC_SMTPD_CMD_FLAG_SUSPEND	(1<<3)	/* suspend command engine */
698 
699 static const PSC_SMTPD_COMMAND command_table[] = {
700     "HELO", psc_helo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
701     "EHLO", psc_ehlo_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
702     "STARTTLS", psc_starttls_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS | PSC_SMTPD_CMD_FLAG_SUSPEND,
703     "XCLIENT", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
704     "XFORWARD", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
705     "AUTH", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_NONE,
706     "MAIL", psc_mail_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
707     "RCPT", psc_rcpt_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
708     "DATA", psc_data_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
709     /* ".", psc_dot_cmd, PSC_SMTPD_CMD_FLAG_NONE, */
710     "RSET", psc_rset_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
711     "NOOP", psc_noop_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_PRE_TLS,
712     "VRFY", psc_vrfy_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
713     "ETRN", psc_etrn_cmd, PSC_SMTPD_CMD_FLAG_ENABLE,
714     "QUIT", psc_quit_cmd, PSC_SMTPD_CMD_FLAG_ENABLE | PSC_SMTPD_CMD_FLAG_DESTROY | PSC_SMTPD_CMD_FLAG_PRE_TLS,
715     0,
716 };
717 
718 /* psc_smtpd_read_event - pseudo responder */
719 
720 static void psc_smtpd_read_event(int event, char *context)
721 {
722     const char *myname = "psc_smtpd_read_event";
723     PSC_STATE *state = (PSC_STATE *) context;
724     int     ch;
725     struct cmd_trans {
726 	int     state;
727 	int     want;
728 	int     next_state;
729     };
730     const char *saved_where;
731 
732 #define PSC_SMTPD_CMD_ST_ANY		0
733 #define PSC_SMTPD_CMD_ST_CR		1
734 #define PSC_SMTPD_CMD_ST_CR_LF		2
735 
736     static const struct cmd_trans cmd_trans[] = {
737 	PSC_SMTPD_CMD_ST_ANY, '\r', PSC_SMTPD_CMD_ST_CR,
738 	PSC_SMTPD_CMD_ST_CR, '\n', PSC_SMTPD_CMD_ST_CR_LF,
739 	0, 0, 0,
740     };
741     const struct cmd_trans *transp;
742     char   *cmd_buffer_ptr;
743     char   *command;
744     const PSC_SMTPD_COMMAND *cmdp;
745     int     write_stat;
746 
747     if (msg_verbose > 1)
748 	msg_info("%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
749 		 myname, psc_post_queue_length, psc_check_queue_length,
750 		 event, vstream_fileno(state->smtp_client_stream),
751 		 state->smtp_client_addr, state->smtp_client_port,
752 		 psc_print_state_flags(state->flags, myname));
753 
754     /*
755      * Basic liveness requirements.
756      *
757      * Drain all input in the VSTREAM buffer, otherwise this socket will not
758      * receive further read event notification until the client disconnects!
759      *
760      * To suspend this loop temporarily before the buffer is drained, use the
761      * PSC_SUSPEND_SMTP_CMD_EVENTS() and PSC_RESUME_SMTP_CMD_EVENTS() macros,
762      * and set the PSC_SMTPD_CMD_FLAG_SUSPEND flag in the command table.
763      *
764      * Don't try to read input before it has arrived, otherwise we would starve
765      * the pseudo threads of other sessions. Get out of here as soon as the
766      * VSTREAM read buffer dries up. Do not look for more input in kernel
767      * buffers. That input wasn't likely there when psc_smtpd_read_event()
768      * was called. Also, yielding the pseudo thread will improve fairness for
769      * other pseudo threads.
770      */
771 
772     /*
773      * Note: on entry into this function the VSTREAM buffer may or may not be
774      * empty, so we test the "no more input" condition at the bottom of the
775      * loops.
776      */
777     for (;;) {
778 
779 	/*
780 	 * Read one command line, possibly one fragment at a time.
781 	 */
782 	for (;;) {
783 
784 	    if ((ch = PSC_SMTPD_NEXT_CHAR(state)) == VSTREAM_EOF) {
785 		PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event);
786 		return;
787 	    }
788 
789 	    /*
790 	     * Sanity check. We don't want to store infinitely long commands.
791 	     */
792 	    if (state->read_state == PSC_SMTPD_CMD_ST_ANY
793 		&& VSTRING_LEN(state->cmd_buffer) >= var_line_limit) {
794 		msg_info("COMMAND LENGTH LIMIT from [%s]:%s after %s",
795 			 PSC_CLIENT_ADDR_PORT(state), state->where);
796 		PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
797 						   psc_smtpd_421_reply);
798 		return;
799 	    }
800 	    VSTRING_ADDCH(state->cmd_buffer, ch);
801 
802 	    /*
803 	     * Try to match the current character desired by the state
804 	     * machine. If that fails, try to restart the machine with a
805 	     * match for its first state. Like smtpd(8), we understand lines
806 	     * ending in <CR><LF> and bare <LF>. Unlike smtpd(8), we may
807 	     * treat lines ending in bare <LF> as an offense.
808 	     */
809 	    for (transp = cmd_trans; transp->state != state->read_state; transp++)
810 		if (transp->want == 0)
811 		    msg_panic("%s: command_read: unknown state: %d",
812 			      myname, state->read_state);
813 	    if (ch == transp->want)
814 		state->read_state = transp->next_state;
815 	    else if (ch == cmd_trans[0].want)
816 		state->read_state = cmd_trans[0].next_state;
817 	    else
818 		state->read_state = PSC_SMTPD_CMD_ST_ANY;
819 	    if (state->read_state == PSC_SMTPD_CMD_ST_CR_LF) {
820 		vstring_truncate(state->cmd_buffer,
821 				 VSTRING_LEN(state->cmd_buffer) - 2);
822 		break;
823 	    }
824 
825 	    /*
826 	     * Bare newline test.
827 	     */
828 	    if (ch == '\n') {
829 		if ((state->flags & PSC_STATE_MASK_BARLF_TODO_SKIP)
830 		    == PSC_STATE_FLAG_BARLF_TODO) {
831 		    PSC_SMTPD_ESCAPE_TEXT(psc_temp, STR(state->cmd_buffer),
832 				   VSTRING_LEN(state->cmd_buffer) - 1, 100);
833 		    msg_info("BARE NEWLINE from [%s]:%s after %s",
834 			     PSC_CLIENT_ADDR_PORT(state), STR(psc_temp));
835 		    PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_FAIL);
836 		    PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_BARLF_PASS);
837 		    state->barlf_stamp = PSC_TIME_STAMP_DISABLED;	/* XXX */
838 		    /* Skip this test for the remainder of this session. */
839 		    PSC_SKIP_SESSION_STATE(state, "bare newline test",
840 					   PSC_STATE_FLAG_BARLF_SKIP);
841 		    switch (psc_barlf_action) {
842 		    case PSC_ACT_DROP:
843 			PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
844 						       psc_smtpd_time_event,
845 					    "521 5.5.1 Protocol error\r\n");
846 			return;
847 		    case PSC_ACT_ENFORCE:
848 			PSC_ENFORCE_SESSION_STATE(state,
849 					    "550 5.5.1 Protocol error\r\n");
850 			break;
851 		    case PSC_ACT_IGNORE:
852 			PSC_UNFAIL_SESSION_STATE(state,
853 						 PSC_STATE_FLAG_BARLF_FAIL);
854 			/* Temporarily whitelist until something expires. */
855 			PSC_PASS_SESSION_STATE(state, "bare newline test",
856 					       PSC_STATE_FLAG_BARLF_PASS);
857 			state->barlf_stamp = event_time() + psc_min_ttl;
858 			break;
859 		    default:
860 			msg_panic("%s: unknown bare_newline action value %d",
861 				  myname, psc_barlf_action);
862 		    }
863 		}
864 		vstring_truncate(state->cmd_buffer,
865 				 VSTRING_LEN(state->cmd_buffer) - 1);
866 		break;
867 	    }
868 
869 	    /*
870 	     * Yield this pseudo thread when the VSTREAM buffer is empty in
871 	     * the middle of a command.
872 	     *
873 	     * XXX Do not reset the read timeout. The entire command must be
874 	     * received within the time limit.
875 	     */
876 	    if (PSC_SMTPD_BUFFER_EMPTY(state))
877 		return;
878 	}
879 
880 	/*
881 	 * Terminate the command buffer, and apply the last-resort command
882 	 * editing workaround.
883 	 */
884 	VSTRING_TERMINATE(state->cmd_buffer);
885 	if (psc_cmd_filter != 0) {
886 	    const char *cp;
887 
888 	    for (cp = STR(state->cmd_buffer); *cp && IS_SPACE_TAB(*cp); cp++)
889 		 /* void */ ;
890 	    if ((cp = psc_dict_get(psc_cmd_filter, cp)) != 0) {
891 		msg_info("[%s]:%s: replacing command \"%.100s\" with \"%.100s\"",
892 			 state->smtp_client_addr, state->smtp_client_port,
893 			 STR(state->cmd_buffer), cp);
894 		vstring_strcpy(state->cmd_buffer, cp);
895 	    } else if (psc_cmd_filter->error != 0) {
896 		msg_fatal("%s:%s lookup error for \"%.100s\"",
897 			  psc_cmd_filter->type, psc_cmd_filter->name, cp);
898 	    }
899 	}
900 
901 	/*
902 	 * Reset the command buffer write pointer and state machine in
903 	 * preparation for the next command. For this to work as expected,
904 	 * VSTRING_RESET() must be non-destructive. We just can't ask for the
905 	 * VSTRING_LEN() and vstring_end() results.
906 	 */
907 	state->read_state = PSC_SMTPD_CMD_ST_ANY;
908 	VSTRING_RESET(state->cmd_buffer);
909 
910 	/*
911 	 * Process the command line.
912 	 *
913 	 * Caution: some command handlers terminate the session and destroy the
914 	 * session state structure. When this happens we must leave the SMTP
915 	 * engine to avoid a dangling pointer problem.
916 	 */
917 	cmd_buffer_ptr = STR(state->cmd_buffer);
918 	if (msg_verbose)
919 	    msg_info("< [%s]:%s: %s", state->smtp_client_addr,
920 		     state->smtp_client_port, cmd_buffer_ptr);
921 
922 	/* Parse the command name. */
923 	if ((command = PSC_SMTPD_NEXT_TOKEN(cmd_buffer_ptr)) == 0)
924 	    command = "";
925 
926 	/*
927 	 * The non-SMTP, PIPELINING and command COUNT tests depend on the
928 	 * client command handler.
929 	 *
930 	 * Caution: cmdp->name and cmdp->action may be null on loop exit.
931 	 */
932 	saved_where = state->where;
933 	state->where = PSC_SMTPD_CMD_UNIMPL;
934 	for (cmdp = command_table; cmdp->name != 0; cmdp++) {
935 	    if (strcasecmp(command, cmdp->name) == 0) {
936 		state->where = cmdp->name;
937 		break;
938 	    }
939 	}
940 
941 	if ((state->flags & PSC_STATE_FLAG_SMTPD_X21)
942 	    && cmdp->action != psc_quit_cmd) {
943 	    PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
944 					       state->final_reply);
945 	    return;
946 	}
947 	/* Non-SMTP command test. */
948 	if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_SKIP)
949 	    == PSC_STATE_FLAG_NSMTP_TODO && cmdp->name == 0
950 	    && (is_header(command)
951 	/* Ignore forbid_cmds lookup errors. Non-critical feature. */
952 		|| (*var_psc_forbid_cmds
953 		    && string_list_match(psc_forbid_cmds, command)))) {
954 	    printable(command, '?');
955 	    PSC_SMTPD_ESCAPE_TEXT(psc_temp, cmd_buffer_ptr,
956 				  strlen(cmd_buffer_ptr), 100);
957 	    msg_info("NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s",
958 		     PSC_CLIENT_ADDR_PORT(state), saved_where,
959 		     command, STR(psc_temp));
960 	    PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_FAIL);
961 	    PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_NSMTP_PASS);
962 	    state->nsmtp_stamp = PSC_TIME_STAMP_DISABLED;	/* XXX */
963 	    /* Skip this test for the remainder of this SMTP session. */
964 	    PSC_SKIP_SESSION_STATE(state, "non-smtp test",
965 				   PSC_STATE_FLAG_NSMTP_SKIP);
966 	    switch (psc_nsmtp_action) {
967 	    case PSC_ACT_DROP:
968 		PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
969 						   psc_smtpd_time_event,
970 		   "521 5.7.0 Error: I can break rules, too. Goodbye.\r\n");
971 		return;
972 	    case PSC_ACT_ENFORCE:
973 		PSC_ENFORCE_SESSION_STATE(state,
974 					  "550 5.5.1 Protocol error\r\n");
975 		break;
976 	    case PSC_ACT_IGNORE:
977 		PSC_UNFAIL_SESSION_STATE(state,
978 					 PSC_STATE_FLAG_NSMTP_FAIL);
979 		/* Temporarily whitelist until something else expires. */
980 		PSC_PASS_SESSION_STATE(state, "non-smtp test",
981 				       PSC_STATE_FLAG_NSMTP_PASS);
982 		state->nsmtp_stamp = event_time() + psc_min_ttl;
983 		break;
984 	    default:
985 		msg_panic("%s: unknown non_smtp_command action value %d",
986 			  myname, psc_nsmtp_action);
987 	    }
988 	}
989 	/* Command PIPELINING test. */
990 	if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_SKIP)
991 	    == PSC_STATE_FLAG_PIPEL_TODO && !PSC_SMTPD_BUFFER_EMPTY(state)) {
992 	    printable(command, '?');
993 	    PSC_SMTPD_ESCAPE_TEXT(psc_temp, PSC_SMTPD_PEEK_DATA(state),
994 				  PSC_SMTPD_PEEK_LEN(state), 100);
995 	    msg_info("COMMAND PIPELINING from [%s]:%s after %.100s: %s",
996 		     PSC_CLIENT_ADDR_PORT(state), command, STR(psc_temp));
997 	    PSC_FAIL_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_FAIL);
998 	    PSC_UNPASS_SESSION_STATE(state, PSC_STATE_FLAG_PIPEL_PASS);
999 	    state->pipel_stamp = PSC_TIME_STAMP_DISABLED;	/* XXX */
1000 	    /* Skip this test for the remainder of this SMTP session. */
1001 	    PSC_SKIP_SESSION_STATE(state, "pipelining test",
1002 				   PSC_STATE_FLAG_PIPEL_SKIP);
1003 	    switch (psc_pipel_action) {
1004 	    case PSC_ACT_DROP:
1005 		PSC_CLEAR_EVENT_DROP_SESSION_STATE(state,
1006 						   psc_smtpd_time_event,
1007 					    "521 5.5.1 Protocol error\r\n");
1008 		return;
1009 	    case PSC_ACT_ENFORCE:
1010 		PSC_ENFORCE_SESSION_STATE(state,
1011 					  "550 5.5.1 Protocol error\r\n");
1012 		break;
1013 	    case PSC_ACT_IGNORE:
1014 		PSC_UNFAIL_SESSION_STATE(state,
1015 					 PSC_STATE_FLAG_PIPEL_FAIL);
1016 		/* Temporarily whitelist until something else expires. */
1017 		PSC_PASS_SESSION_STATE(state, "pipelining test",
1018 				       PSC_STATE_FLAG_PIPEL_PASS);
1019 		state->pipel_stamp = event_time() + psc_min_ttl;
1020 		break;
1021 	    default:
1022 		msg_panic("%s: unknown pipelining action value %d",
1023 			  myname, psc_pipel_action);
1024 	    }
1025 	}
1026 
1027 	/*
1028 	 * The following tests don't pass until the client gets all the way
1029 	 * to the RCPT TO command. However, the client can still fail these
1030 	 * tests with some later command.
1031 	 */
1032 	if (cmdp->action == psc_rcpt_cmd) {
1033 	    if ((state->flags & PSC_STATE_MASK_BARLF_TODO_PASS_FAIL)
1034 		== PSC_STATE_FLAG_BARLF_TODO) {
1035 		PSC_PASS_SESSION_STATE(state, "bare newline test",
1036 				       PSC_STATE_FLAG_BARLF_PASS);
1037 		/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
1038 		state->barlf_stamp = event_time() + var_psc_barlf_ttl;
1039 	    }
1040 	    if ((state->flags & PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL)
1041 		== PSC_STATE_FLAG_NSMTP_TODO) {
1042 		PSC_PASS_SESSION_STATE(state, "non-smtp test",
1043 				       PSC_STATE_FLAG_NSMTP_PASS);
1044 		/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
1045 		state->nsmtp_stamp = event_time() + var_psc_nsmtp_ttl;
1046 	    }
1047 	    if ((state->flags & PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL)
1048 		== PSC_STATE_FLAG_PIPEL_TODO) {
1049 		PSC_PASS_SESSION_STATE(state, "pipelining test",
1050 				       PSC_STATE_FLAG_PIPEL_PASS);
1051 		/* XXX Reset to PSC_TIME_STAMP_DISABLED on failure. */
1052 		state->pipel_stamp = event_time() + var_psc_pipel_ttl;
1053 	    }
1054 	}
1055 	/* Command COUNT limit test. */
1056 	if (++state->command_count > var_psc_cmd_count
1057 	    && cmdp->action != psc_quit_cmd) {
1058 	    msg_info("COMMAND COUNT LIMIT from [%s]:%s after %s",
1059 		     PSC_CLIENT_ADDR_PORT(state), saved_where);
1060 	    PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, psc_smtpd_time_event,
1061 					       psc_smtpd_421_reply);
1062 	    return;
1063 	}
1064 	/* Finally, execute the command. */
1065 	if (cmdp->name == 0 || (cmdp->flags & PSC_SMTPD_CMD_FLAG_ENABLE) == 0) {
1066 	    write_stat = PSC_SEND_REPLY(state,
1067 			     "502 5.5.2 Error: command not recognized\r\n");
1068 	} else if (var_psc_enforce_tls
1069 		   && (state->flags & PSC_STATE_FLAG_USING_TLS) == 0
1070 		   && (cmdp->flags & PSC_SMTPD_CMD_FLAG_PRE_TLS) == 0) {
1071 	    write_stat = PSC_SEND_REPLY(state,
1072 		       "530 5.7.0 Must issue a STARTTLS command first\r\n");
1073 	} else {
1074 	    write_stat = cmdp->action(state, cmd_buffer_ptr);
1075 	    if (cmdp->flags & PSC_SMTPD_CMD_FLAG_DESTROY)
1076 		return;
1077 	}
1078 
1079 	/*
1080 	 * Terminate the session after a write error.
1081 	 */
1082 	if (write_stat < 0) {
1083 	    PSC_CLEAR_EVENT_HANGUP(state, psc_smtpd_time_event);
1084 	    return;
1085 	}
1086 
1087 	/*
1088 	 * We're suspended, waiting for some external event to happen.
1089 	 * Hopefully, someone will call us back to process the remainder of
1090 	 * the pending input, otherwise we could hang.
1091 	 */
1092 	if (cmdp->flags & PSC_SMTPD_CMD_FLAG_SUSPEND)
1093 	    return;
1094 
1095 	/*
1096 	 * Reset the command read timeout before reading the next command.
1097 	 */
1098 	event_request_timer(psc_smtpd_time_event, (char *) state,
1099 			    PSC_EFF_CMD_TIME_LIMIT);
1100 
1101 	/*
1102 	 * Yield this pseudo thread when the VSTREAM buffer is empty.
1103 	 */
1104 	if (PSC_SMTPD_BUFFER_EMPTY(state))
1105 	    return;
1106     }
1107 }
1108 
1109 /* psc_smtpd_tests - per-session deep protocol test initialization */
1110 
1111 void    psc_smtpd_tests(PSC_STATE *state)
1112 {
1113     static char *myname = "psc_smtpd_tests";
1114 
1115     /*
1116      * Report errors and progress in the context of this test.
1117      */
1118     PSC_BEGIN_TESTS(state, "tests after SMTP handshake");
1119 
1120     /*
1121      * Initialize per-session state that is used only by the dummy engine:
1122      * the command read buffer and the command read state machine.
1123      */
1124     state->cmd_buffer = vstring_alloc(100);
1125     state->read_state = PSC_SMTPD_CMD_ST_ANY;
1126 
1127     /*
1128      * Opportunistically make postscreen more useful by turning on the
1129      * pipelining and non-SMTP command tests when a pre-handshake test
1130      * failed, or when some deep test is configured as enabled.
1131      *
1132      * XXX Make "opportunistically" configurable for each test.
1133      */
1134     if ((state->flags & PSC_STATE_FLAG_SMTPD_X21) == 0) {
1135 	state->flags |= PSC_STATE_MASK_SMTPD_TODO;
1136     } else {
1137 	state->flags &= ~PSC_STATE_MASK_SMTPD_TODO;
1138     }
1139 
1140     /*
1141      * Send no SMTP banner to pregreeting clients. This eliminates a lot of
1142      * "NON-SMTP COMMAND" events, and improves sender/recipient logging.
1143      */
1144     if ((state->flags & PSC_STATE_FLAG_PREGR_FAIL) == 0
1145 	&& PSC_SEND_REPLY(state, psc_smtpd_greeting) != 0) {
1146 	psc_hangup_event(state);
1147 	return;
1148     }
1149 
1150     /*
1151      * Wait for the client to respond.
1152      */
1153     PSC_READ_EVENT_REQUEST2(vstream_fileno(state->smtp_client_stream),
1154 			    psc_smtpd_read_event, psc_smtpd_time_event,
1155 			    (char *) state, PSC_EFF_CMD_TIME_LIMIT);
1156 }
1157 
1158 /* psc_smtpd_init - per-process deep protocol test initialization */
1159 
1160 void    psc_smtpd_init(void)
1161 {
1162 
1163     /*
1164      * Initialize the server banner.
1165      */
1166     vstring_sprintf(psc_temp, "220 %s\r\n", var_smtpd_banner);
1167     psc_smtpd_greeting = mystrdup(STR(psc_temp));
1168 
1169     /*
1170      * Initialize the HELO reply.
1171      */
1172     vstring_sprintf(psc_temp, "250 %s\r\n", var_myhostname);
1173     psc_smtpd_helo_reply = mystrdup(STR(psc_temp));
1174 
1175     /*
1176      * STARTTLS support. Note the complete absence of #ifdef USE_TLS
1177      * throughout the postscreen(8) source code. If Postfix is built without
1178      * TLS support, then the TLS proxy will simply report that TLS is not
1179      * available, and conventional error handling will take care of the
1180      * issue.
1181      *
1182      * Legacy code copied from smtpd(8). The pre-fabricated EHLO reply depends
1183      * on this.
1184      */
1185     if (*var_psc_tls_level) {
1186 	switch (tls_level_lookup(var_psc_tls_level)) {
1187 	default:
1188 	    msg_fatal("Invalid TLS level \"%s\"", var_psc_tls_level);
1189 	    /* NOTREACHED */
1190 	    break;
1191 	case TLS_LEV_SECURE:
1192 	case TLS_LEV_VERIFY:
1193 	case TLS_LEV_FPRINT:
1194 	    msg_warn("%s: unsupported TLS level \"%s\", using \"encrypt\"",
1195 		     VAR_PSC_TLS_LEVEL, var_psc_tls_level);
1196 	    /* FALLTHROUGH */
1197 	case TLS_LEV_ENCRYPT:
1198 	    var_psc_enforce_tls = var_psc_use_tls = 1;
1199 	    break;
1200 	case TLS_LEV_MAY:
1201 	    var_psc_enforce_tls = 0;
1202 	    var_psc_use_tls = 1;
1203 	    break;
1204 	case TLS_LEV_NONE:
1205 	    var_psc_enforce_tls = var_psc_use_tls = 0;
1206 	    break;
1207 	}
1208     }
1209     var_psc_use_tls = var_psc_use_tls || var_psc_enforce_tls;
1210 #ifdef TODO_SASL_AUTH
1211     var_psc_tls_auth_only = var_psc_tls_auth_only || var_psc_enforce_tls;
1212 #endif
1213 
1214     /*
1215      * Initialize the EHLO reply. Once for plaintext sessions, and once for
1216      * TLS sessions.
1217      */
1218     psc_smtpd_format_ehlo_reply(psc_temp, psc_ehlo_discard_mask);
1219     psc_smtpd_ehlo_reply_plain = mystrdup(STR(psc_temp));
1220 
1221     psc_smtpd_format_ehlo_reply(psc_temp,
1222 				psc_ehlo_discard_mask | EHLO_MASK_STARTTLS);
1223     psc_smtpd_ehlo_reply_tls = mystrdup(STR(psc_temp));
1224 
1225     /*
1226      * Initialize the 421 timeout reply.
1227      */
1228     vstring_sprintf(psc_temp, "421 4.4.2 %s Error: timeout exceeded\r\n",
1229 		    var_myhostname);
1230     psc_smtpd_timeout_reply = mystrdup(STR(psc_temp));
1231 
1232     /*
1233      * Initialize the generic 421 reply.
1234      */
1235     vstring_sprintf(psc_temp, "421 %s Service unavailable - try again later\r\n",
1236 		    var_myhostname);
1237     psc_smtpd_421_reply = mystrdup(STR(psc_temp));
1238 
1239     /*
1240      * Initialize the reply footer.
1241      */
1242     if (*var_psc_rej_footer)
1243 	psc_expand_init();
1244 }
1245 
1246 /* psc_smtpd_pre_jail_init - per-process deep protocol test initialization */
1247 
1248 void    psc_smtpd_pre_jail_init(void)
1249 {
1250 
1251     /*
1252      * Determine what server ESMTP features to suppress, typically to avoid
1253      * inter-operability problems. We do the default filter here, and
1254      * determine client-dependent filtering on the fly.
1255      *
1256      * XXX Bugger. This means we have to restart when the table changes!
1257      */
1258     if (*var_psc_ehlo_dis_maps)
1259 	psc_ehlo_discard_maps = maps_create(VAR_PSC_EHLO_DIS_MAPS,
1260 					    var_psc_ehlo_dis_maps,
1261 					    DICT_FLAG_LOCK);
1262     psc_ehlo_discard_mask = ehlo_mask(var_psc_ehlo_dis_words);
1263 
1264     /*
1265      * Last-resort command editing support.
1266      */
1267     if (*var_psc_cmd_filter)
1268 	psc_cmd_filter = dict_open(var_psc_cmd_filter, O_RDONLY,
1269 				   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
1270 }
1271