Postfix3.3.1
bounce_notify_service.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_notify_service 3
4 /* SUMMARY
5 /* send non-delivery report to sender, server side
6 /* SYNOPSIS
7 /* #include "bounce_service.h"
8 /*
9 /* int bounce_notify_service(flags, service, queue_name, queue_id,
10 /* encoding, smtputf8, sender, dsn_envid,
11 /* dsn_ret, templates)
12 /* int flags;
13 /* char *service;
14 /* char *queue_name;
15 /* char *queue_id;
16 /* char *encoding;
17 /* int smtputf8;
18 /* char *sender;
19 /* char *dsn_envid;
20 /* int dsn_ret;
21 /* BOUNCE_TEMPLATES *templates;
22 /* DESCRIPTION
23 /* This module implements the server side of the bounce_flush()
24 /* (send bounce message) request.
25 /*
26 /* When a message bounces, a full copy is sent to the originator,
27 /* and an optional copy of the diagnostics with message headers is
28 /* sent to the postmaster. The result is non-zero when the operation
29 /* should be tried again. Otherwise, the logfile is removed.
30 /*
31 /* When a bounce is sent, the sender address is the empty
32 /* address. When a bounce bounces, an optional double bounce
33 /* with the entire undeliverable mail is sent to the postmaster,
34 /* with as sender address the double bounce address.
35 /* DIAGNOSTICS
36 /* Fatal error: error opening existing file.
37 /* BUGS
38 /* SEE ALSO
39 /* bounce(3) basic bounce service client interface
40 /* LICENSE
41 /* .ad
42 /* .fi
43 /* The Secure Mailer license must be distributed with this software.
44 /* AUTHOR(S)
45 /* Wietse Venema
46 /* IBM T.J. Watson Research
47 /* P.O. Box 704
48 /* Yorktown Heights, NY 10598, USA
49 /*--*/
50 
51 /* System library. */
52 
53 #include <sys_defs.h>
54 #include <fcntl.h>
55 #include <errno.h>
56 #include <string.h>
57 #include <ctype.h>
58 
59 /* Utility library. */
60 
61 #include <msg.h>
62 #include <vstream.h>
63 #include <name_mask.h>
64 #include <stringops.h>
65 
66 /* Global library. */
67 
68 #include <mail_params.h>
69 #include <mail_queue.h>
70 #include <post_mail.h>
71 #include <mail_addr.h>
72 #include <mail_error.h>
73 #include <bounce.h>
74 #include <dsn_mask.h>
75 #include <rec_type.h>
76 
77 /* Application-specific. */
78 
79 #include "bounce_service.h"
80 
81 #define STR vstring_str
82 
83 /* bounce_notify_service - send a bounce */
84 
85 int bounce_notify_service(int flags, char *service, char *queue_name,
86  char *queue_id, char *encoding,
87  int smtputf8, char *recipient,
88  char *dsn_envid, int dsn_ret,
89  BOUNCE_TEMPLATES *ts)
90 {
91  BOUNCE_INFO *bounce_info;
92  int bounce_status = 1;
93  int postmaster_status = 1;
94  VSTREAM *bounce;
97  VSTRING *new_id = vstring_alloc(10);
98  char *postmaster;
99  int count;
100 
101  /*
102  * Initialize. Open queue file, bounce log, etc.
103  *
104  * XXX DSN The bounce service produces RFC 3464-style "failed mail" reports
105  * from information in two following types of logfile:
106  *
107  * 1 - bounce: this file is used for RFC 3464-style reports of permanent
108  * delivery errors by the bounce(8) service. This reports to the sender
109  * all recipients that have no DSN NOTIFY information (compatibility) and
110  * all recipients that have DSN NOTIFY=FAILURE; this reports to
111  * postmaster all recipients, if postmaster notification is enabled.
112  *
113  * 2 - defer: this file is used for three types of report:
114  *
115  * 2a) RFC 3464-style "mail is too old" reports by the bounce(8) service.
116  * This reports to the sender all recipients that have no DSN NOTIFY
117  * information (compatibility) and all recipients that have DSN
118  * NOTIFY=FAILURE; this reports to postmaster all recipients, if
119  * postmaster notification is enabled.
120  *
121  * Other reports that other servers produce from the defer logfile:
122  *
123  * 2b) On-demand reports of all delayed deliveries by the showq(8) service
124  * and mailq(1) command. This reports all recipients that have a
125  * transient delivery error.
126  *
127  * 2c) RFC 3464-style "delayed mail" notifications by the defer(8) service.
128  * This reports to the sender all recipients that have no DSN NOTIFY
129  * information (compatibility) and all recipients that have DSN
130  * NOTIFY=DELAY; this reports to postmaster all recipients, if postmaster
131  * notification is enabled.
132  */
133  bounce_info = bounce_mail_init(service, queue_name, queue_id,
134  encoding, smtputf8, dsn_envid,
135  ts->failure);
136 
137 #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
138 #define NULL_TRACE_FLAGS 0
139 
140  /*
141  * The choice of sender address depends on the recipient address. For a
142  * single bounce (a non-delivery notification to the message originator),
143  * the sender address is the empty string. For a double bounce (typically
144  * a failed single bounce, or a postmaster notification that was produced
145  * by any of the mail processes) the sender address is defined by the
146  * var_double_bounce_sender configuration variable. When a double bounce
147  * cannot be delivered, the queue manager blackholes the resulting triple
148  * bounce message.
149  */
150 
151  /*
152  * Double bounce failed. Never send a triple bounce.
153  *
154  * However, this does not prevent double bounces from bouncing on other
155  * systems. In order to cope with this, either the queue manager must
156  * recognize the double-bounce recipient address and discard mail, or
157  * every delivery agent must recognize the double-bounce sender address
158  * and substitute something else so mail does not come back at us.
159  */
160  if (strcasecmp_utf8(recipient, mail_addr_double_bounce()) == 0) {
161  msg_warn("%s: undeliverable postmaster notification discarded",
162  queue_id);
163  bounce_status = 0;
164  }
165 
166  /*
167  * Single bounce failed. Optionally send a double bounce to postmaster,
168  * subject to notify_classes restrictions.
169  */
170 #define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
171 #define SEND_POSTMASTER_ANY_BOUNCE_NOTICE (notify_mask & ANY_BOUNCE)
172 
173  else if (*recipient == 0) {
175  bounce_status = 0;
176  } else {
177  postmaster = var_2bounce_rcpt;
179  postmaster,
182  smtputf8,
183  new_id)) != 0) {
184 
185  /*
186  * Double bounce to Postmaster. This is the last opportunity
187  * for this message to be delivered. Send the text with
188  * reason for the bounce, and the headers of the original
189  * message. Don't bother sending the boiler-plate text.
190  */
191  count = -1;
192  if (bounce_header(bounce, bounce_info, postmaster,
193  POSTMASTER_COPY) == 0
194  && (count = bounce_diagnostic_log(bounce, bounce_info,
195  DSN_NOTIFY_OVERRIDE)) > 0
196  && bounce_header_dsn(bounce, bounce_info) == 0
197  && bounce_diagnostic_dsn(bounce, bounce_info,
198  DSN_NOTIFY_OVERRIDE) > 0) {
199  bounce_original(bounce, bounce_info, DSN_RET_FULL);
200  bounce_status = post_mail_fclose(bounce);
201  if (bounce_status == 0)
202  msg_info("%s: postmaster non-delivery notification: %s",
203  queue_id, STR(new_id));
204  } else {
205  /* No applicable recipients found - cancel this notice. */
206  (void) vstream_fclose(bounce);
207  if (count == 0)
208  bounce_status = 0;
209  }
210  }
211  }
212  }
213 
214  /*
215  * Non-bounce failed. Send a single bounce to the sender, subject to DSN
216  * NOTIFY restrictions.
217  */
218  else {
219  if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient,
222  smtputf8,
223  new_id)) != 0) {
224 
225  /*
226  * Send the bounce message header, some boilerplate text that
227  * pretends that we are a polite mail system, the text with
228  * reason for the bounce, and a copy of the original message.
229  */
230  count = -1;
231  if (bounce_header(bounce, bounce_info, recipient,
232  NO_POSTMASTER_COPY) == 0
233  && bounce_boilerplate(bounce, bounce_info) == 0
234  && (count = bounce_diagnostic_log(bounce, bounce_info,
235  DSN_NOTIFY_FAILURE)) > 0
236  && bounce_header_dsn(bounce, bounce_info) == 0
237  && bounce_diagnostic_dsn(bounce, bounce_info,
238  DSN_NOTIFY_FAILURE) > 0) {
239  bounce_original(bounce, bounce_info, dsn_ret ?
240  dsn_ret : DSN_RET_FULL);
241  bounce_status = post_mail_fclose(bounce);
242  if (bounce_status == 0)
243  msg_info("%s: sender non-delivery notification: %s",
244  queue_id, STR(new_id));
245  } else {
246  /* No applicable recipients found - cancel this notice. */
247  (void) vstream_fclose(bounce);
248  if (count == 0)
249  bounce_status = 0;
250  }
251  }
252 
253  /*
254  * Optionally, send a postmaster notice, subject to notify_classes
255  * restrictions.
256  *
257  * This postmaster notice is not critical, so if it fails don't
258  * retransmit the bounce that we just generated, just log a warning.
259  */
260 #define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE)
261 
262  if (bounce_status == 0 && SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
263  && strcasecmp_utf8(recipient, mail_addr_double_bounce()) != 0) {
264 
265  /*
266  * Send the text with reason for the bounce, and the headers of
267  * the original message. Don't bother sending the boiler-plate
268  * text. This postmaster notice is not critical, so if it fails
269  * don't retransmit the bounce that we just generated, just log a
270  * warning.
271  */
272  postmaster = var_bounce_rcpt;
274  postmaster,
277  smtputf8,
278  new_id)) != 0) {
279  count = -1;
280  if (bounce_header(bounce, bounce_info, postmaster,
281  POSTMASTER_COPY) == 0
282  && (count = bounce_diagnostic_log(bounce, bounce_info,
283  DSN_NOTIFY_OVERRIDE)) > 0
284  && bounce_header_dsn(bounce, bounce_info) == 0
285  && bounce_diagnostic_dsn(bounce, bounce_info,
286  DSN_NOTIFY_OVERRIDE) > 0) {
287  bounce_original(bounce, bounce_info, DSN_RET_HDRS);
288  postmaster_status = post_mail_fclose(bounce);
289  if (postmaster_status == 0)
290  msg_info("%s: postmaster non-delivery notification: %s",
291  queue_id, STR(new_id));
292  } else {
293  /* No applicable recipients found - cancel this notice. */
294  (void) vstream_fclose(bounce);
295  if (count == 0)
296  postmaster_status = 0;
297  }
298  }
299  if (postmaster_status)
300  msg_warn("%s: postmaster notice failed while bouncing to %s",
301  queue_id, recipient);
302  }
303  }
304 
305  /*
306  * Optionally, delete the recipients from the queue file.
307  */
308  if (bounce_status == 0 && (flags & BOUNCE_FLAG_DELRCPT))
309  bounce_delrcpt(bounce_info);
310 
311  /*
312  * Examine the completion status. Delete the bounce log file only when
313  * the bounce was posted successfully, and only if we are bouncing for
314  * real, not just warning.
315  */
316  if (bounce_status == 0 && mail_queue_remove(service, queue_id)
317  && errno != ENOENT)
318  msg_fatal("remove %s %s: %m", service, queue_id);
319 
320  /*
321  * Cleanup.
322  */
323  bounce_mail_free(bounce_info);
324  vstring_free(new_id);
325 
326  return (bounce_status);
327 }
#define SEND_POSTMASTER_ANY_BOUNCE_NOTICE
#define NULL_TRACE_FLAGS
int bounce_notify_service(int flags, char *service, char *queue_name, char *queue_id, char *encoding, int smtputf8, char *recipient, char *dsn_envid, int dsn_ret, BOUNCE_TEMPLATES *ts)
int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int headers_only)
#define POSTMASTER_COPY
#define DSN_RET_HDRS
Definition: dsn_mask.h:18
#define DSN_NOTIFY_OVERRIDE
Definition: dsn_mask.h:58
#define DSN_NOTIFY_FAILURE
Definition: dsn_mask.h:45
int bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info, const char *dest, int postmaster_copy)
#define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
const NAME_MASK mail_error_masks[]
Definition: mail_error.c:70
#define strcasecmp_utf8(s1, s2)
Definition: stringops.h:75
char * var_bounce_rcpt
Definition: bounce.c:194
int bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int notify_filter)
VSTREAM * post_mail_fopen_nowait(const char *sender, const char *recipient, int source_class, int trace_flags, int utf8_flags, VSTRING *queue_id)
Definition: post_mail.c:293
char * var_notify_classes
Definition: bounce.c:193
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define MAIL_SRC_MASK_BOUNCE
Definition: mail_proto.h:81
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int post_mail_fclose(VSTREAM *cleanup)
Definition: post_mail.c:449
#define name_mask(tag, table, str)
Definition: name_mask.h:49
#define DSN_RET_FULL
Definition: dsn_mask.h:17
int bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
int bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int notify_filter)
#define VAR_NOTIFY_CLASSES
Definition: mail_params.h:72
const char * mail_addr_double_bounce(void)
Definition: mail_addr.c:64
int mail_queue_remove(const char *queue_name, const char *queue_id)
Definition: mail_queue.c:274
#define NO_POSTMASTER_COPY
#define STR
BOUNCE_INFO * bounce_mail_init(const char *service, const char *queue_name, const char *queue_id, const char *encoding, int smtputf8, const char *dsn_envid, BOUNCE_TEMPLATE *template)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
BOUNCE_TEMPLATE * failure
void bounce_mail_free(BOUNCE_INFO *bounce_info)
int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
char * var_2bounce_rcpt
Definition: bounce.c:195
#define BOUNCE_FLAG_DELRCPT
Definition: bounce.h:62
#define NULL_SENDER
void msg_info(const char *fmt,...)
Definition: msg.c:199
void bounce_delrcpt(BOUNCE_INFO *bounce_info)