Postfix3.3.1
bounce_notify_verp.c
[詳解]
1 /*++
2 /* NAME
3 /* bounce_notify_verp 3
4 /* SUMMARY
5 /* send non-delivery report to sender, server side
6 /* SYNOPSIS
7 /* #include "bounce_service.h"
8 /*
9 /* int bounce_notify_verp(flags, service, queue_name, queue_id,
10 /* encoding, smtputf8, sender,
11 /* dsn_envid, dsn_ret, verp_delims,
12 /* templates)
13 /* int flags;
14 /* char *service;
15 /* char *queue_name;
16 /* char *queue_id;
17 /* char *encoding;
18 /* int smtputf8;
19 /* char *sender;
20 /* char *dsn_envid;
21 /* int dsn_ret;
22 /* char *verp_delims;
23 /* BOUNCE_TEMPLATES *templates;
24 /* DESCRIPTION
25 /* This module implements the server side of the bounce_notify()
26 /* (send bounce message) request. The logfile
27 /* is removed after and a warning is posted.
28 /* The bounce recipient address is encoded in VERP format.
29 /* This routine must be used for single bounces only.
30 /*
31 /* When a message bounces, a full copy is sent to the originator,
32 /* and an optional copy of the diagnostics with message headers is
33 /* sent to the postmaster. The result is non-zero when the operation
34 /* should be tried again.
35 /*
36 /* When a bounce is sent, the sender address is the empty
37 /* address.
38 /* DIAGNOSTICS
39 /* Fatal error: error opening existing file.
40 /* SEE ALSO
41 /* bounce(3) basic bounce service client interface
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /* The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /* Wietse Venema
48 /* IBM T.J. Watson Research
49 /* P.O. Box 704
50 /* Yorktown Heights, NY 10598, USA
51 /*--*/
52 
53 /* System library. */
54 
55 #include <sys_defs.h>
56 #include <fcntl.h>
57 #include <errno.h>
58 #include <string.h>
59 #include <ctype.h>
60 
61 /* Utility library. */
62 
63 #include <msg.h>
64 #include <vstream.h>
65 #include <name_mask.h>
66 #include <stringops.h>
67 
68 /* Global library. */
69 
70 #include <mail_params.h>
71 #include <mail_queue.h>
72 #include <post_mail.h>
73 #include <mail_addr.h>
74 #include <mail_error.h>
75 #include <verp_sender.h>
76 #include <bounce.h>
77 #include <dsn_mask.h>
78 #include <rec_type.h>
79 
80 /* Application-specific. */
81 
82 #include "bounce_service.h"
83 
84 #define STR vstring_str
85 
86 /* bounce_notify_verp - send a bounce, VERP style */
87 
88 int bounce_notify_verp(int flags, char *service, char *queue_name,
89  char *queue_id, char *encoding,
90  int smtputf8, char *recipient,
91  char *dsn_envid, int dsn_ret,
92  char *verp_delims, BOUNCE_TEMPLATES *ts)
93 {
94  const char *myname = "bounce_notify_verp";
95  BOUNCE_INFO *bounce_info;
96  int bounce_status = 0;
97  int postmaster_status;
98  VSTREAM *bounce;
101  char *postmaster;
102  VSTRING *verp_buf;
103  VSTRING *new_id;
104 
105  /*
106  * Sanity checks. We must be called only for undeliverable non-bounce
107  * messages.
108  */
109  if (*recipient == 0)
110  msg_panic("%s: attempt to bounce a single bounce", myname);
111  if (strcasecmp_utf8(recipient, mail_addr_double_bounce()) == 0)
112  msg_panic("%s: attempt to bounce a double bounce", myname);
113 
114  /*
115  * Initialize. Open queue file, bounce log, etc.
116  */
117  bounce_info = bounce_mail_init(service, queue_name, queue_id,
118  encoding, smtputf8, dsn_envid,
119  ts->failure);
120 
121  /*
122  * If we have no recipient list then we can't send VERP replies. Send
123  * *something* anyway so that the mail is not lost in a black hole.
124  */
125  if (bounce_info->log_handle == 0) {
126  DSN_BUF *dsn_buf = dsb_create();
127  RCPT_BUF *rcpt_buf = rcpb_create();
128 
129  dsb_simple(dsn_buf, "5.0.0", "(error report unavailable)");
130  (void) DSN_FROM_DSN_BUF(dsn_buf);
131  vstring_strcpy(rcpt_buf->address, "(recipient address unavailable)");
132  (void) RECIPIENT_FROM_RCPT_BUF(rcpt_buf);
133  bounce_status = bounce_one_service(flags, queue_name, queue_id,
134  encoding, smtputf8, recipient,
135  dsn_envid, dsn_ret, rcpt_buf,
136  dsn_buf, ts);
137  rcpb_free(rcpt_buf);
138  dsb_free(dsn_buf);
139  bounce_mail_free(bounce_info);
140  return (bounce_status);
141  }
142 #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
143 #define NULL_TRACE_FLAGS 0
144 
145  /*
146  * A non-bounce message was returned. Send a single bounce, one per
147  * recipient.
148  */
149  verp_buf = vstring_alloc(100);
150  new_id = vstring_alloc(10);
151  while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf,
152  bounce_info->dsn_buf) != 0) {
153  RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
154 
155  /*
156  * Notify the originator, subject to DSN NOTIFY restrictions.
157  *
158  * Fix 20090114: Use the Postfix original recipient, because that is
159  * what the VERP consumer expects.
160  */
161  if (rcpt->dsn_notify != 0 /* compat */
162  && (rcpt->dsn_notify & DSN_NOTIFY_FAILURE) == 0) {
163  bounce_status = 0;
164  } else {
165  verp_sender(verp_buf, verp_delims, recipient, rcpt);
166  if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf),
169  smtputf8,
170  new_id)) != 0) {
171 
172  /*
173  * Send the bounce message header, some boilerplate text that
174  * pretends that we are a polite mail system, the text with
175  * reason for the bounce, and a copy of the original message.
176  */
177  if (bounce_header(bounce, bounce_info, STR(verp_buf),
178  NO_POSTMASTER_COPY) == 0
179  && bounce_boilerplate(bounce, bounce_info) == 0
180  && bounce_recipient_log(bounce, bounce_info) == 0
181  && bounce_header_dsn(bounce, bounce_info) == 0
182  && bounce_recipient_dsn(bounce, bounce_info) == 0)
183  bounce_original(bounce, bounce_info, dsn_ret ?
184  dsn_ret : DSN_RET_FULL);
185  bounce_status = post_mail_fclose(bounce);
186  if (bounce_status == 0)
187  msg_info("%s: sender non-delivery notification: %s",
188  queue_id, STR(new_id));
189  } else
190  bounce_status = 1;
191 
192  /*
193  * Stop at the first sign of trouble, instead of making the
194  * problem worse.
195  */
196  if (bounce_status != 0)
197  break;
198 
199  /*
200  * Optionally, mark this recipient as done.
201  */
202  if (flags & BOUNCE_FLAG_DELRCPT)
203  bounce_delrcpt_one(bounce_info);
204  }
205 
206  /*
207  * Optionally, send a postmaster notice, subject to notify_classes
208  * restrictions.
209  *
210  * This postmaster notice is not critical, so if it fails don't
211  * retransmit the bounce that we just generated, just log a warning.
212  */
213 #define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE)
214 
216 
217  /*
218  * Send the text with reason for the bounce, and the headers of
219  * the original message. Don't bother sending the boiler-plate
220  * text. This postmaster notice is not critical, so if it fails
221  * don't retransmit the bounce that we just generated, just log a
222  * warning.
223  */
224  postmaster = var_bounce_rcpt;
226  postmaster,
229  smtputf8,
230  new_id)) != 0) {
231  if (bounce_header(bounce, bounce_info, postmaster,
232  POSTMASTER_COPY) == 0
233  && bounce_recipient_log(bounce, bounce_info) == 0
234  && bounce_header_dsn(bounce, bounce_info) == 0
235  && bounce_recipient_dsn(bounce, bounce_info) == 0)
236  bounce_original(bounce, bounce_info, DSN_RET_HDRS);
237  postmaster_status = post_mail_fclose(bounce);
238  if (postmaster_status == 0)
239  msg_info("%s: postmaster non-delivery notification: %s",
240  queue_id, STR(new_id));
241  } else
242  postmaster_status = 1;
243 
244  if (postmaster_status)
245  msg_warn("%s: postmaster notice failed while bouncing to %s",
246  queue_id, recipient);
247  }
248  }
249 
250  /*
251  * Examine the completion status. Delete the bounce log file only when
252  * the bounce was posted successfully, and only if we are bouncing for
253  * real, not just warning.
254  */
255  if (bounce_status == 0 && mail_queue_remove(service, queue_id)
256  && errno != ENOENT)
257  msg_fatal("remove %s %s: %m", service, queue_id);
258 
259  /*
260  * Cleanup.
261  */
262  bounce_mail_free(bounce_info);
263  vstring_free(verp_buf);
264  vstring_free(new_id);
265 
266  return (bounce_status);
267 }
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)
DSN_BUF * dsb_create(void)
Definition: dsn_buf.c:169
int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, int headers_only)
#define POSTMASTER_COPY
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
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)
VSTRING * verp_sender(VSTRING *buf, const char *delimiters, const char *sender, const RECIPIENT *rcpt_info)
Definition: verp_sender.c:67
#define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE
void dsb_free(DSN_BUF *dsb)
Definition: dsn_buf.c:190
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
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
RECIPIENT rcpt
Definition: rcpt_buf.h:30
RCPT_BUF * rcpb_create(void)
Definition: rcpt_buf.c:80
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
int bounce_notify_verp(int flags, char *service, char *queue_name, char *queue_id, char *encoding, int smtputf8, char *recipient, char *dsn_envid, int dsn_ret, char *verp_delims, BOUNCE_TEMPLATES *ts)
void rcpb_free(RCPT_BUF *rcpt)
Definition: rcpt_buf.c:108
#define DSN_FROM_DSN_BUF(dsb)
Definition: dsn_buf.h:68
char * var_notify_classes
Definition: bounce.c:193
VSTRING * address
Definition: rcpt_buf.h:31
#define NULL_TRACE_FLAGS
#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)
DSN_BUF * dsb_simple(DSN_BUF *dsb, const char *status, const char *format,...)
Definition: dsn_buf.c:275
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
DSN_BUF * dsn_buf
#define STR
#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 RECIPIENT_FROM_RCPT_BUF(buf)
Definition: rcpt_buf.h:43
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)
int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
BOUNCE_LOG * log_handle
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
BOUNCE_TEMPLATE * failure
#define NULL_SENDER
void bounce_mail_free(BOUNCE_INFO *bounce_info)
int bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
#define BOUNCE_FLAG_DELRCPT
Definition: bounce.h:62
void bounce_delrcpt_one(BOUNCE_INFO *bounce_info)
BOUNCE_LOG * bounce_log_read(BOUNCE_LOG *bp, RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf)
Definition: bounce_log.c:147
void msg_info(const char *fmt,...)
Definition: msg.c:199