Postfix3.3.1
bounce_one_service.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_one_service 3
4 /* SUMMARY
5 /* send non-delivery report to sender, server side
6 /* SYNOPSIS
7 /* #include "bounce_service.h"
8 /*
9 /* int bounce_one_service(flags, queue_name, queue_id, encoding,
10 /* smtputf8, orig_sender, envid, ret,
11 /* rcpt_buf, dsn_buf, templates)
12 /* int flags;
13 /* char *queue_name;
14 /* char *queue_id;
15 /* char *encoding;
16 /* int smtputf8;
17 /* char *orig_sender;
18 /* char *envid;
19 /* int ret;
20 /* RCPT_BUF *rcpt_buf;
21 /* DSN_BUF *dsn_buf;
22 /* BOUNCE_TEMPLATES *templates;
23 /* DESCRIPTION
24 /* This module implements the server side of the bounce_one()
25 /* (send bounce message for one recipient) request.
26 /*
27 /* When a message bounces, a full copy is sent to the originator,
28 /* and an optional copy of the diagnostics with message headers is
29 /* sent to the postmaster. The result is non-zero when the operation
30 /* should be tried again.
31 /*
32 /* When a bounce is sent, the sender address is the empty
33 /* address. When a bounce bounces, an optional double bounce
34 /* with the entire undeliverable mail is sent to the postmaster,
35 /* with as sender address the double bounce address.
36 /* DIAGNOSTICS
37 /* Fatal error: error opening existing file.
38 /* BUGS
39 /* SEE ALSO
40 /* bounce(3) basic bounce service client interface
41 /* LICENSE
42 /* .ad
43 /* .fi
44 /* The Secure Mailer license must be distributed with this software.
45 /* AUTHOR(S)
46 /* Wietse Venema
47 /* IBM T.J. Watson Research
48 /* P.O. Box 704
49 /* Yorktown Heights, NY 10598, USA
50 /*--*/
51 
52 /* System library. */
53 
54 #include <sys_defs.h>
55 #include <fcntl.h>
56 #include <errno.h>
57 #include <string.h>
58 #include <ctype.h>
59 
60 /* Utility library. */
61 
62 #include <msg.h>
63 #include <vstream.h>
64 #include <name_mask.h>
65 #include <stringops.h>
66 
67 /* Global library. */
68 
69 #include <mail_params.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_one_service - send a bounce for one recipient */
84 
85 int bounce_one_service(int flags, char *queue_name, char *queue_id,
86  char *encoding, int smtputf8,
87  char *orig_sender, char *dsn_envid,
88  int dsn_ret, RCPT_BUF *rcpt_buf,
89  DSN_BUF *dsn_buf, 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 
99  /*
100  * Initialize. Open queue file, bounce log, etc.
101  */
102  bounce_info = bounce_mail_one_init(queue_name, queue_id, encoding,
103  smtputf8, dsn_envid, rcpt_buf,
104  dsn_buf, ts->failure);
105 
106 #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
107 #define NULL_TRACE_FLAGS 0
108 
109  /*
110  * The choice of bounce sender address depends on the original sender
111  * address. For a single bounce (a non-delivery notification to the
112  * message originator), the sender address is the empty string. For a
113  * double bounce (typically a failed single bounce, or a postmaster
114  * notification that was produced by any of the mail processes) the
115  * sender address is defined by the var_double_bounce_sender
116  * configuration variable. When a double bounce cannot be delivered, the
117  * queue manager blackholes the resulting triple bounce message.
118  */
119 
120  /*
121  * Double bounce failed. Never send a triple bounce.
122  *
123  * However, this does not prevent double bounces from bouncing on other
124  * systems. In order to cope with this, either the queue manager must
125  * recognize the double-bounce original sender address and discard mail,
126  * or every delivery agent must recognize the double-bounce sender
127  * address and substitute something else so mail does not come back at
128  * us.
129  */
130  if (strcasecmp_utf8(orig_sender, mail_addr_double_bounce()) == 0) {
131  msg_warn("%s: undeliverable postmaster notification discarded",
132  queue_id);
133  bounce_status = 0;
134  }
135 
136  /*
137  * Single bounce failed. Optionally send a double bounce to postmaster,
138  * subject to notify_classes restrictions.
139  */
140 #define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE)
141 #define SEND_POSTMASTER_ANY_BOUNCE_NOTICE (notify_mask & ANY_BOUNCE)
142 
143  else if (*orig_sender == 0) {
145  bounce_status = 0;
146  } else {
151  smtputf8,
152  new_id)) != 0) {
153 
154  /*
155  * Double bounce to Postmaster. This is the last opportunity
156  * for this message to be delivered. Send the text with
157  * reason for the bounce, and the headers of the original
158  * message. Don't bother sending the boiler-plate text.
159  */
160  if (!bounce_header(bounce, bounce_info, var_2bounce_rcpt,
162  && bounce_recipient_log(bounce, bounce_info) == 0
163  && bounce_header_dsn(bounce, bounce_info) == 0
164  && bounce_recipient_dsn(bounce, bounce_info) == 0)
165  bounce_original(bounce, bounce_info, DSN_RET_FULL);
166  bounce_status = post_mail_fclose(bounce);
167  if (bounce_status == 0)
168  msg_info("%s: postmaster non-delivery notification: %s",
169  queue_id, STR(new_id));
170  }
171  }
172  }
173 
174  /*
175  * Non-bounce failed. Send a single bounce, subject to DSN NOTIFY
176  * restrictions.
177  */
178  else {
179  RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
180 
181  if (rcpt->dsn_notify != 0 /* compat */
182  && (rcpt->dsn_notify & DSN_NOTIFY_FAILURE) == 0) {
183  bounce_status = 0;
184  } else {
185  if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender,
188  smtputf8,
189  new_id)) != 0) {
190 
191  /*
192  * Send the bounce message header, some boilerplate text that
193  * pretends that we are a polite mail system, the text with
194  * reason for the bounce, and a copy of the original message.
195  */
196  if (bounce_header(bounce, bounce_info, orig_sender,
197  NO_POSTMASTER_COPY) == 0
198  && bounce_boilerplate(bounce, bounce_info) == 0
199  && bounce_recipient_log(bounce, bounce_info) == 0
200  && bounce_header_dsn(bounce, bounce_info) == 0
201  && bounce_recipient_dsn(bounce, bounce_info) == 0)
202  bounce_original(bounce, bounce_info, dsn_ret ?
203  dsn_ret : DSN_RET_FULL);
204  bounce_status = post_mail_fclose(bounce);
205  if (bounce_status == 0)
206  msg_info("%s: sender non-delivery notification: %s",
207  queue_id, STR(new_id));
208  }
209  }
210 
211  /*
212  * Optionally send a postmaster notice, subject to notify_classes
213  * restrictions.
214  *
215  * This postmaster notice is not critical, so if it fails don't
216  * retransmit the bounce that we just generated, just log a warning.
217  */
218 #define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE)
219 
220  if (bounce_status == 0 && SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
221  && strcasecmp_utf8(orig_sender, mail_addr_double_bounce()) != 0) {
222 
223  /*
224  * Send the text with reason for the bounce, and the headers of
225  * the original message. Don't bother sending the boiler-plate
226  * text. This postmaster notice is not critical, so if it fails
227  * don't retransmit the bounce that we just generated, just log a
228  * warning.
229  */
234  smtputf8,
235  new_id)) != 0) {
236  if (bounce_header(bounce, bounce_info, var_bounce_rcpt,
237  POSTMASTER_COPY) == 0
238  && bounce_recipient_log(bounce, bounce_info) == 0
239  && bounce_header_dsn(bounce, bounce_info) == 0
240  && bounce_recipient_dsn(bounce, bounce_info) == 0)
241  bounce_original(bounce, bounce_info, DSN_RET_HDRS);
242  postmaster_status = post_mail_fclose(bounce);
243  if (postmaster_status == 0)
244  msg_info("%s: postmaster non-delivery notification: %s",
245  queue_id, STR(new_id));
246  }
247  if (postmaster_status)
248  msg_warn("%s: postmaster notice failed while bouncing to %s",
249  queue_id, orig_sender);
250  }
251  }
252 
253  /*
254  * Optionally, delete the recipient from the queue file.
255  */
256  if (bounce_status == 0 && (flags & BOUNCE_FLAG_DELRCPT))
257  bounce_delrcpt_one(bounce_info);
258 
259  /*
260  * Cleanup.
261  */
262  bounce_mail_free(bounce_info);
263  vstring_free(new_id);
264 
265  return (bounce_status);
266 }
int bounce_one_service(int flags, char *queue_name, char *queue_id, char *encoding, int smtputf8, char *orig_sender, char *dsn_envid, int dsn_ret, RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf, BOUNCE_TEMPLATES *ts)
int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int headers_only)
#define POSTMASTER_COPY
RCPT_BUF * rcpt_buf
#define DSN_RET_HDRS
Definition: dsn_mask.h:18
#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 NULL_SENDER
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
RECIPIENT rcpt
Definition: rcpt_buf.h:30
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
#define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
char * var_notify_classes
Definition: bounce.c:193
#define SEND_POSTMASTER_ANY_BOUNCE_NOTICE
#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 bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
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)
#define VAR_NOTIFY_CLASSES
Definition: mail_params.h:72
const char * mail_addr_double_bounce(void)
Definition: mail_addr.c:64
#define NO_POSTMASTER_COPY
#define STR
#define NULL_TRACE_FLAGS
int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
BOUNCE_TEMPLATE * failure
void bounce_mail_free(BOUNCE_INFO *bounce_info)
BOUNCE_INFO * bounce_mail_one_init(const char *queue_name, const char *queue_id, const char *encoding, int smtputf8, const char *dsn_envid, RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf, BOUNCE_TEMPLATE *template)
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
void bounce_delrcpt_one(BOUNCE_INFO *bounce_info)
void msg_info(const char *fmt,...)
Definition: msg.c:199