1/* $NetBSD: bounce_warn_service.c,v 1.2 2017/02/14 01:16:44 christos Exp $ */ 2 3/*++ 4/* NAME 5/* bounce_warn_service 3 6/* SUMMARY 7/* send non-delivery report to sender, server side 8/* SYNOPSIS 9/* #include "bounce_service.h" 10/* 11/* int bounce_warn_service(flags, service, queue_name, queue_id, 12/* encoding, smtputf8, sender, envid, 13/* dsn_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 dsn_ret; 23/* BOUNCE_TEMPLATES *ts; 24/* DESCRIPTION 25/* This module implements the server side of the bounce_warn() 26/* (send delay notice) request. The logfile 27/* is not removed, and a warning is sent instead of a bounce. 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 <mail_queue.h> 73#include <post_mail.h> 74#include <mail_addr.h> 75#include <mail_error.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_warn_service - send a delayed mail notice */ 86 87int bounce_warn_service(int unused_flags, char *service, char *queue_name, 88 char *queue_id, char *encoding, 89 int smtputf8, char *recipient, 90 char *dsn_envid, int dsn_ret, 91 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 char *postmaster; 101 int count; 102 103 /* 104 * Initialize. Open queue file, bounce log, etc. 105 * 106 * XXX DSN This service produces RFC 3464-style "delayed mail" reports from 107 * information in the defer logfile. That same file is used for three 108 * different types of report: 109 * 110 * a) On-demand reports of all delayed deliveries by the mailq(1) command. 111 * This reports all recipients that have a transient delivery error. 112 * 113 * b) RFC 3464-style "delayed mail" notifications by the defer(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=DELAY; this reports to postmaster all recipients, subject to 117 * notify_classes restrictions. 118 * 119 * c) RFC 3464-style bounce reports by the bounce(8) service when mail is 120 * too old. This reports to the sender all recipients that have no DSN 121 * NOTIFY information (compatibility) and all recipients that have DSN 122 * NOTIFY=FAILURE; this reports to postmaster all recipients, subject to 123 * notify_classes restrictions. 124 */ 125 bounce_info = bounce_mail_init(service, queue_name, queue_id, 126 encoding, smtputf8, dsn_envid, ts->delay); 127 128#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ 129#define NULL_TRACE_FLAGS 0 130 131 /* 132 * The choice of sender address depends on the recipient address. For a 133 * single bounce (a non-delivery notification to the message originator), 134 * the sender address is the empty string. For a double bounce (typically 135 * a failed single bounce, or a postmaster notification that was produced 136 * by any of the mail processes) the sender address is defined by the 137 * var_double_bounce_sender configuration variable. When a double bounce 138 * cannot be delivered, the queue manager blackholes the resulting triple 139 * bounce message. 140 */ 141 142 /* 143 * Double bounce failed. Never send a triple bounce. 144 * 145 * However, this does not prevent double bounces from bouncing on other 146 * systems. In order to cope with this, either the queue manager must 147 * recognize the double-bounce recipient address and discard mail, or 148 * every delivery agent must recognize the double-bounce sender address 149 * and substitute something else so mail does not come back at us. 150 */ 151 if (strcasecmp_utf8(recipient, mail_addr_double_bounce()) == 0) { 152 msg_warn("%s: undeliverable postmaster notification discarded", 153 queue_id); 154 bounce_status = 0; 155 } 156 157 /* 158 * Single bounce failed. Optionally send a double bounce to postmaster, 159 * subject to notify_classes restrictions. 160 */ 161#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE) 162#define SEND_POSTMASTER_DELAY_NOTICE (notify_mask & MAIL_ERROR_DELAY) 163 164 else if (*recipient == 0) { 165 if (!SEND_POSTMASTER_DELAY_NOTICE) { 166 bounce_status = 0; 167 } else { 168 postmaster = var_delay_rcpt; 169 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 170 postmaster, 171 MAIL_SRC_MASK_BOUNCE, 172 NULL_TRACE_FLAGS, 173 smtputf8, 174 new_id)) != 0) { 175 176 /* 177 * Double bounce to Postmaster. This is the last opportunity 178 * for this message to be delivered. Send the text with 179 * reason for the bounce, and the headers of the original 180 * message. Don't bother sending the boiler-plate text. 181 */ 182 count = -1; 183 if (!bounce_header(bounce, bounce_info, postmaster, 184 POSTMASTER_COPY) 185 && (count = bounce_diagnostic_log(bounce, bounce_info, 186 DSN_NOTIFY_OVERRIDE)) > 0 187 && bounce_header_dsn(bounce, bounce_info) == 0 188 && bounce_diagnostic_dsn(bounce, bounce_info, 189 DSN_NOTIFY_OVERRIDE) > 0) { 190 bounce_original(bounce, bounce_info, DSN_RET_FULL); 191 bounce_status = post_mail_fclose(bounce); 192 if (bounce_status == 0) 193 msg_info("%s: postmaster delay notification: %s", 194 queue_id, STR(new_id)); 195 } else { 196 (void) vstream_fclose(bounce); 197 if (count == 0) 198 bounce_status = 0; 199 } 200 } 201 } 202 } 203 204 /* 205 * Non-bounce failed. Send a single bounce, subject to DSN NOTIFY 206 * restrictions. 207 */ 208 else { 209 if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, 210 MAIL_SRC_MASK_BOUNCE, 211 NULL_TRACE_FLAGS, 212 smtputf8, 213 new_id)) != 0) { 214 215 /* 216 * Send the bounce message header, some boilerplate text that 217 * pretends that we are a polite mail system, the text with 218 * reason for the bounce, and a copy of the original message. 219 */ 220 count = -1; 221 if (bounce_header(bounce, bounce_info, recipient, 222 NO_POSTMASTER_COPY) == 0 223 && bounce_boilerplate(bounce, bounce_info) == 0 224 && (count = bounce_diagnostic_log(bounce, bounce_info, 225 DSN_NOTIFY_DELAY)) > 0 226 && bounce_header_dsn(bounce, bounce_info) == 0 227 && bounce_diagnostic_dsn(bounce, bounce_info, 228 DSN_NOTIFY_DELAY) > 0) { 229 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 230 bounce_status = post_mail_fclose(bounce); 231 if (bounce_status == 0) 232 msg_info("%s: sender delay notification: %s", 233 queue_id, STR(new_id)); 234 } else { 235 (void) vstream_fclose(bounce); 236 if (count == 0) 237 bounce_status = 0; 238 } 239 } 240 241 /* 242 * Optionally send a postmaster notice, subject to notify_classes 243 * restrictions. 244 * 245 * This postmaster notice is not critical, so if it fails don't 246 * retransmit the bounce that we just generated, just log a warning. 247 */ 248 if (bounce_status == 0 && SEND_POSTMASTER_DELAY_NOTICE 249 && strcasecmp_utf8(recipient, mail_addr_double_bounce()) != 0) { 250 251 /* 252 * Send the text with reason for the bounce, and the headers of 253 * the original message. Don't bother sending the boiler-plate 254 * text. This postmaster notice is not critical, so if it fails 255 * don't retransmit the bounce that we just generated, just log a 256 * warning. 257 */ 258 postmaster = var_delay_rcpt; 259 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 260 postmaster, 261 MAIL_SRC_MASK_BOUNCE, 262 NULL_TRACE_FLAGS, 263 smtputf8, 264 new_id)) != 0) { 265 count = -1; 266 if (bounce_header(bounce, bounce_info, postmaster, 267 POSTMASTER_COPY) == 0 268 && (count = bounce_diagnostic_log(bounce, bounce_info, 269 DSN_NOTIFY_OVERRIDE)) > 0 270 && bounce_header_dsn(bounce, bounce_info) == 0 271 && bounce_diagnostic_dsn(bounce, bounce_info, 272 DSN_NOTIFY_OVERRIDE) > 0) { 273 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 274 postmaster_status = post_mail_fclose(bounce); 275 if (postmaster_status == 0) 276 msg_info("%s: postmaster delay notification: %s", 277 queue_id, STR(new_id)); 278 } else { 279 (void) vstream_fclose(bounce); 280 if (count == 0) 281 postmaster_status = 0; 282 } 283 } 284 if (postmaster_status) 285 msg_warn("%s: postmaster notice failed while warning %s", 286 queue_id, recipient); 287 } 288 } 289 290 /* 291 * Cleanup. 292 */ 293 bounce_mail_free(bounce_info); 294 vstring_free(new_id); 295 296 return (bounce_status); 297} 298