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