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