1/*++ 2/* NAME 3/* bounce 3 4/* SUMMARY 5/* bounce service client 6/* SYNOPSIS 7/* #include <bounce.h> 8/* 9/* int bounce_append(flags, id, stats, recipient, relay, dsn) 10/* int flags; 11/* const char *id; 12/* MSG_STATS *stats; 13/* RECIPIENT *rcpt; 14/* const char *relay; 15/* DSN *dsn; 16/* 17/* int bounce_flush(flags, queue, id, encoding, sender, 18/* dsn_envid, dsn_ret) 19/* int flags; 20/* const char *queue; 21/* const char *id; 22/* const char *encoding; 23/* const char *sender; 24/* const char *dsn_envid; 25/* int dsn_ret; 26/* 27/* int bounce_flush_verp(flags, queue, id, encoding, sender, 28/* dsn_envid, dsn_ret, verp_delims) 29/* int flags; 30/* const char *queue; 31/* const char *id; 32/* const char *encoding; 33/* const char *sender; 34/* const char *dsn_envid; 35/* int dsn_ret; 36/* const char *verp_delims; 37/* 38/* int bounce_one(flags, queue, id, encoding, sender, envid, ret, 39/* stats, recipient, relay, dsn) 40/* int flags; 41/* const char *queue; 42/* const char *id; 43/* const char *encoding; 44/* const char *sender; 45/* const char *dsn_envid; 46/* int dsn_ret; 47/* MSG_STATS *stats; 48/* RECIPIENT *rcpt; 49/* const char *relay; 50/* DSN *dsn; 51/* DESCRIPTION 52/* This module implements the client interface to the message 53/* bounce service, which maintains a per-message log of status 54/* records with recipients that were bounced, and the dsn_text why. 55/* 56/* bounce_append() appends a dsn_text for non-delivery to the 57/* bounce log for the named recipient, updates the address 58/* verification service, or updates a message delivery record 59/* on request by the sender. The flags argument determines 60/* the action. 61/* 62/* bounce_flush() actually bounces the specified message to 63/* the specified sender, including the bounce log that was 64/* built with bounce_append(). The bounce logfile is removed 65/* upon successful completion. 66/* 67/* bounce_flush_verp() is like bounce_flush(), but sends one 68/* notification per recipient, with the failed recipient encoded 69/* into the sender address. 70/* 71/* bounce_one() bounces one recipient and immediately sends a 72/* notification to the sender. This procedure does not append 73/* the recipient and dsn_text to the per-message bounce log, and 74/* should be used when a delivery agent changes the error 75/* return address in a manner that depends on the recipient 76/* address. 77/* 78/* Arguments: 79/* .IP flags 80/* The bitwise OR of zero or more of the following (specify 81/* BOUNCE_FLAG_NONE to request no special processing): 82/* .RS 83/* .IP BOUNCE_FLAG_CLEAN 84/* Delete the bounce log in case of an error (as in: pretend 85/* that we never even tried to bounce this message). 86/* .IP BOUNCE_FLAG_DELRCPT 87/* When specified with a flush request, request that 88/* recipients be deleted from the queue file. 89/* 90/* Note: the bounce daemon ignores this request when the 91/* recipient queue file offset is <= 0. 92/* .IP DEL_REQ_FLAG_MTA_VRFY 93/* The message is an MTA-requested address verification probe. 94/* Update the address verification database instead of bouncing 95/* mail. 96/* .IP DEL_REQ_FLAG_USR_VRFY 97/* The message is a user-requested address expansion probe. 98/* Update the message delivery record instead of bouncing mail. 99/* .IP DEL_REQ_FLAG_RECORD 100/* This is a normal message with logged delivery. Update the 101/* message delivery record and bounce the mail. 102/* .RE 103/* .IP queue 104/* The message queue name of the original message file. 105/* .IP id 106/* The message queue id if the original message file. The bounce log 107/* file has the same name as the original message file. 108/* .IP stats 109/* Time stamps from different message delivery stages 110/* and session reuse count. 111/* .IP rcpt 112/* Recipient information. See recipient_list(3). 113/* .IP relay 114/* Name of the host that the message could not be delivered to. 115/* This information is used for syslogging only. 116/* .IP encoding 117/* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}. 118/* .IP sender 119/* The sender envelope address. 120/* .IP dsn_envid 121/* Optional DSN envelope ID. 122/* .IP dsn_ret 123/* Optional DSN return full/headers option. 124/* .IP dsn 125/* Delivery status. See dsn(3). The specified action is ignored. 126/* .IP verp_delims 127/* VERP delimiter characters, used when encoding the failed 128/* sender into the envelope sender address. 129/* DIAGNOSTICS 130/* In case of success, these functions log the action, and return a 131/* zero value. Otherwise, the functions return a non-zero result, 132/* and when BOUNCE_FLAG_CLEAN is disabled, log that message 133/* delivery is deferred. 134/* BUGS 135/* Should be replaced by routines with an attribute-value based 136/* interface instead of an interface that uses a rigid argument list. 137/* LICENSE 138/* .ad 139/* .fi 140/* The Secure Mailer license must be distributed with this software. 141/* AUTHOR(S) 142/* Wietse Venema 143/* IBM T.J. Watson Research 144/* P.O. Box 704 145/* Yorktown Heights, NY 10598, USA 146/*--*/ 147 148/* System library. */ 149 150#include <sys_defs.h> 151#include <string.h> 152 153/* Utility library. */ 154 155#include <msg.h> 156#include <vstring.h> 157#include <mymalloc.h> 158 159/* Global library. */ 160 161#include <mail_params.h> 162#include <mail_proto.h> 163#include <log_adhoc.h> 164#include <dsn_util.h> 165#include <rcpt_print.h> 166#include <dsn_print.h> 167#include <verify.h> 168#include <defer.h> 169#include <trace.h> 170#include <bounce.h> 171 172/* bounce_append - append dsn_text to per-message bounce log */ 173 174int bounce_append(int flags, const char *id, MSG_STATS *stats, 175 RECIPIENT *rcpt, const char *relay, 176 DSN *dsn) 177{ 178 DSN my_dsn = *dsn; 179 int status; 180 181 /* 182 * Sanity check. If we're really confident, change this into msg_panic 183 * (remember, this information may be under control by a hostile server). 184 */ 185 if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) { 186 msg_warn("bounce_append: ignoring dsn code \"%s\"", my_dsn.status); 187 my_dsn.status = "5.0.0"; 188 } 189 190 /* 191 * MTA-requested address verification information is stored in the verify 192 * service database. 193 */ 194 if (flags & DEL_REQ_FLAG_MTA_VRFY) { 195 my_dsn.action = "undeliverable"; 196 status = verify_append(id, stats, rcpt, relay, &my_dsn, 197 DEL_RCPT_STAT_BOUNCE); 198 return (status); 199 } 200 201 /* 202 * User-requested address verification information is logged and mailed 203 * to the requesting user. 204 */ 205 if (flags & DEL_REQ_FLAG_USR_VRFY) { 206 my_dsn.action = "undeliverable"; 207 status = trace_append(flags, id, stats, rcpt, relay, &my_dsn); 208 return (status); 209 } 210 211 /* 212 * Normal (well almost) delivery. When we're pretending that we can't 213 * bounce, don't create a defer log file when we wouldn't keep the bounce 214 * log file. That's a lot of negatives in one sentence. 215 */ 216 else if (var_soft_bounce && (flags & BOUNCE_FLAG_CLEAN)) { 217 return (-1); 218 } 219 220 /* 221 * Normal mail delivery. May also send a delivery record to the user. 222 * 223 * XXX DSN We write all recipients to the bounce logfile regardless of DSN 224 * NOTIFY options, because those options don't apply to postmaster 225 * notifications. 226 */ 227 else { 228 char *my_status = mystrdup(my_dsn.status); 229 const char *log_status = var_soft_bounce ? "SOFTBOUNCE" : "bounced"; 230 231 /* 232 * Supply default action. 233 */ 234 my_dsn.status = my_status; 235 if (var_soft_bounce) { 236 my_status[0] = '4'; 237 my_dsn.action = "delayed"; 238 } else { 239 my_dsn.action = "failed"; 240 } 241 242 if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ? 243 var_defer_service : var_bounce_service, 244 ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND, 245 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, 246 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, 247 ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, 248 ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn, 249 ATTR_TYPE_END) == 0 250 && ((flags & DEL_REQ_FLAG_RECORD) == 0 251 || trace_append(flags, id, stats, rcpt, relay, 252 &my_dsn) == 0)) { 253 log_adhoc(id, stats, rcpt, relay, &my_dsn, log_status); 254 status = (var_soft_bounce ? -1 : 0); 255 } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { 256 VSTRING *junk = vstring_alloc(100); 257 258 my_dsn.status = "4.3.0"; 259 vstring_sprintf(junk, "%s or %s service failure", 260 var_bounce_service, var_trace_service); 261 my_dsn.reason = vstring_str(junk); 262 status = defer_append(flags, id, stats, rcpt, relay, &my_dsn); 263 vstring_free(junk); 264 } else { 265 status = -1; 266 } 267 myfree(my_status); 268 return (status); 269 } 270} 271 272/* bounce_flush - flush the bounce log and deliver to the sender */ 273 274int bounce_flush(int flags, const char *queue, const char *id, 275 const char *encoding, const char *sender, 276 const char *dsn_envid, int dsn_ret) 277{ 278 279 /* 280 * When we're pretending that we can't bounce, don't send a bounce 281 * message. 282 */ 283 if (var_soft_bounce) 284 return (-1); 285 if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service, 286 ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH, 287 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, 288 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, 289 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, 290 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 291 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 292 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 293 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret, 294 ATTR_TYPE_END) == 0) { 295 return (0); 296 } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { 297 msg_info("%s: status=deferred (bounce failed)", id); 298 return (-1); 299 } else { 300 return (-1); 301 } 302} 303 304/* bounce_flush_verp - verpified notification */ 305 306int bounce_flush_verp(int flags, const char *queue, const char *id, 307 const char *encoding, const char *sender, 308 const char *dsn_envid, int dsn_ret, 309 const char *verp_delims) 310{ 311 312 /* 313 * When we're pretending that we can't bounce, don't send a bounce 314 * message. 315 */ 316 if (var_soft_bounce) 317 return (-1); 318 if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service, 319 ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_VERP, 320 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, 321 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, 322 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, 323 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 324 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 325 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 326 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret, 327 ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims, 328 ATTR_TYPE_END) == 0) { 329 return (0); 330 } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { 331 msg_info("%s: status=deferred (bounce failed)", id); 332 return (-1); 333 } else { 334 return (-1); 335 } 336} 337 338/* bounce_one - send notice for one recipient */ 339 340int bounce_one(int flags, const char *queue, const char *id, 341 const char *encoding, const char *sender, 342 const char *dsn_envid, int dsn_ret, 343 MSG_STATS *stats, RECIPIENT *rcpt, 344 const char *relay, DSN *dsn) 345{ 346 DSN my_dsn = *dsn; 347 int status; 348 349 /* 350 * Sanity check. 351 */ 352 if (my_dsn.status[0] != '5' || !dsn_valid(my_dsn.status)) { 353 msg_warn("bounce_one: ignoring dsn code \"%s\"", my_dsn.status); 354 my_dsn.status = "5.0.0"; 355 } 356 357 /* 358 * MTA-requested address verification information is stored in the verify 359 * service database. 360 */ 361 if (flags & DEL_REQ_FLAG_MTA_VRFY) { 362 my_dsn.action = "undeliverable"; 363 status = verify_append(id, stats, rcpt, relay, &my_dsn, 364 DEL_RCPT_STAT_BOUNCE); 365 return (status); 366 } 367 368 /* 369 * User-requested address verification information is logged and mailed 370 * to the requesting user. 371 */ 372 if (flags & DEL_REQ_FLAG_USR_VRFY) { 373 my_dsn.action = "undeliverable"; 374 status = trace_append(flags, id, stats, rcpt, relay, &my_dsn); 375 return (status); 376 } 377 378 /* 379 * When we're not bouncing, then use the standard multi-recipient logfile 380 * based procedure. 381 */ 382 else if (var_soft_bounce) { 383 return (bounce_append(flags, id, stats, rcpt, relay, &my_dsn)); 384 } 385 386 /* 387 * Normal mail delivery. May also send a delivery record to the user. 388 * 389 * XXX DSN We send all recipients regardless of DSN NOTIFY options, because 390 * those options don't apply to postmaster notifications. 391 */ 392 else { 393 394 /* 395 * Supply default action. 396 */ 397 my_dsn.action = "failed"; 398 399 if (mail_command_client(MAIL_CLASS_PRIVATE, var_bounce_service, 400 ATTR_TYPE_INT, MAIL_ATTR_NREQ, BOUNCE_CMD_ONE, 401 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, 402 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, 403 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, 404 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, 405 ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, 406 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, 407 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, dsn_ret, 408 ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt, 409 ATTR_TYPE_FUNC, dsn_print, (void *) &my_dsn, 410 ATTR_TYPE_END) == 0 411 && ((flags & DEL_REQ_FLAG_RECORD) == 0 412 || trace_append(flags, id, stats, rcpt, relay, 413 &my_dsn) == 0)) { 414 log_adhoc(id, stats, rcpt, relay, &my_dsn, "bounced"); 415 status = 0; 416 } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { 417 VSTRING *junk = vstring_alloc(100); 418 419 my_dsn.status = "4.3.0"; 420 vstring_sprintf(junk, "%s or %s service failure", 421 var_bounce_service, var_trace_service); 422 my_dsn.reason = vstring_str(junk); 423 status = defer_append(flags, id, stats, rcpt, relay, &my_dsn); 424 vstring_free(junk); 425 } else { 426 status = -1; 427 } 428 return (status); 429 } 430} 431