1/*++ 2/* NAME 3/* bounce_one_service 3 4/* SUMMARY 5/* send non-delivery report to sender, server side 6/* SYNOPSIS 7/* #include "bounce_service.h" 8/* 9/* int bounce_one_service(flags, queue_name, queue_id, encoding, 10/* orig_sender, envid, ret, 11/* rcpt_buf, dsn_buf, templates) 12/* int flags; 13/* char *queue_name; 14/* char *queue_id; 15/* char *encoding; 16/* char *orig_sender; 17/* char *envid; 18/* int ret; 19/* RCPT_BUF *rcpt_buf; 20/* DSN_BUF *dsn_buf; 21/* BOUNCE_TEMPLATES *templates; 22/* DESCRIPTION 23/* This module implements the server side of the bounce_one() 24/* (send bounce message for one recipient) request. 25/* 26/* When a message bounces, a full copy is sent to the originator, 27/* and an optional copy of the diagnostics with message headers is 28/* sent to the postmaster. The result is non-zero when the operation 29/* should be tried again. 30/* 31/* When a bounce is sent, the sender address is the empty 32/* address. When a bounce bounces, an optional double bounce 33/* with the entire undeliverable mail is sent to the postmaster, 34/* with as sender address the double bounce 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#ifdef STRCASECMP_IN_STRINGS_H 60#include <strings.h> 61#endif 62 63/* Utility library. */ 64 65#include <msg.h> 66#include <vstream.h> 67#include <name_mask.h> 68 69/* Global library. */ 70 71#include <mail_params.h> 72#include <post_mail.h> 73#include <mail_addr.h> 74#include <mail_error.h> 75#include <bounce.h> 76#include <dsn_mask.h> 77 78/* Application-specific. */ 79 80#include "bounce_service.h" 81 82#define STR vstring_str 83 84/* bounce_one_service - send a bounce for one recipient */ 85 86int bounce_one_service(int flags, char *queue_name, char *queue_id, 87 char *encoding, char *orig_sender, 88 char *dsn_envid, int dsn_ret, 89 RCPT_BUF *rcpt_buf, DSN_BUF *dsn_buf, 90 BOUNCE_TEMPLATES *ts) 91{ 92 BOUNCE_INFO *bounce_info; 93 int bounce_status = 1; 94 int postmaster_status = 1; 95 VSTREAM *bounce; 96 int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, 97 var_notify_classes); 98 VSTRING *new_id = vstring_alloc(10); 99 100 /* 101 * Initialize. Open queue file, bounce log, etc. 102 */ 103 bounce_info = bounce_mail_one_init(queue_name, queue_id, encoding, 104 dsn_envid, rcpt_buf, dsn_buf, 105 ts->failure); 106 107#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ 108#define NULL_TRACE_FLAGS 0 109 110 /* 111 * The choice of bounce sender address depends on the original sender 112 * address. For a single bounce (a non-delivery notification to the 113 * message originator), the sender address is the empty string. For a 114 * double bounce (typically a failed single bounce, or a postmaster 115 * notification that was produced by any of the mail processes) the 116 * sender address is defined by the var_double_bounce_sender 117 * configuration variable. When a double bounce cannot be delivered, the 118 * queue manager blackholes the resulting triple bounce message. 119 */ 120 121 /* 122 * Double bounce failed. Never send a triple bounce. 123 * 124 * However, this does not prevent double bounces from bouncing on other 125 * systems. In order to cope with this, either the queue manager must 126 * recognize the double-bounce original sender address and discard mail, 127 * or every delivery agent must recognize the double-bounce sender 128 * address and substitute something else so mail does not come back at 129 * us. 130 */ 131 if (strcasecmp(orig_sender, mail_addr_double_bounce()) == 0) { 132 msg_warn("%s: undeliverable postmaster notification discarded", 133 queue_id); 134 bounce_status = 0; 135 } 136 137 /* 138 * Single bounce failed. Optionally send a double bounce to postmaster, 139 * subject to notify_classes restrictions. 140 */ 141#define ANY_BOUNCE (MAIL_ERROR_2BOUNCE | MAIL_ERROR_BOUNCE) 142#define SEND_POSTMASTER_ANY_BOUNCE_NOTICE (notify_mask & ANY_BOUNCE) 143 144 else if (*orig_sender == 0) { 145 if (!SEND_POSTMASTER_ANY_BOUNCE_NOTICE) { 146 bounce_status = 0; 147 } else { 148 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 149 var_2bounce_rcpt, 150 INT_FILT_MASK_BOUNCE, 151 NULL_TRACE_FLAGS, 152 new_id)) != 0) { 153 154 /* 155 * Double bounce to Postmaster. This is the last opportunity 156 * for this message to be delivered. Send the text with 157 * reason for the bounce, and the headers of the original 158 * message. Don't bother sending the boiler-plate text. 159 */ 160 if (!bounce_header(bounce, bounce_info, var_2bounce_rcpt, 161 POSTMASTER_COPY) 162 && bounce_recipient_log(bounce, bounce_info) == 0 163 && bounce_header_dsn(bounce, bounce_info) == 0 164 && bounce_recipient_dsn(bounce, bounce_info) == 0) 165 bounce_original(bounce, bounce_info, DSN_RET_FULL); 166 bounce_status = post_mail_fclose(bounce); 167 if (bounce_status == 0) 168 msg_info("%s: postmaster non-delivery notification: %s", 169 queue_id, STR(new_id)); 170 } 171 } 172 } 173 174 /* 175 * Non-bounce failed. Send a single bounce, subject to DSN NOTIFY 176 * restrictions. 177 */ 178 else { 179 RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt; 180 181 if (rcpt->dsn_notify != 0 /* compat */ 182 && (rcpt->dsn_notify & DSN_NOTIFY_FAILURE) == 0) { 183 bounce_status = 0; 184 } else { 185 if ((bounce = post_mail_fopen_nowait(NULL_SENDER, orig_sender, 186 INT_FILT_MASK_BOUNCE, 187 NULL_TRACE_FLAGS, 188 new_id)) != 0) { 189 190 /* 191 * Send the bounce message header, some boilerplate text that 192 * pretends that we are a polite mail system, the text with 193 * reason for the bounce, and a copy of the original message. 194 */ 195 if (bounce_header(bounce, bounce_info, orig_sender, 196 NO_POSTMASTER_COPY) == 0 197 && bounce_boilerplate(bounce, bounce_info) == 0 198 && bounce_recipient_log(bounce, bounce_info) == 0 199 && bounce_header_dsn(bounce, bounce_info) == 0 200 && bounce_recipient_dsn(bounce, bounce_info) == 0) 201 bounce_original(bounce, bounce_info, dsn_ret ? 202 dsn_ret : DSN_RET_FULL); 203 bounce_status = post_mail_fclose(bounce); 204 if (bounce_status == 0) 205 msg_info("%s: sender non-delivery notification: %s", 206 queue_id, STR(new_id)); 207 } 208 } 209 210 /* 211 * Optionally send a postmaster notice, subject to notify_classes 212 * restrictions. 213 * 214 * This postmaster notice is not critical, so if it fails don't 215 * retransmit the bounce that we just generated, just log a warning. 216 */ 217#define SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE (notify_mask & MAIL_ERROR_BOUNCE) 218 219 if (bounce_status == 0 && SEND_POSTMASTER_SINGLE_BOUNCE_NOTICE 220 && strcasecmp(orig_sender, mail_addr_double_bounce()) != 0) { 221 222 /* 223 * Send the text with reason for the bounce, and the headers of 224 * the original message. Don't bother sending the boiler-plate 225 * text. This postmaster notice is not critical, so if it fails 226 * don't retransmit the bounce that we just generated, just log a 227 * warning. 228 */ 229 if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), 230 var_bounce_rcpt, 231 INT_FILT_MASK_BOUNCE, 232 NULL_TRACE_FLAGS, 233 new_id)) != 0) { 234 if (bounce_header(bounce, bounce_info, var_bounce_rcpt, 235 POSTMASTER_COPY) == 0 236 && bounce_recipient_log(bounce, bounce_info) == 0 237 && bounce_header_dsn(bounce, bounce_info) == 0 238 && bounce_recipient_dsn(bounce, bounce_info) == 0) 239 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 240 postmaster_status = post_mail_fclose(bounce); 241 if (postmaster_status == 0) 242 msg_info("%s: postmaster non-delivery notification: %s", 243 queue_id, STR(new_id)); 244 } 245 if (postmaster_status) 246 msg_warn("%s: postmaster notice failed while bouncing to %s", 247 queue_id, orig_sender); 248 } 249 } 250 251 /* 252 * Optionally, delete the recipient from the queue file. 253 */ 254 if (bounce_status == 0 && (flags & BOUNCE_FLAG_DELRCPT)) 255 bounce_delrcpt_one(bounce_info); 256 257 /* 258 * Cleanup. 259 */ 260 bounce_mail_free(bounce_info); 261 vstring_free(new_id); 262 263 return (bounce_status); 264} 265