1 /*++
2 /* NAME
3 /*	smtp_trouble 3
4 /* SUMMARY
5 /*	error handler policies
6 /* SYNOPSIS
7 /*	#include "smtp.h"
8 /*
9 /*	int	smtp_sess_fail(state)
10 /*	SMTP_STATE *state;
11 /*
12 /*	int	smtp_site_fail(state, mta_name, resp, format, ...)
13 /*	SMTP_STATE *state;
14 /*	const char *mta_name;
15 /*	SMTP_RESP *resp;
16 /*	const char *format;
17 /*
18 /*	int	smtp_mesg_fail(state, mta_name, resp, format, ...)
19 /*	SMTP_STATE *state;
20 /*	const char *mta_name;
21 /*	SMTP_RESP *resp;
22 /*	const char *format;
23 /*
24 /*	void	smtp_rcpt_fail(state, recipient, mta_name, resp, format, ...)
25 /*	SMTP_STATE *state;
26 /*	RECIPIENT *recipient;
27 /*	const char *mta_name;
28 /*	SMTP_RESP *resp;
29 /*	const char *format;
30 /*
31 /*	int	smtp_stream_except(state, exception, description)
32 /*	SMTP_STATE *state;
33 /*	int	exception;
34 /*	const char *description;
35 /* AUXILIARY FUNCTIONS
36 /*	int	smtp_misc_fail(state, throttle, mta_name, resp, format, ...)
37 /*	SMTP_STATE *state;
38 /*	int	throttle;
39 /*	const char *mta_name;
40 /*	SMTP_RESP *resp;
41 /*	const char *format;
42 /* DESCRIPTION
43 /*	This module handles all non-fatal errors that can happen while
44 /*	attempting to deliver mail via SMTP, and implements the policy
45 /*	of how to deal with the error. Depending on the nature of
46 /*	the problem, delivery of a single message is deferred, delivery
47 /*	of all messages to the same domain is deferred, or one or more
48 /*	recipients are given up as non-deliverable and a bounce log is
49 /*	updated. In any case, the recipient is marked as either KEEP
50 /*	(try again with a backup host) or DROP (delete recipient from
51 /*	delivery request).
52 /*
53 /*	In addition, when an unexpected response code is seen such
54 /*	as 3xx where only 4xx or 5xx are expected, or any error code
55 /*	that suggests a syntax error or something similar, the
56 /*	protocol error flag is set so that the postmaster receives
57 /*	a transcript of the session. No notification is generated for
58 /*	what appear to be configuration errors - very likely, they
59 /*	would suffer the same problem and just cause more trouble.
60 /*
61 /*	In case of a soft error, action depends on whether the error
62 /*	qualifies for trying the request with other mail servers (log
63 /*	an informational record only and try a backup server) or
64 /*	whether this is the final server (log recipient delivery status
65 /*	records and delete the recipient from the request).
66 /*
67 /*	smtp_sess_fail() takes a pre-formatted error report after
68 /*	failure to complete some protocol handshake.  The policy is
69 /*	as with smtp_site_fail().
70 /*
71 /*	smtp_site_fail() handles the case where the program fails to
72 /*	complete the initial handshake: the server is not reachable,
73 /*	is not running, does not want talk to us, or we talk to ourselves.
74 /*	The \fIcode\fR gives an error status code; the \fIformat\fR
75 /*	argument gives a textual description.
76 /*	The policy is: soft error, non-final server: log an informational
77 /*	record why the host is being skipped; soft error, final server:
78 /*	defer delivery of all remaining recipients and mark the destination
79 /*	as problematic; hard error: bounce all remaining recipients.
80 /*	The session is marked as "do not cache".
81 /*	The result is non-zero.
82 /*
83 /*	smtp_mesg_fail() handles the case where the smtp server
84 /*	does not accept the sender address or the message data,
85 /*	or when the local MTA is unable to convert the message data.
86 /*	The policy is: soft error, non-final server: log an informational
87 /*	record why the host is being skipped; soft error, final server:
88 /*	defer delivery of all remaining recipients; hard error: bounce all
89 /*	remaining recipients.
90 /*	The result is non-zero.
91 /*
92 /*	smtp_misc_fail() provides a more detailed interface than
93 /*	smtp_site_fail() and smtp_mesg_fail(), which are convenience
94 /*	wrappers around smtp_misc_fail(). The throttle argument
95 /*	is either SMTP_THROTTLE or SMTP_NOTHROTTLE; it is used only
96 /*	in the "soft error, final server" policy, and determines
97 /*	whether a destination will be marked as problematic.
98 /*
99 /*	smtp_rcpt_fail() handles the case where a recipient is not
100 /*	accepted by the server for reasons other than that the server
101 /*	recipient limit is reached.
102 /*	The policy is: soft error, non-final server: log an informational
103 /*	record why the recipient is being skipped; soft error, final server:
104 /*	defer delivery of this recipient; hard error: bounce this
105 /*	recipient.
106 /*
107 /*	smtp_stream_except() handles the exceptions generated by
108 /*	the smtp_stream(3) module (i.e. timeouts and I/O errors).
109 /*	The \fIexception\fR argument specifies the type of problem.
110 /*	The \fIdescription\fR argument describes at what stage of
111 /*	the SMTP dialog the problem happened.
112 /*	The policy is: non-final server: log an informational record
113 /*	with the reason why the host is being skipped; final server:
114 /*	defer delivery of all remaining recipients.
115 /*	Retry plaintext delivery after TLS post-handshake session
116 /*	failure, provided that at least one recipient was not
117 /*	deferred or rejected during the TLS phase, and that global
118 /*	preconditions for plaintext fallback are met.
119 /*	The session is marked as "do not cache".
120 /*	The result is non-zero.
121 /*
122 /*	Arguments:
123 /* .IP state
124 /*	SMTP client state per delivery request.
125 /* .IP resp
126 /*	Server response including reply code and text.
127 /* .IP recipient
128 /*	Undeliverable recipient address information.
129 /* .IP format
130 /*	Human-readable description of why mail is not deliverable.
131 /* DIAGNOSTICS
132 /*	Panic: unknown exception code.
133 /* SEE ALSO
134 /*	smtp_proto(3) smtp high-level protocol
135 /*	smtp_stream(3) smtp low-level protocol
136 /*	defer(3) basic message defer interface
137 /*	bounce(3) basic message bounce interface
138 /* LICENSE
139 /* .ad
140 /* .fi
141 /*	The Secure Mailer license must be distributed with this software.
142 /* AUTHOR(S)
143 /*	Wietse Venema
144 /*	IBM T.J. Watson Research
145 /*	P.O. Box 704
146 /*	Yorktown Heights, NY 10598, USA
147 /*
148 /*	Wietse Venema
149 /*	Google, Inc.
150 /*	111 8th Avenue
151 /*	New York, NY 10011, USA
152 /*--*/
153 
154 /* System library. */
155 
156 #include <sys_defs.h>
157 #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
158 #include <stdarg.h>
159 #include <string.h>
160 
161 /* Utility library. */
162 
163 #include <msg.h>
164 #include <vstring.h>
165 #include <stringops.h>
166 
167 /* Global library. */
168 
169 #include <smtp_stream.h>
170 #include <deliver_request.h>
171 #include <deliver_completed.h>
172 #include <bounce.h>
173 #include <defer.h>
174 #include <mail_error.h>
175 #include <dsn_buf.h>
176 #include <dsn.h>
177 #include <mail_params.h>
178 
179 /* Application-specific. */
180 
181 #include "smtp.h"
182 #include "smtp_sasl.h"
183 
184 /* smtp_check_code - check response code */
185 
smtp_check_code(SMTP_SESSION * session,int code)186 static void smtp_check_code(SMTP_SESSION *session, int code)
187 {
188 
189     /*
190      * The intention of this code is to alert the postmaster when the local
191      * Postfix SMTP client screws up, protocol wise. RFC 821 says that x0z
192      * replies "refer to syntax errors, syntactically correct commands that
193      * don't fit any functional category, and unimplemented or superfluous
194      * commands". Unfortunately, this also triggers postmaster notices when
195      * remote servers screw up, protocol wise. This is becoming a common
196      * problem now that response codes are configured manually as part of
197      * anti-UCE systems, by people who aren't aware of RFC details.
198      *
199      * Fix 20190621: don't cache an SMTP session after an SMTP protocol error.
200      * The protocol may be in a bad state. Disable caching here so that the
201      * protocol engine will send QUIT.
202      */
203     if (code < 400 || code > 599
204 	|| code == 555			/* RFC 1869, section 6.1. */
205 	|| (code >= 500 && code < 510)) {
206 	session->error_mask |= MAIL_ERROR_PROTOCOL;
207 	DONT_CACHE_THIS_SESSION;
208     }
209 }
210 
211 /* smtp_bulk_fail - skip, defer or bounce recipients, maybe throttle queue */
212 
smtp_bulk_fail(SMTP_STATE * state,int throttle_queue)213 static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue)
214 {
215     DELIVER_REQUEST *request = state->request;
216     SMTP_SESSION *session = state->session;
217     DSN_BUF *why = state->why;
218     RECIPIENT *rcpt;
219     int     status;
220     int     aggregate_status;
221     int     soft_error = (STR(why->status)[0] == '4');
222     int     soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce);
223     int     nrcpt;
224 
225     /*
226      * Don't defer the recipients just yet when this error qualifies them for
227      * delivery to a backup server. Just log something informative to show
228      * why we're skipping this host.
229      */
230     if ((soft_error || soft_bounce_error)
231 	&& (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) {
232 	msg_info("%s: %s", request->queue_id, STR(why->reason));
233 	for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
234 	    rcpt = request->rcpt_list.info + nrcpt;
235 	    if (SMTP_RCPT_ISMARKED(rcpt))
236 		continue;
237 	    SMTP_RCPT_KEEP(state, rcpt);
238 	}
239     }
240 
241     /*
242      * Defer or bounce all the remaining recipients, and delete them from the
243      * delivery request. If a bounce fails, defer instead and do not qualify
244      * the recipient for delivery to a backup server.
245      */
246     else {
247 
248 	/*
249 	 * If we are still in the connection set-up phase, update the set-up
250 	 * completion time here, otherwise the time spent in set-up latency
251 	 * will be attributed as message transfer latency.
252 	 *
253 	 * All remaining recipients have failed at this point, so we update the
254 	 * delivery completion time stamp so that multiple recipient status
255 	 * records show the same delay values.
256 	 */
257 	if (request->msg_stats.conn_setup_done.tv_sec == 0) {
258 	    GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
259 	    request->msg_stats.deliver_done =
260 		request->msg_stats.conn_setup_done;
261 	} else
262 	    GETTIMEOFDAY(&request->msg_stats.deliver_done);
263 
264 	(void) DSN_FROM_DSN_BUF(why);
265 	aggregate_status = 0;
266 	for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
267 	    rcpt = request->rcpt_list.info + nrcpt;
268 	    if (SMTP_RCPT_ISMARKED(rcpt))
269 		continue;
270 	    status = (soft_error ? defer_append : bounce_append)
271 		(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
272 		 &request->msg_stats, rcpt,
273 		 session ? session->namaddrport : "none", &why->dsn);
274 	    if (status == 0)
275 		deliver_completed(state->src, rcpt->offset);
276 	    SMTP_RCPT_DROP(state, rcpt);
277 	    aggregate_status |= status;
278 	}
279 	state->status |= aggregate_status;
280 	if ((state->misc_flags & SMTP_MISC_FLAG_COMPLETE_SESSION) == 0
281 	    && throttle_queue && aggregate_status
282 	    && request->hop_status == 0)
283 	    request->hop_status = DSN_COPY(&why->dsn);
284     }
285 
286     /*
287      * Don't cache this session. We can't talk to this server.
288      */
289     if (throttle_queue && session)
290 	DONT_CACHE_THROTTLED_SESSION;
291 
292     return (-1);
293 }
294 
295 /* smtp_sess_fail - skip site, defer or bounce all recipients */
296 
smtp_sess_fail(SMTP_STATE * state)297 int     smtp_sess_fail(SMTP_STATE *state)
298 {
299 
300     /*
301      * We can't avoid copying copying lots of strings into VSTRING buffers,
302      * because this error information is collected by a routine that
303      * terminates BEFORE the error is reported.
304      */
305     return (smtp_bulk_fail(state, SMTP_THROTTLE));
306 }
307 
308 /* vsmtp_fill_dsn - fill in temporary DSN structure */
309 
vsmtp_fill_dsn(SMTP_STATE * state,const char * mta_name,const char * status,const char * reply,const char * format,va_list ap)310 static void vsmtp_fill_dsn(SMTP_STATE *state, const char *mta_name,
311 			           const char *status, const char *reply,
312 			           const char *format, va_list ap)
313 {
314     DSN_BUF *why = state->why;
315 
316     /*
317      * We could avoid copying lots of strings into VSTRING buffers, because
318      * this error information is given to us by a routine that terminates
319      * AFTER the error is reported. However, this results in ugly kludges
320      * when informal text needs to be formatted. So we maintain consistency
321      * with other error reporting in the SMTP client even if we waste a few
322      * cycles.
323      *
324      * Fix 20190621: don't cache an SMTP session after an SMTP protocol error.
325      * The protocol may be in a bad state. Disable caching here so that the
326      * protocol engine will send QUIT.
327      */
328     VSTRING_RESET(why->reason);
329     if (mta_name && status && status[0] != '4' && status[0] != '5') {
330 	SMTP_SESSION *session = state->session;
331 
332 	session->error_mask |= MAIL_ERROR_PROTOCOL;
333 	DONT_CACHE_THIS_SESSION;
334 	vstring_strcpy(why->reason, "Protocol error: ");
335 	status = "5.5.0";
336     }
337     vstring_vsprintf_append(why->reason, format, ap);
338     dsb_formal(why, status, DSB_DEF_ACTION,
339 	       mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, mta_name,
340 	       reply ? DSB_DTYPE_SMTP : DSB_DTYPE_NONE, reply);
341 }
342 
343 /* smtp_misc_fail - maybe throttle queue; skip/defer/bounce all recipients */
344 
smtp_misc_fail(SMTP_STATE * state,int throttle,const char * mta_name,SMTP_RESP * resp,const char * format,...)345 int     smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
346 		               SMTP_RESP *resp, const char *format,...)
347 {
348     va_list ap;
349 
350     /*
351      * Initialize.
352      */
353     va_start(ap, format);
354     vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap);
355     va_end(ap);
356 
357     if (state->session && mta_name)
358 	smtp_check_code(state->session, resp->code);
359 
360     /*
361      * Skip, defer or bounce recipients, and throttle this queue.
362      */
363     return (smtp_bulk_fail(state, throttle));
364 }
365 
366 /* smtp_rcpt_fail - skip, defer, or bounce recipient */
367 
smtp_rcpt_fail(SMTP_STATE * state,RECIPIENT * rcpt,const char * mta_name,SMTP_RESP * resp,const char * format,...)368 void    smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name,
369 		               SMTP_RESP *resp, const char *format,...)
370 {
371     DELIVER_REQUEST *request = state->request;
372     SMTP_SESSION *session = state->session;
373     DSN_BUF *why = state->why;
374     int     status;
375     int     soft_error;
376     int     soft_bounce_error;
377     va_list ap;
378 
379     /*
380      * Sanity check.
381      */
382     if (SMTP_RCPT_ISMARKED(rcpt))
383 	msg_panic("smtp_rcpt_fail: recipient <%s> is marked", rcpt->address);
384 
385     /*
386      * Initialize.
387      */
388     va_start(ap, format);
389     vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap);
390     va_end(ap);
391     soft_error = STR(why->status)[0] == '4';
392     soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce);
393 
394     if (state->session && mta_name)
395 	smtp_check_code(state->session, resp->code);
396 
397     /*
398      * Don't defer this recipient record just yet when this error qualifies
399      * for trying other mail servers. Just log something informative to show
400      * why we're skipping this recipient now.
401      */
402     if ((soft_error || soft_bounce_error)
403 	&& (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) {
404 	msg_info("%s: %s", request->queue_id, STR(why->reason));
405 	SMTP_RCPT_KEEP(state, rcpt);
406     }
407 
408     /*
409      * Defer or bounce this recipient, and delete from the delivery request.
410      * If the bounce fails, defer instead and do not qualify the recipient
411      * for delivery to a backup server.
412      *
413      * Note: we may still make an SMTP connection to deliver other recipients
414      * that did qualify for delivery to a backup server.
415      */
416     else {
417 	(void) DSN_FROM_DSN_BUF(state->why);
418 	status = (soft_error ? defer_append : bounce_append)
419 	    (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
420 	     &request->msg_stats, rcpt,
421 	     session ? session->namaddrport : "none", &why->dsn);
422 	if (status == 0)
423 	    deliver_completed(state->src, rcpt->offset);
424 	SMTP_RCPT_DROP(state, rcpt);
425 	state->status |= status;
426     }
427 }
428 
429 /* smtp_stream_except - defer domain after I/O problem */
430 
smtp_stream_except(SMTP_STATE * state,int code,const char * description)431 int     smtp_stream_except(SMTP_STATE *state, int code, const char *description)
432 {
433     SMTP_SESSION *session = state->session;
434     DSN_BUF *why = state->why;
435 
436     /*
437      * Sanity check.
438      */
439     if (session == 0)
440 	msg_panic("smtp_stream_except: no session");
441 
442     /*
443      * Initialize.
444      */
445     switch (code) {
446     default:
447 	msg_panic("smtp_stream_except: unknown exception %d", code);
448     case SMTP_ERR_EOF:
449 	dsb_simple(why, "4.4.2", "lost connection with %s while %s",
450 		   session->namaddr, description);
451 #ifdef USE_TLS
452 	if (PLAINTEXT_FALLBACK_OK_AFTER_TLS_SESSION_FAILURE)
453 	    RETRY_AS_PLAINTEXT;
454 #endif
455 	break;
456     case SMTP_ERR_TIME:
457 	dsb_simple(why, "4.4.2", "conversation with %s timed out while %s",
458 		   session->namaddr, description);
459 #ifdef USE_TLS
460 	if (PLAINTEXT_FALLBACK_OK_AFTER_TLS_SESSION_FAILURE)
461 	    RETRY_AS_PLAINTEXT;
462 #endif
463 	break;
464     case SMTP_ERR_DATA:
465 	session->error_mask |= MAIL_ERROR_DATA;
466 	dsb_simple(why, "4.3.0", "local data error while talking to %s",
467 		   session->namaddr);
468     }
469 
470     /*
471      * The smtp_bulk_fail() call below will not throttle the destination when
472      * falling back to plaintext, because RETRY_AS_PLAINTEXT clears the
473      * FINAL_SERVER flag.
474      */
475     return (smtp_bulk_fail(state, SMTP_THROTTLE));
476 }
477