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