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 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