1/*++ 2/* NAME 3/* bounce_notify_service 3 4/* SUMMARY 5/* send non-delivery report to sender, server side 6/* SYNOPSIS 7/* #include "bounce_service.h" 8/* 9/* int bounce_notify_service(flags, queue_name, queue_id, encoding, 10/* sender, dsn_envid, dsn_ret, templates) 11/* int flags; 12/* char *queue_name; 13/* char *queue_id; 14/* char *encoding; 15/* char *sender; 16/* char *dsn_envid; 17/* int dsn_ret; 18/* BOUNCE_TEMPLATES *templates; 19/* DESCRIPTION 20/* This module implements the server side of the bounce_flush() 21/* (send bounce message) request. 22/* 23/* When a message bounces, a full copy is sent to the originator, 24/* and an optional copy of the diagnostics with message headers is 25/* sent to the postmaster. The result is non-zero when the operation 26/* should be tried again. Otherwise, the logfile is removed. 27/* 28/* When a bounce is sent, the sender address is the empty 29/* address. When a bounce bounces, an optional double bounce 30/* with the entire undeliverable mail is sent to the postmaster, 31/* with as sender address the double bounce address. 32/* DIAGNOSTICS 33/* Fatal error: error opening existing file. 34/* BUGS 35/* SEE ALSO 36/* bounce(3) basic bounce service client interface 37/* LICENSE 38/* .ad 39/* .fi 40/* The Secure Mailer license must be distributed with this software. 41/* AUTHOR(S) 42/* Wietse Venema 43/* IBM T.J. Watson Research 44/* P.O. Box 704 45/* Yorktown Heights, NY 10598, USA 46/*--*/ 47 48/* System library. */ 49 50#include <sys_defs.h> 51#include <fcntl.h> 52#include <errno.h> 53#include <string.h> 54#include <ctype.h> 55 56#ifdef STRCASECMP_IN_STRINGS_H 57#include <strings.h> 58#endif 59 60/* Utility library. */ 61 62#include <msg.h> 63#include <vstream.h> 64#include <name_mask.h> 65 66/* Global library. */ 67 68#include <mail_params.h> 69#include <mail_queue.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 76/* Application-specific. */ 77 78#include "bounce_service.h" 79 80#define STR vstring_str 81 82/* bounce_notify_service - send a bounce */ 83 84int bounce_notify_service(int flags, char *service, char *queue_name, 85 char *queue_id, char *encoding, 86 char *recipient, char *dsn_envid, 87 int dsn_ret, BOUNCE_TEMPLATES *ts) 88{ 89 BOUNCE_INFO *bounce_info; 90 int bounce_status = 1; 91 int postmaster_status = 1; 92 VSTREAM *bounce; 93 int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, 94 var_notify_classes); 95 VSTRING *new_id = vstring_alloc(10); 96 char *postmaster; 97 int count; 98 99 /* 100 * Initialize. Open queue file, bounce log, etc. 101 * 102 * XXX DSN The bounce service produces RFC 3464-style "failed mail" reports 103 * from information in two following types of logfile: 104 * 105 * 1 - bounce: this file is used for RFC 3464-style reports of permanent 106 * delivery errors by the bounce(8) service. This reports to the sender 107 * all recipients that have no DSN NOTIFY information (compatibility) and 108 * all recipients that have DSN NOTIFY=FAILURE; this reports to 109 * postmaster all recipients, if postmaster notification is enabled. 110 * 111 * 2 - defer: this file is used for three types of report: 112 * 113 * 2a) RFC 3464-style "mail is too old" reports by the bounce(8) service. 114 * This reports to the sender all recipients that have no DSN NOTIFY 115 * information (compatibility) and all recipients that have DSN 116 * NOTIFY=FAILURE; this reports to postmaster all recipients, if 117 * postmaster notification is enabled. 118 * 119 * Other reports that other servers produce from the defer logfile: 120 * 121 * 2b) On-demand reports of all delayed deliveries by the showq(8) service 122 * and mailq(1) command. This reports all recipients that have a 123 * transient delivery error. 124 * 125 * 2c) RFC 3464-style "delayed mail" notifications by the defer(8) service. 126 * This reports to the sender all recipients that have no DSN NOTIFY 127 * information (compatibility) and all recipients that have DSN 128 * NOTIFY=DELAY; this reports to postmaster all recipients, if postmaster 129 * notification is enabled. 130 */ 131 bounce_info = bounce_mail_init(service, queue_name, queue_id, 132 encoding, dsn_envid, ts->failure); 133 134#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ 135#define NULL_TRACE_FLAGS 0 136 137 /* 138 * The choice of sender address depends on the recipient address. For a 139 * single bounce (a non-delivery notification to the message originator), 140 * the sender address is the empty string. For a double bounce (typically 141 * a failed single bounce, or a postmaster notification that was produced 142 * by any of the mail processes) the sender address is defined by the 143 * var_double_bounce_sender configuration variable. When a double bounce 144 * cannot be delivered, the queue manager blackholes the resulting triple 145 * bounce message. 146 */ 147 148 /* 149 * Double bounce failed. Never send a triple bounce. 150 * 151 * However, this does not prevent double bounces from bouncing on other 152 * systems. In order to cope with this, either the queue manager must 153 * recognize the double-bounce recipient address and discard mail, or 154 * every delivery agent must recognize the double-bounce sender address 155 * and substitute something else so mail does not come back at us. 156 */ 157 if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) { 158 msg_warn("%s: undeliverable postmaster notification discarded", 159 queue_id); 160 bounce_status = 0; 161 } 162 163 /* 164 * Single bounce failed. Optionally send a double bounce to postmaster, 165 * subject to notify_classes restrictions. 166 */ 167#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE) 168#define SEND_POSTMASTER_ANY_BOUNCE_NOTICE (notify_mask & ANY_BOUNCE) 169 170 else if (*recipient == 0) { 171 if (!SEND_POSTMASTER_ANY_BOUNCE_NOTICE) { 172 bounce_status = 0; 173 } else { 174 postmaster = var_2bounce_rcpt; 175 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 176 postmaster, 177 INT_FILT_MASK_BOUNCE, 178 NULL_TRACE_FLAGS, 179 new_id)) != 0) { 180 181 /* 182 * Double bounce to Postmaster. This is the last opportunity 183 * for this message to be delivered. Send the text with 184 * reason for the bounce, and the headers of the original 185 * message. Don't bother sending the boiler-plate text. 186 */ 187 count = -1; 188 if (bounce_header(bounce, bounce_info, postmaster, 189 POSTMASTER_COPY) == 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_FULL); 196 bounce_status = post_mail_fclose(bounce); 197 if (bounce_status == 0) 198 msg_info("%s: postmaster non-delivery notification: %s", 199 queue_id, STR(new_id)); 200 } else { 201 /* No applicable recipients found - cancel this notice. */ 202 (void) vstream_fclose(bounce); 203 if (count == 0) 204 bounce_status = 0; 205 } 206 } 207 } 208 } 209 210 /* 211 * Non-bounce failed. Send a single bounce to the sender, subject to DSN 212 * NOTIFY restrictions. 213 */ 214 else { 215 if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, 216 INT_FILT_MASK_BOUNCE, 217 NULL_TRACE_FLAGS, 218 new_id)) != 0) { 219 220 /* 221 * Send the bounce message header, some boilerplate text that 222 * pretends that we are a polite mail system, the text with 223 * reason for the bounce, and a copy of the original message. 224 */ 225 count = -1; 226 if (bounce_header(bounce, bounce_info, recipient, 227 NO_POSTMASTER_COPY) == 0 228 && bounce_boilerplate(bounce, bounce_info) == 0 229 && (count = bounce_diagnostic_log(bounce, bounce_info, 230 DSN_NOTIFY_FAILURE)) > 0 231 && bounce_header_dsn(bounce, bounce_info) == 0 232 && bounce_diagnostic_dsn(bounce, bounce_info, 233 DSN_NOTIFY_FAILURE) > 0) { 234 bounce_original(bounce, bounce_info, dsn_ret ? 235 dsn_ret : DSN_RET_FULL); 236 bounce_status = post_mail_fclose(bounce); 237 if (bounce_status == 0) 238 msg_info("%s: sender non-delivery notification: %s", 239 queue_id, STR(new_id)); 240 } else { 241 /* No applicable recipients found - cancel this notice. */ 242 (void) vstream_fclose(bounce); 243 if (count == 0) 244 bounce_status = 0; 245 } 246 } 247 248 /* 249 * Optionally, send a postmaster notice, subject to notify_classes 250 * restrictions. 251 * 252 * This postmaster notice is not critical, so if it fails don't 253 * retransmit the bounce that we just generated, just log a warning. 254 */ 255#define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE) 256 257 if (bounce_status == 0 && SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE 258 && strcasecmp(recipient, mail_addr_double_bounce()) != 0) { 259 260 /* 261 * Send the text with reason for the bounce, and the headers of 262 * the original message. Don't bother sending the boiler-plate 263 * text. This postmaster notice is not critical, so if it fails 264 * don't retransmit the bounce that we just generated, just log a 265 * warning. 266 */ 267 postmaster = var_bounce_rcpt; 268 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 269 postmaster, 270 INT_FILT_MASK_BOUNCE, 271 NULL_TRACE_FLAGS, 272 new_id)) != 0) { 273 count = -1; 274 if (bounce_header(bounce, bounce_info, postmaster, 275 POSTMASTER_COPY) == 0 276 && (count = bounce_diagnostic_log(bounce, bounce_info, 277 DSN_NOTIFY_OVERRIDE)) > 0 278 && bounce_header_dsn(bounce, bounce_info) == 0 279 && bounce_diagnostic_dsn(bounce, bounce_info, 280 DSN_NOTIFY_OVERRIDE) > 0) { 281 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 282 postmaster_status = post_mail_fclose(bounce); 283 if (postmaster_status == 0) 284 msg_info("%s: postmaster non-delivery notification: %s", 285 queue_id, STR(new_id)); 286 } else { 287 /* No applicable recipients found - cancel this notice. */ 288 (void) vstream_fclose(bounce); 289 if (count == 0) 290 postmaster_status = 0; 291 } 292 } 293 if (postmaster_status) 294 msg_warn("%s: postmaster notice failed while bouncing to %s", 295 queue_id, recipient); 296 } 297 } 298 299 /* 300 * Optionally, delete the recipients from the queue file. 301 */ 302 if (bounce_status == 0 && (flags & BOUNCE_FLAG_DELRCPT)) 303 bounce_delrcpt(bounce_info); 304 305 /* 306 * Examine the completion status. Delete the bounce log file only when 307 * the bounce was posted successfully, and only if we are bouncing for 308 * real, not just warning. 309 */ 310 if (bounce_status == 0 && mail_queue_remove(service, queue_id) 311 && errno != ENOENT) 312 msg_fatal("remove %s %s: %m", service, queue_id); 313 314 /* 315 * Cleanup. 316 */ 317 bounce_mail_free(bounce_info); 318 vstring_free(new_id); 319 320 return (bounce_status); 321} 322