Postfix3.3.1
smtp_trouble.c
[詳解]
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 
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  if (code < 400 || code > 599
200  || code == 555 /* RFC 1869, section 6.1. */
201  || (code >= 500 && code < 510))
202  session->error_mask |= MAIL_ERROR_PROTOCOL;
203 }
204 
205 /* smtp_bulk_fail - skip, defer or bounce recipients, maybe throttle queue */
206 
207 static int smtp_bulk_fail(SMTP_STATE *state, int throttle_queue)
208 {
209  DELIVER_REQUEST *request = state->request;
210  SMTP_SESSION *session = state->session;
211  DSN_BUF *why = state->why;
212  RECIPIENT *rcpt;
213  int status;
214  int aggregate_status;
215  int soft_error = (STR(why->status)[0] == '4');
216  int soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce);
217  int nrcpt;
218 
219  /*
220  * Don't defer the recipients just yet when this error qualifies them for
221  * delivery to a backup server. Just log something informative to show
222  * why we're skipping this host.
223  */
224  if ((soft_error || soft_bounce_error)
225  && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) {
226  msg_info("%s: %s", request->queue_id, STR(why->reason));
227  for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
228  rcpt = request->rcpt_list.info + nrcpt;
229  if (SMTP_RCPT_ISMARKED(rcpt))
230  continue;
231  SMTP_RCPT_KEEP(state, rcpt);
232  }
233  }
234 
235  /*
236  * Defer or bounce all the remaining recipients, and delete them from the
237  * delivery request. If a bounce fails, defer instead and do not qualify
238  * the recipient for delivery to a backup server.
239  */
240  else {
241 
242  /*
243  * If we are still in the connection set-up phase, update the set-up
244  * completion time here, otherwise the time spent in set-up latency
245  * will be attributed as message transfer latency.
246  *
247  * All remaining recipients have failed at this point, so we update the
248  * delivery completion time stamp so that multiple recipient status
249  * records show the same delay values.
250  */
251  if (request->msg_stats.conn_setup_done.tv_sec == 0) {
252  GETTIMEOFDAY(&request->msg_stats.conn_setup_done);
253  request->msg_stats.deliver_done =
254  request->msg_stats.conn_setup_done;
255  } else
256  GETTIMEOFDAY(&request->msg_stats.deliver_done);
257 
258  (void) DSN_FROM_DSN_BUF(why);
259  aggregate_status = 0;
260  for (nrcpt = 0; nrcpt < SMTP_RCPT_LEFT(state); nrcpt++) {
261  rcpt = request->rcpt_list.info + nrcpt;
262  if (SMTP_RCPT_ISMARKED(rcpt))
263  continue;
264  status = (soft_error ? defer_append : bounce_append)
265  (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
266  &request->msg_stats, rcpt,
267  session ? session->namaddrport : "none", &why->dsn);
268  if (status == 0)
269  deliver_completed(state->src, rcpt->offset);
270  SMTP_RCPT_DROP(state, rcpt);
271  aggregate_status |= status;
272  }
273  state->status |= aggregate_status;
274  if ((state->misc_flags & SMTP_MISC_FLAG_COMPLETE_SESSION) == 0
275  && throttle_queue && aggregate_status
276  && request->hop_status == 0)
277  request->hop_status = DSN_COPY(&why->dsn);
278  }
279 
280  /*
281  * Don't cache this session. We can't talk to this server.
282  */
283  if (throttle_queue && session)
285 
286  return (-1);
287 }
288 
289 /* smtp_sess_fail - skip site, defer or bounce all recipients */
290 
292 {
293 
294  /*
295  * We can't avoid copying copying lots of strings into VSTRING buffers,
296  * because this error information is collected by a routine that
297  * terminates BEFORE the error is reported.
298  */
299  return (smtp_bulk_fail(state, SMTP_THROTTLE));
300 }
301 
302 /* vsmtp_fill_dsn - fill in temporary DSN structure */
303 
304 static void vsmtp_fill_dsn(SMTP_STATE *state, const char *mta_name,
305  const char *status, const char *reply,
306  const char *format, va_list ap)
307 {
308  DSN_BUF *why = state->why;
309 
310  /*
311  * We could avoid copying lots of strings into VSTRING buffers, because
312  * this error information is given to us by a routine that terminates
313  * AFTER the error is reported. However, this results in ugly kludges
314  * when informal text needs to be formatted. So we maintain consistency
315  * with other error reporting in the SMTP client even if we waste a few
316  * cycles.
317  */
318  VSTRING_RESET(why->reason);
319  if (mta_name && status && status[0] != '4' && status[0] != '5') {
320  vstring_strcpy(why->reason, "Protocol error: ");
321  status = "5.5.0";
322  }
323  vstring_vsprintf_append(why->reason, format, ap);
324  dsb_formal(why, status, DSB_DEF_ACTION,
325  mta_name ? DSB_MTYPE_DNS : DSB_MTYPE_NONE, mta_name,
326  reply ? DSB_DTYPE_SMTP : DSB_DTYPE_NONE, reply);
327 }
328 
329 /* smtp_misc_fail - maybe throttle queue; skip/defer/bounce all recipients */
330 
331 int smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name,
332  SMTP_RESP *resp, const char *format,...)
333 {
334  va_list ap;
335 
336  /*
337  * Initialize.
338  */
339  va_start(ap, format);
340  vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap);
341  va_end(ap);
342 
343  if (state->session && mta_name)
344  smtp_check_code(state->session, resp->code);
345 
346  /*
347  * Skip, defer or bounce recipients, and throttle this queue.
348  */
349  return (smtp_bulk_fail(state, throttle));
350 }
351 
352 /* smtp_rcpt_fail - skip, defer, or bounce recipient */
353 
354 void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name,
355  SMTP_RESP *resp, const char *format,...)
356 {
357  DELIVER_REQUEST *request = state->request;
358  SMTP_SESSION *session = state->session;
359  DSN_BUF *why = state->why;
360  int status;
361  int soft_error;
362  int soft_bounce_error;
363  va_list ap;
364 
365  /*
366  * Sanity check.
367  */
368  if (SMTP_RCPT_ISMARKED(rcpt))
369  msg_panic("smtp_rcpt_fail: recipient <%s> is marked", rcpt->address);
370 
371  /*
372  * Initialize.
373  */
374  va_start(ap, format);
375  vsmtp_fill_dsn(state, mta_name, resp->dsn, resp->str, format, ap);
376  va_end(ap);
377  soft_error = STR(why->status)[0] == '4';
378  soft_bounce_error = (STR(why->status)[0] == '5' && var_soft_bounce);
379 
380  if (state->session && mta_name)
381  smtp_check_code(state->session, resp->code);
382 
383  /*
384  * Don't defer this recipient record just yet when this error qualifies
385  * for trying other mail servers. Just log something informative to show
386  * why we're skipping this recipient now.
387  */
388  if ((soft_error || soft_bounce_error)
389  && (state->misc_flags & SMTP_MISC_FLAG_FINAL_SERVER) == 0) {
390  msg_info("%s: %s", request->queue_id, STR(why->reason));
391  SMTP_RCPT_KEEP(state, rcpt);
392  }
393 
394  /*
395  * Defer or bounce this recipient, and delete from the delivery request.
396  * If the bounce fails, defer instead and do not qualify the recipient
397  * for delivery to a backup server.
398  *
399  * Note: we may still make an SMTP connection to deliver other recipients
400  * that did qualify for delivery to a backup server.
401  */
402  else {
403  (void) DSN_FROM_DSN_BUF(state->why);
404  status = (soft_error ? defer_append : bounce_append)
405  (DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
406  &request->msg_stats, rcpt,
407  session ? session->namaddrport : "none", &why->dsn);
408  if (status == 0)
409  deliver_completed(state->src, rcpt->offset);
410  SMTP_RCPT_DROP(state, rcpt);
411  state->status |= status;
412  }
413 }
414 
415 /* smtp_stream_except - defer domain after I/O problem */
416 
417 int smtp_stream_except(SMTP_STATE *state, int code, const char *description)
418 {
419  SMTP_SESSION *session = state->session;
420  DSN_BUF *why = state->why;
421 
422  /*
423  * Sanity check.
424  */
425  if (session == 0)
426  msg_panic("smtp_stream_except: no session");
427 
428  /*
429  * Initialize.
430  */
431  switch (code) {
432  default:
433  msg_panic("smtp_stream_except: unknown exception %d", code);
434  case SMTP_ERR_EOF:
435  dsb_simple(why, "4.4.2", "lost connection with %s while %s",
436  session->namaddr, description);
437 #ifdef USE_TLS
440 #endif
441  break;
442  case SMTP_ERR_TIME:
443  dsb_simple(why, "4.4.2", "conversation with %s timed out while %s",
444  session->namaddr, description);
445 #ifdef USE_TLS
448 #endif
449  break;
450  case SMTP_ERR_DATA:
451  session->error_mask |= MAIL_ERROR_DATA;
452  dsb_simple(why, "4.3.0", "local data error while talking to %s",
453  session->namaddr);
454  }
455 
456  /*
457  * The smtp_bulk_fail() call below will not throttle the destination when
458  * falling back to plaintext, because RETRY_AS_PLAINTEXT clears the
459  * FINAL_SERVER flag.
460  */
461  return (smtp_bulk_fail(state, SMTP_THROTTLE));
462 }
#define DSB_DEF_ACTION
Definition: dsn_buf.h:40
int status
Definition: smtp.h:148
char * str
Definition: smtp.h:500
RECIPIENT_LIST rcpt_list
struct SMTP_SESSION * session
Definition: smtp.h:147
#define MAIL_ERROR_DATA
Definition: mail_error.h:29
VSTREAM * src
Definition: smtp.h:144
DSN_BUF * why
Definition: smtp.h:184
const char * address
int var_soft_bounce
Definition: mail_params.c:281
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
const char * dsn
Definition: smtp.h:499
#define SMTP_ERR_TIME
Definition: smtp_stream.h:31
#define PLAINTEXT_FALLBACK_OK_AFTER_TLS_SESSION_FAILURE
Definition: smtp.h:477
void deliver_completed(VSTREAM *stream, long offset)
DELIVER_REQUEST * request
Definition: smtp.h:146
DSN dsn
Definition: dsn_buf.h:28
int misc_flags
Definition: smtp.h:143
#define DSN_COPY(dsn)
Definition: dsn.h:68
#define RETRY_AS_PLAINTEXT
Definition: smtp.h:489
#define DEL_REQ_TRACE_FLAGS(f)
MSG_STATS msg_stats
int error_mask
Definition: smtp.h:320
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
int bounce_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:222
#define DSB_MTYPE_DNS
Definition: dsn_buf.h:44
#define DSB_DTYPE_SMTP
Definition: dsn_buf.h:48
struct timeval conn_setup_done
Definition: msg_stats.h:59
#define SMTP_ERR_EOF
Definition: smtp_stream.h:30
#define SMTP_MISC_FLAG_COMPLETE_SESSION
Definition: smtp.h:248
int smtp_misc_fail(SMTP_STATE *state, int throttle, const char *mta_name, SMTP_RESP *resp, const char *format,...)
Definition: smtp_trouble.c:331
#define DSN_FROM_DSN_BUF(dsb)
Definition: dsn_buf.h:68
int smtp_sess_fail(SMTP_STATE *state)
Definition: smtp_trouble.c:291
#define VSTRING_RESET(vp)
Definition: vstring.h:77
#define STR(x)
Definition: anvil.c:518
#define SMTP_RCPT_ISMARKED(rcpt)
Definition: smtp.h:559
#define SMTP_MISC_FLAG_FINAL_SERVER
Definition: smtp.h:245
#define SMTP_RCPT_DROP(state, rcpt)
Definition: smtp.h:551
#define DONT_CACHE_THROTTLED_SESSION
Definition: smtp.h:440
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
int smtp_stream_except(SMTP_STATE *state, int code, const char *description)
Definition: smtp_trouble.c:417
#define DSB_DTYPE_NONE
Definition: dsn_buf.h:47
#define SMTP_RCPT_KEEP(state, rcpt)
Definition: smtp.h:555
#define SMTP_RCPT_LEFT(state)
Definition: smtp.h:561
VSTRING * reason
Definition: dsn_buf.h:37
VSTRING * vstring_vsprintf_append(VSTRING *vp, const char *format, va_list ap)
Definition: vstring.c:636
#define MAIL_ERROR_PROTOCOL
Definition: mail_error.h:23
#define SMTP_ERR_DATA
Definition: smtp_stream.h:34
DSN_BUF * dsb_formal(DSN_BUF *dsb, const char *status, const char *action, const char *mtype, const char *mname, const char *dtype, const char *dtext)
Definition: dsn_buf.c:307
RECIPIENT * info
int code
Definition: smtp.h:498
char * namaddr
Definition: smtp.h:307
#define SMTP_THROTTLE
Definition: smtp.h:571
int defer_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:187
void smtp_rcpt_fail(SMTP_STATE *state, RECIPIENT *rcpt, const char *mta_name, SMTP_RESP *resp, const char *format,...)
Definition: smtp_trouble.c:354
struct timeval deliver_done
Definition: msg_stats.h:60
#define DSB_MTYPE_NONE
Definition: dsn_buf.h:43
VSTRING * status
Definition: dsn_buf.h:30
char * namaddrport
Definition: smtp.h:310
void msg_info(const char *fmt,...)
Definition: msg.c:199