Postfix3.3.1
bounce.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce 3
4 /* SUMMARY
5 /* bounce service client
6 /* SYNOPSIS
7 /* #include <bounce.h>
8 /*
9 /* int bounce_append(flags, id, stats, recipient, relay, dsn)
10 /* int flags;
11 /* const char *id;
12 /* MSG_STATS *stats;
13 /* RECIPIENT *rcpt;
14 /* const char *relay;
15 /* DSN *dsn;
16 /*
17 /* int bounce_flush(flags, queue, id, encoding, smtputf8, sender,
18 /* dsn_envid, dsn_ret)
19 /* int flags;
20 /* const char *queue;
21 /* const char *id;
22 /* const char *encoding;
23 /* int smtputf8;
24 /* const char *sender;
25 /* const char *dsn_envid;
26 /* int dsn_ret;
27 /*
28 /* int bounce_flush_verp(flags, queue, id, encoding, smtputf8,
29 /* sender, dsn_envid, dsn_ret, verp_delims)
30 /* int flags;
31 /* const char *queue;
32 /* const char *id;
33 /* const char *encoding;
34 /* int smtputf8;
35 /* const char *sender;
36 /* const char *dsn_envid;
37 /* int dsn_ret;
38 /* const char *verp_delims;
39 /*
40 /* int bounce_one(flags, queue, id, encoding, smtputf8, sender,
41 /* dsn_envid, ret, stats, recipient, relay, dsn)
42 /* int flags;
43 /* const char *queue;
44 /* const char *id;
45 /* const char *encoding;
46 /* int smtputf8;
47 /* const char *sender;
48 /* const char *dsn_envid;
49 /* int dsn_ret;
50 /* MSG_STATS *stats;
51 /* RECIPIENT *rcpt;
52 /* const char *relay;
53 /* DSN *dsn;
54 /*
55 /* void bounce_client_init(title, maps)
56 /* const char *title;
57 /* const char *maps;
58 /* INTERNAL API
59 /* DSN_FILTER *delivery_status_filter;
60 /*
61 /* int bounce_append_intern(flags, id, stats, recipient, relay, dsn)
62 /* int flags;
63 /* const char *id;
64 /* MSG_STATS *stats;
65 /* RECIPIENT *rcpt;
66 /* const char *relay;
67 /*
68 /* int bounce_one_intern(flags, queue, id, encoding, smtputf8, sender,
69 /* dsn_envid, ret, stats, recipient, relay, dsn)
70 /* int flags;
71 /* const char *queue;
72 /* const char *id;
73 /* const char *encoding;
74 /* int smtputf8;
75 /* const char *sender;
76 /* const char *dsn_envid;
77 /* int dsn_ret;
78 /* MSG_STATS *stats;
79 /* RECIPIENT *rcpt;
80 /* const char *relay;
81 /* DSN *dsn;
82 /* DESCRIPTION
83 /* This module implements the client interface to the message
84 /* bounce service, which maintains a per-message log of status
85 /* records with recipients that were bounced, and the dsn_text why.
86 /*
87 /* bounce_append() appends a dsn_text for non-delivery to the
88 /* bounce log for the named recipient, updates the address
89 /* verification service, or updates a message delivery record
90 /* on request by the sender. The flags argument determines
91 /* the action.
92 /*
93 /* bounce_flush() actually bounces the specified message to
94 /* the specified sender, including the bounce log that was
95 /* built with bounce_append(). The bounce logfile is removed
96 /* upon successful completion.
97 /*
98 /* bounce_flush_verp() is like bounce_flush(), but sends one
99 /* notification per recipient, with the failed recipient encoded
100 /* into the sender address.
101 /*
102 /* bounce_one() bounces one recipient and immediately sends a
103 /* notification to the sender. This procedure does not append
104 /* the recipient and dsn_text to the per-message bounce log, and
105 /* should be used when a delivery agent changes the error
106 /* return address in a manner that depends on the recipient
107 /* address.
108 /*
109 /* bounce_client_init() initializes an optional DSN filter.
110 /*
111 /* bounce_append_intern() and bounce_one_intern() are for use
112 /* after the DSN filter.
113 /*
114 /* Arguments:
115 /* .IP flags
116 /* The bitwise OR of zero or more of the following (specify
117 /* BOUNCE_FLAG_NONE to request no special processing):
118 /* .RS
119 /* .IP BOUNCE_FLAG_CLEAN
120 /* Delete the bounce log in case of an error (as in: pretend
121 /* that we never even tried to bounce this message).
122 /* .IP BOUNCE_FLAG_DELRCPT
123 /* When specified with a flush request, request that
124 /* recipients be deleted from the queue file.
125 /*
126 /* Note: the bounce daemon ignores this request when the
127 /* recipient queue file offset is <= 0.
128 /* .IP DEL_REQ_FLAG_MTA_VRFY
129 /* The message is an MTA-requested address verification probe.
130 /* Update the address verification database instead of bouncing
131 /* mail.
132 /* .IP DEL_REQ_FLAG_USR_VRFY
133 /* The message is a user-requested address expansion probe.
134 /* Update the message delivery record instead of bouncing mail.
135 /* .IP DEL_REQ_FLAG_RECORD
136 /* This is a normal message with logged delivery. Update the
137 /* message delivery record and bounce the mail.
138 /* .RE
139 /* .IP queue
140 /* The message queue name of the original message file.
141 /* .IP id
142 /* The message queue id if the original message file. The bounce log
143 /* file has the same name as the original message file.
144 /* .IP stats
145 /* Time stamps from different message delivery stages
146 /* and session reuse count.
147 /* .IP rcpt
148 /* Recipient information. See recipient_list(3).
149 /* .IP relay
150 /* Name of the host that the message could not be delivered to.
151 /* This information is used for syslogging only.
152 /* .IP encoding
153 /* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
154 /* .IP smtputf8
155 /* The level of SMTPUTF8 support (to be defined).
156 /* .IP sender
157 /* The sender envelope address.
158 /* .IP dsn_envid
159 /* Optional DSN envelope ID.
160 /* .IP dsn_ret
161 /* Optional DSN return full/headers option.
162 /* .IP dsn
163 /* Delivery status. See dsn(3). The specified action is ignored.
164 /* .IP verp_delims
165 /* VERP delimiter characters, used when encoding the failed
166 /* sender into the envelope sender address.
167 /* DIAGNOSTICS
168 /* In case of success, these functions log the action, and return a
169 /* zero value. Otherwise, the functions return a non-zero result,
170 /* and when BOUNCE_FLAG_CLEAN is disabled, log that message
171 /* delivery is deferred.
172 /* .IP title
173 /* The origin of the optional DSN filter lookup table names.
174 /* .IP maps
175 /* The optional "type:table" DSN filter lookup table names,
176 /* separated by comma or whitespace.
177 /* BUGS
178 /* Should be replaced by routines with an attribute-value based
179 /* interface instead of an interface that uses a rigid argument list.
180 /* LICENSE
181 /* .ad
182 /* .fi
183 /* The Secure Mailer license must be distributed with this software.
184 /* AUTHOR(S)
185 /* Wietse Venema
186 /* IBM T.J. Watson Research
187 /* P.O. Box 704
188 /* Yorktown Heights, NY 10598, USA
189 /*--*/
190 
191 /* System library. */
192 
193 #include <sys_defs.h>
194 #include <string.h>
195 
196 /* Utility library. */
197 
198 #include <msg.h>
199 #include <vstring.h>
200 #include <mymalloc.h>
201 
202 /* Global library. */
203 
204 #define DSN_INTERN
205 #include <mail_params.h>
206 #include <mail_proto.h>
207 #include <log_adhoc.h>
208 #include <dsn_util.h>
209 #include <rcpt_print.h>
210 #include <dsn_print.h>
211 #include <verify.h>
212 #include <defer.h>
213 #include <trace.h>
214 #include <bounce.h>
215 
216 /* Shared internally, between bounce and defer clients. */
217 
219 
220 /* bounce_append - append delivery status to per-message bounce log */
221 
222 int bounce_append(int flags, const char *id, MSG_STATS *stats,
223  RECIPIENT *rcpt, const char *relay,
224  DSN *dsn)
225 {
226  DSN my_dsn = *dsn;
227  DSN *dsn_res;
228 
229  /*
230  * Sanity check. If we're really confident, change this into msg_panic
231  * (remember, this information may be under control by a hostile server).
232  */
233  if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) {
234  msg_warn("bounce_append: ignoring dsn code \"%s\"", my_dsn.status);
235  my_dsn.status = "5.0.0";
236  }
237 
238  /*
239  * DSN filter (Postfix 3.0).
240  */
241  if (delivery_status_filter != 0
242  && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) {
243  if (dsn_res->status[0] == '4')
244  return (defer_append_intern(flags, id, stats, rcpt, relay, dsn_res));
245  my_dsn = *dsn_res;
246  }
247  return (bounce_append_intern(flags, id, stats, rcpt, relay, &my_dsn));
248 }
249 
250 /* bounce_append_intern - append delivery status to per-message bounce log */
251 
252 int bounce_append_intern(int flags, const char *id, MSG_STATS *stats,
253  RECIPIENT *rcpt, const char *relay,
254  DSN *dsn)
255 {
256  DSN my_dsn = *dsn;
257  int status;
258 
259  /*
260  * MTA-requested address verification information is stored in the verify
261  * service database.
262  */
263  if (flags & DEL_REQ_FLAG_MTA_VRFY) {
264  my_dsn.action = "undeliverable";
265  status = verify_append(id, stats, rcpt, relay, &my_dsn,
267  return (status);
268  }
269 
270  /*
271  * User-requested address verification information is logged and mailed
272  * to the requesting user.
273  */
274  if (flags & DEL_REQ_FLAG_USR_VRFY) {
275  my_dsn.action = "undeliverable";
276  status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
277  return (status);
278  }
279 
280  /*
281  * Normal (well almost) delivery. When we're pretending that we can't
282  * bounce, don't create a defer log file when we wouldn't keep the bounce
283  * log file. That's a lot of negatives in one sentence.
284  */
285  else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) {
286  return (-1);
287  }
288 
289  /*
290  * Normal mail delivery. May also send a delivery record to the user.
291  *
292  * XXX DSN We write all recipients to the bounce logfile regardless of DSN
293  * NOTIFY options, because those options don't apply to postmaster
294  * notifications.
295  */
296  else {
297  char *my_status = mystrdup(my_dsn.status);
298  const char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced";
299 
300  /*
301  * Supply default action.
302  */
303  my_dsn.status = my_status;
304  if (var_soft_bounce) {
305  my_status[0] = '4';
306  my_dsn.action = "delayed";
307  } else {
308  my_dsn.action = "failed";
309  }
310 
316  SEND_ATTR_FUNC(rcpt_print, (void *) rcpt),
317  SEND_ATTR_FUNC(dsn_print, (void *) &my_dsn),
318  ATTR_TYPE_END) == 0
319  && ((flags & DEL_REQ_FLAG_RECORD) == 0
320  || trace_append(flags, id, stats, rcpt, relay,
321  &my_dsn) == 0)) {
322  log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status);
323  status = (var_soft_bounce ? -1 : 0);
324  } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
325  VSTRING *junk = vstring_alloc(100);
326 
327  my_dsn.status = "4.3.0";
328  vstring_sprintf(junk, "%s or %s service failure",
329  var_bounce_service, var_trace_service);
330  my_dsn.reason = vstring_str(junk);
331  status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn);
332  vstring_free(junk);
333  } else {
334  status = -1;
335  }
336  myfree(my_status);
337  return (status);
338  }
339 }
340 
341 /* bounce_flush - flush the bounce log and deliver to the sender */
342 
343 int bounce_flush(int flags, const char *queue, const char *id,
344  const char *encoding, int smtputf8,
345  const char *sender, const char *dsn_envid,
346  int dsn_ret)
347 {
348 
349  /*
350  * When we're pretending that we can't bounce, don't send a bounce
351  * message.
352  */
353  if (var_soft_bounce)
354  return (-1);
365  ATTR_TYPE_END) == 0) {
366  return (0);
367  } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
368  msg_info("%s: status=deferred (bounce failed)", id);
369  return (-1);
370  } else {
371  return (-1);
372  }
373 }
374 
375 /* bounce_flush_verp - verpified notification */
376 
377 int bounce_flush_verp(int flags, const char *queue, const char *id,
378  const char *encoding, int smtputf8,
379  const char *sender, const char *dsn_envid,
380  int dsn_ret, const char *verp_delims)
381 {
382 
383  /*
384  * When we're pretending that we can't bounce, don't send a bounce
385  * message.
386  */
387  if (var_soft_bounce)
388  return (-1);
399  SEND_ATTR_STR(MAIL_ATTR_VERPDL, verp_delims),
400  ATTR_TYPE_END) == 0) {
401  return (0);
402  } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
403  msg_info("%s: status=deferred (bounce failed)", id);
404  return (-1);
405  } else {
406  return (-1);
407  }
408 }
409 
410 /* bounce_one - send notice for one recipient */
411 
412 int bounce_one(int flags, const char *queue, const char *id,
413  const char *encoding, int smtputf8,
414  const char *sender, const char *dsn_envid,
415  int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt,
416  const char *relay, DSN *dsn)
417 {
418  DSN my_dsn = *dsn;
419  DSN *dsn_res;
420 
421  /*
422  * Sanity check.
423  */
424  if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) {
425  msg_warn("bounce_one: ignoring dsn code \"%s\"", my_dsn.status);
426  my_dsn.status = "5.0.0";
427  }
428 
429  /*
430  * DSN filter (Postfix 3.0).
431  */
432  if (delivery_status_filter != 0
433  && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) {
434  if (dsn_res->status[0] == '4')
435  return (defer_append_intern(flags, id, stats, rcpt, relay, dsn_res));
436  my_dsn = *dsn_res;
437  }
438  return (bounce_one_intern(flags, queue, id, encoding, smtputf8, sender,
439  dsn_envid, dsn_ret, stats, rcpt, relay, &my_dsn));
440 }
441 
442 /* bounce_one_intern - send notice for one recipient */
443 
444 int bounce_one_intern(int flags, const char *queue, const char *id,
445  const char *encoding, int smtputf8,
446  const char *sender, const char *dsn_envid,
447  int dsn_ret, MSG_STATS *stats,
448  RECIPIENT *rcpt, const char *relay,
449  DSN *dsn)
450 {
451  DSN my_dsn = *dsn;
452  int status;
453 
454  /*
455  * MTA-requested address verification information is stored in the verify
456  * service database.
457  */
458  if (flags & DEL_REQ_FLAG_MTA_VRFY) {
459  my_dsn.action = "undeliverable";
460  status = verify_append(id, stats, rcpt, relay, &my_dsn,
462  return (status);
463  }
464 
465  /*
466  * User-requested address verification information is logged and mailed
467  * to the requesting user.
468  */
469  if (flags & DEL_REQ_FLAG_USR_VRFY) {
470  my_dsn.action = "undeliverable";
471  status = trace_append(flags, id, stats, rcpt, relay, &my_dsn);
472  return (status);
473  }
474 
475  /*
476  * When we're not bouncing, then use the standard multi-recipient logfile
477  * based procedure.
478  */
479  else if (var_soft_bounce) {
480  return (bounce_append_intern(flags, id, stats, rcpt, relay, &my_dsn));
481  }
482 
483  /*
484  * Normal mail delivery. May also send a delivery record to the user.
485  *
486  * XXX DSN We send all recipients regardless of DSN NOTIFY options, because
487  * those options don't apply to postmaster notifications.
488  */
489  else {
490 
491  /*
492  * Supply default action.
493  */
494  my_dsn.action = "failed";
495 
506  SEND_ATTR_FUNC(rcpt_print, (void *) rcpt),
507  SEND_ATTR_FUNC(dsn_print, (void *) &my_dsn),
508  ATTR_TYPE_END) == 0
509  && ((flags & DEL_REQ_FLAG_RECORD) == 0
510  || trace_append(flags, id, stats, rcpt, relay,
511  &my_dsn) == 0)) {
512  log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced");
513  status = 0;
514  } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) {
515  VSTRING *junk = vstring_alloc(100);
516 
517  my_dsn.status = "4.3.0";
518  vstring_sprintf(junk, "%s or %s service failure",
520  my_dsn.reason = vstring_str(junk);
521  status = defer_append_intern(flags, id, stats, rcpt, relay, &my_dsn);
522  vstring_free(junk);
523  } else {
524  status = -1;
525  }
526  return (status);
527  }
528 }
529 
530 /* bounce_client_init - initialize bounce/defer DSN filter */
531 
532 void bounce_client_init(const char *title, const char *maps)
533 {
534  static const char myname[] = "bounce_client_init";
535 
536  if (delivery_status_filter != 0)
537  msg_panic("%s: duplicate initialization", myname);
538  if (*maps)
539  delivery_status_filter = dsn_filter_create(title, maps);
540 }
int dsn_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, int flags, void *ptr)
Definition: dsn_print.c:48
DSN_FILTER * delivery_status_filter
Definition: bounce.c:218
void myfree(void *ptr)
Definition: mymalloc.c:207
size_t dsn_valid(const char *text)
Definition: dsn_util.c:112
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
int var_soft_bounce
Definition: mail_params.c:281
const char * action
Definition: dsn.h:19
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
const char * reason
Definition: dsn.h:20
#define vstring_str(vp)
Definition: vstring.h:71
int trace_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: trace.c:106
#define BOUNCE_CMD_ONE
Definition: bounce.h:47
#define ATTR_TYPE_END
Definition: attr.h:39
#define DEL_REQ_FLAG_USR_VRFY
#define DEL_RCPT_STAT_BOUNCE
#define BOUNCE_FLAG_CLEAN
Definition: bounce.h:61
DSN_FILTER * dsn_filter_create(const char *title, const char *map_names)
Definition: dsn_filter.c:107
int bounce_append(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:222
#define BOUNCE_CMD_APPEND
Definition: bounce.h:43
int bounce_one(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:412
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
int bounce_append_intern(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:252
int verify_append(const char *queue_id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn, int vrfy_stat)
Definition: verify.c:92
#define MAIL_ATTR_NREQ
Definition: mail_proto.h:125
char * var_trace_service
Definition: mail_params.c:311
#define MAIL_ATTR_SMTPUTF8
Definition: mail_proto.h:277
int bounce_flush(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret)
Definition: bounce.c:343
#define BOUNCE_CMD_VERP
Definition: bounce.h:46
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_DSN_RET
Definition: mail_proto.h:274
char * var_bounce_service
Definition: mail_params.c:301
char * var_defer_service
Definition: mail_params.c:303
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
int mail_command_client(const char *class, const char *name,...)
#define MAIL_ATTR_DSN_ENVID
Definition: mail_proto.h:273
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
int defer_append_intern(int flags, const char *id, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: defer.c:216
void log_adhoc(const char *id, MSG_STATS *stats, RECIPIENT *recipient, const char *relay, DSN *dsn, const char *status)
Definition: log_adhoc.c:82
const char * status
Definition: dsn.h:18
void bounce_client_init(const char *title, const char *maps)
Definition: bounce.c:532
int bounce_flush_verp(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, const char *verp_delims)
Definition: bounce.c:377
#define SEND_ATTR_FUNC(func, val)
Definition: attr.h:69
int bounce_one_intern(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, const char *relay, DSN *dsn)
Definition: bounce.c:444
Definition: dsn.h:17
#define BOUNCE_CMD_FLUSH
Definition: bounce.h:44
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
int rcpt_print(ATTR_PRINT_MASTER_FN print_fn, VSTREAM *fp, int flags, void *ptr)
Definition: rcpt_print.c:51
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
#define MAIL_ATTR_VERPDL
Definition: mail_proto.h:136
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
#define DEL_REQ_FLAG_MTA_VRFY
#define DEL_REQ_FLAG_RECORD
void msg_info(const char *fmt,...)
Definition: msg.c:199
DSN * dsn_filter_lookup(DSN_FILTER *fp, DSN *dsn)
Definition: dsn_filter.c:123