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