1 /* $NetBSD: bounce_trace_service.c,v 1.2 2017/02/14 01:16:44 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* bounce_trace_service 3
6 /* SUMMARY
7 /* send status report to sender, server side
8 /* SYNOPSIS
9 /* #include "bounce_service.h"
10 /*
11 /* int bounce_trace_service(flags, service, queue_name, queue_id,
12 /* encoding, smtputf8, sender, envid,
13 /* ret, templates)
14 /* int flags;
15 /* char *service;
16 /* char *queue_name;
17 /* char *queue_id;
18 /* char *encoding;
19 /* int smtputf8;
20 /* char *sender;
21 /* char *envid;
22 /* int ret;
23 /* BOUNCE_TEMPLATES *templates;
24 /* DESCRIPTION
25 /* This module implements the server side of the trace_flush()
26 /* (send delivery notice) request. The logfile
27 /* is removed after the notice is posted.
28 /*
29 /* A status report includes a prelude with human-readable text,
30 /* a DSN-style report, and the email message that was subject of
31 /* the status report.
32 /*
33 /* When a status report is sent, the sender address is the empty
34 /* 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 <stringops.h>
64
65 /* Global library. */
66
67 #include <mail_params.h>
68 #include <mail_queue.h>
69 #include <post_mail.h>
70 #include <mail_addr.h>
71 #include <mail_error.h>
72 #include <dsn_mask.h>
73 #include <rec_type.h>
74 #include <deliver_request.h> /* USR_VRFY and RECORD flags */
75
76 /* Application-specific. */
77
78 #include "bounce_service.h"
79
80 #define STR vstring_str
81
82 /* bounce_trace_service - send a delivery status notice */
83
bounce_trace_service(int flags,char * service,char * queue_name,char * queue_id,char * encoding,int smtputf8,char * recipient,char * dsn_envid,int unused_dsn_ret,BOUNCE_TEMPLATES * ts)84 int bounce_trace_service(int flags, char *service, char *queue_name,
85 char *queue_id, char *encoding,
86 int smtputf8,
87 char *recipient, char *dsn_envid,
88 int unused_dsn_ret,
89 BOUNCE_TEMPLATES *ts)
90 {
91 BOUNCE_INFO *bounce_info;
92 int bounce_status = 1;
93 VSTREAM *bounce;
94 int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
95 var_notify_classes);
96 VSTRING *new_id;
97 int count;
98 const char *sender;
99
100 /*
101 * For consistency with fail/delay notifications, send notification for a
102 * non-bounce message as a single-bounce message, send notification for a
103 * single-bounce message as a double-bounce message, and drop requests to
104 * send notification for a double-bounce message.
105 */
106 #define NULL_SENDER MAIL_ADDR_EMPTY /* special address */
107
108 if (strcasecmp_utf8(recipient, mail_addr_double_bounce()) == 0) {
109 msg_info("%s: not sending trace/success notification for "
110 "double-bounce message", queue_id);
111 return (0);
112 } else if (*recipient == 0) {
113 if ((notify_mask & MAIL_ERROR_2BOUNCE) != 0) {
114 recipient = var_2bounce_rcpt;
115 sender = mail_addr_double_bounce();
116 } else {
117 msg_info("%s: not sending trace/success notification "
118 "for single-bounce message", queue_id);
119 if (mail_queue_remove(service, queue_id) && errno != ENOENT)
120 msg_fatal("remove %s %s: %m", service, queue_id);
121 return (0);
122 }
123 } else {
124 /* Always send notification for non-bounce message. */
125 sender = NULL_SENDER;
126 }
127
128 /*
129 * Initialize. Open queue file, bounce log, etc.
130 *
131 * XXX DSN The trace service produces information from the trace logfile
132 * which is used for three types of reports:
133 *
134 * a) "what-if" reports that show what would happen without actually
135 * delivering mail (sendmail -bv).
136 *
137 * b) A report of actual deliveries (sendmail -v).
138 *
139 * c) DSN NOTIFY=SUCCESS reports of successful delivery ("delivered",
140 * "expanded" or "relayed").
141 */
142 #define NON_DSN_FLAGS (DEL_REQ_FLAG_USR_VRFY | DEL_REQ_FLAG_RECORD)
143
144 bounce_info = bounce_mail_init(service, queue_name, queue_id,
145 encoding, smtputf8, dsn_envid,
146 flags & NON_DSN_FLAGS ?
147 ts->verify : ts->success);
148
149 /*
150 * XXX With multi-recipient mail some queue file recipients may have
151 * NOTIFY=SUCCESS and others not. Depending on what subset of recipients
152 * are delivered, a trace file may or may not be created. Even when the
153 * last partial delivery attempt had no NOTIFY=SUCCESS recipients, a
154 * trace file may still exist from a previous partial delivery attempt.
155 * So as long as any recipient in the original queue file had
156 * NOTIFY=SUCCESS we have to always look for the trace file and be
157 * prepared for the file not to exist.
158 *
159 * See also comments in qmgr/qmgr_active.c.
160 */
161 if (bounce_info->log_handle == 0) {
162 if (msg_verbose)
163 msg_info("%s: no trace file -- not sending a notification",
164 queue_id);
165 bounce_mail_free(bounce_info);
166 return (0);
167 }
168 #define NULL_TRACE_FLAGS 0
169
170 /*
171 * Send a single bounce with a template message header, some boilerplate
172 * text that pretends that we are a polite mail system, the text with
173 * per-recipient status, and a copy of the original message.
174 *
175 * XXX DSN We use the same trace file for "what-if", "verbose delivery" and
176 * "success" delivery reports. This saves file system overhead because
177 * there are fewer potential left-over files to remove up when we create
178 * a new queue file.
179 */
180 new_id = vstring_alloc(10);
181 if ((bounce = post_mail_fopen_nowait(sender, recipient,
182 MAIL_SRC_MASK_BOUNCE,
183 NULL_TRACE_FLAGS,
184 smtputf8,
185 new_id)) != 0) {
186 count = -1;
187 if (bounce_header(bounce, bounce_info, recipient,
188 NO_POSTMASTER_COPY) == 0
189 && bounce_boilerplate(bounce, bounce_info) == 0
190 && (count = bounce_diagnostic_log(bounce, bounce_info,
191 DSN_NOTIFY_OVERRIDE)) > 0
192 && bounce_header_dsn(bounce, bounce_info) == 0
193 && bounce_diagnostic_dsn(bounce, bounce_info,
194 DSN_NOTIFY_OVERRIDE) > 0) {
195 bounce_original(bounce, bounce_info, DSN_RET_HDRS);
196 bounce_status = post_mail_fclose(bounce);
197 if (bounce_status == 0)
198 msg_info("%s: sender delivery status notification: %s",
199 queue_id, STR(new_id));
200 } else {
201 (void) vstream_fclose(bounce);
202 if (count == 0)
203 bounce_status = 0;
204 }
205 }
206
207 /*
208 * Examine the completion status. Delete the trace log file only when the
209 * status notice was posted successfully.
210 */
211 if (bounce_status == 0 && mail_queue_remove(service, queue_id)
212 && errno != ENOENT)
213 msg_fatal("remove %s %s: %m", service, queue_id);
214
215 /*
216 * Cleanup.
217 */
218 bounce_mail_free(bounce_info);
219 vstring_free(new_id);
220
221 return (bounce_status);
222 }
223