1 /* $NetBSD: defer.c,v 1.5 2026/05/09 18:49:15 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* defer 3 6 /* SUMMARY 7 /* defer service client interface 8 /* SYNOPSIS 9 /* #include <defer.h> 10 /* 11 /* int defer_append(flags, id, stats, rcpt, relay, tstats, dsn) 12 /* int flags; 13 /* const char *id; 14 /* MSG_STATS *stats; 15 /* RECIPIENT *rcpt; 16 /* const char *relay; 17 /* const POL_STATS *tstats; 18 /* DSN *dsn; 19 /* 20 /* int defer_flush(flags, queue, id, encoding, sendopts, sender, 21 /* dsn_envid, dsn_ret) 22 /* int flags; 23 /* const char *queue; 24 /* const char *id; 25 /* const char *encoding; 26 /* int sendopts; 27 /* const char *sender; 28 /* const char *dsn_envid; 29 /* int dsn_ret; 30 /* 31 /* int defer_warn(flags, queue, id, encoding, sendopts, sender, 32 dsn_envid, dsn_ret) 33 /* int flags; 34 /* const char *queue; 35 /* const char *id; 36 /* const char *encoding; 37 /* int sendopts; 38 /* const char *sender; 39 /* const char *dsn_envid; 40 /* int dsn_ret; 41 /* 42 /* int defer_one(flags, queue, id, encoding, sendopts, sender, 43 /* dsn_envid, ret, stats, recipient, relay, 44 /* tstats, dsn) 45 /* int flags; 46 /* const char *queue; 47 /* const char *id; 48 /* const char *encoding; 49 /* int sendopts; 50 /* const char *sender; 51 /* const char *dsn_envid; 52 /* int dsn_ret; 53 /* MSG_STATS *stats; 54 /* RECIPIENT *rcpt; 55 /* const char *relay; 56 /* const POL_STATS *tstats; 57 /* DSN *dsn; 58 /* INTERNAL API 59 /* int defer_append_intern(flags, id, stats, rcpt, relay, tstats, dsn) 60 /* int flags; 61 /* const char *id; 62 /* MSG_STATS *stats; 63 /* RECIPIENT *rcpt; 64 /* const char *relay; 65 /* const POL_STATS *tstats; 66 /* DSN *dsn; 67 /* DESCRIPTION 68 /* This module implements a client interface to the defer service, 69 /* which maintains a per-message logfile with status records for 70 /* each recipient whose delivery is deferred, and the dsn_text why. 71 /* 72 /* defer_append() appends a record to the per-message defer log, 73 /* with the dsn_text for delayed delivery to the named rcpt, 74 /* updates the address verification service, or updates a message 75 /* delivery record on request by the sender. The flags argument 76 /* determines the action. 77 /* The result is a convenient non-zero value. 78 /* When the fast flush cache is enabled, the fast flush server is 79 /* notified of deferred mail. 80 /* 81 /* defer_flush() bounces the specified message to the specified 82 /* sender, including the defer log that was built with defer_append(). 83 /* defer_flush() requests that the deferred recipients are deleted 84 /* from the original queue file; the defer logfile is deleted after 85 /* successful completion. 86 /* The result is zero in case of success, non-zero otherwise. 87 /* 88 /* defer_warn() sends a warning message that the mail in 89 /* question has been deferred. The defer log is not deleted, 90 /* and no recipients are deleted from the original queue file. 91 /* 92 /* defer_one() implements dsn_filter(3) compatibility for the 93 /* bounce_one() routine. 94 /* 95 /* defer_append_intern() is for use after the DSN filter. 96 /* 97 /* Arguments: 98 /* .IP flags 99 /* The bit-wise OR of zero or more of the following (specify 100 /* BOUNCE_FLAG_NONE to explicitly request not special processing): 101 /* .RS 102 /* .IP BOUNCE_FLAG_CLEAN 103 /* Delete the defer log in case of an error (as in: pretend 104 /* that we never even tried to defer this message). 105 /* .IP BOUNCE_FLAG_DELRCPT 106 /* When specified with a flush request, request that 107 /* recipients be deleted from the queue file. 108 /* 109 /* Note: the bounce daemon ignores this request when the 110 /* recipient queue file offset is <= 0. 111 /* .IP DEL_REQ_FLAG_MTA_VRFY 112 /* The message is an MTA-requested address verification probe. 113 /* Update the address verification database instead of deferring 114 /* mail. 115 /* .IP DEL_REQ_FLAG_USR_VRFY 116 /* The message is a user-requested address expansion probe. 117 /* Update the message delivery record instead of deferring 118 /* mail. 119 /* .IP DEL_REQ_FLAG_RECORD 120 /* This is a normal message with logged delivery. Update the 121 /* message delivery record and defer mail delivery. 122 /* .RE 123 /* .IP queue 124 /* The message queue name of the original message file. 125 /* .IP id 126 /* The queue id of the original message file. 127 /* .IP stats 128 /* Time stamps from different message delivery stages 129 /* and session reuse count. 130 /* .IP rcpt 131 /* Recipient information. See recipient_list(3). 132 /* .IP relay 133 /* Host we could not talk to. 134 /* .IP tstats 135 /* TLS per-feature status. 136 /* .IP dsn 137 /* Delivery status. See dsn(3). The specified action is ignored. 138 /* .IP encoding 139 /* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}. 140 /* .IP sendopts 141 /* Sender-requested SMTPUTF8 or RequireTLS support. 142 /* .IP sender 143 /* The sender envelope address. 144 /* .IP dsn_envid 145 /* Optional DSN envelope ID. 146 /* .IP dsn_ret 147 /* Optional DSN return full/headers option. 148 /* .PP 149 /* For convenience, these functions always return a non-zero result. 150 /* DIAGNOSTICS 151 /* Warnings: problems connecting to the defer service. 152 /* Fatal: out of memory. 153 /* BUGS 154 /* Should be replaced by routines with an attribute-value based 155 /* interface instead of an interface that uses a rigid argument list. 156 /* LICENSE 157 /* .ad 158 /* .fi 159 /* The Secure Mailer license must be distributed with this software. 160 /* AUTHOR(S) 161 /* Wietse Venema 162 /* IBM T.J. Watson Research 163 /* P.O. Box 704 164 /* Yorktown Heights, NY 10598, USA 165 /* 166 /* Wietse Venema 167 /* Google, Inc. 168 /* 111 8th Avenue 169 /* New York, NY 10011, USA 170 /* 171 /* Wietse Venema 172 /* porcupine.org 173 /*--*/ 174 175 /* System library. */ 176 177 #include <sys_defs.h> 178 #include <string.h> 179 180 /* Utility library. */ 181 182 #include <msg.h> 183 #include <vstring.h> 184 185 /* Global library. */ 186 187 #define DSN_INTERN 188 #include <mail_params.h> 189 #include <mail_queue.h> 190 #include <mail_proto.h> 191 #include <flush_clnt.h> 192 #include <verify.h> 193 #include <dsn_util.h> 194 #include <rcpt_print.h> 195 #include <dsn_print.h> 196 #include <log_adhoc.h> 197 #include <trace.h> 198 #include <defer.h> 199 200 #define STR(x) vstring_str(x) 201 202 /* defer_append - defer message delivery */ 203 204 int defer_append(int flags, const char *id, MSG_STATS *stats, 205 RECIPIENT *rcpt, const char *relay, 206 const POL_STATS *tstats, DSN *dsn) 207 { 208 DSN my_dsn = *dsn; 209 DSN *dsn_res; 210 211 /* 212 * Sanity check. 213 */ 214 if (my_dsn.status[0] != '4' || !dsn_valid(my_dsn.status)) { 215 msg_warn("defer_append: ignoring dsn code \"%s\"", my_dsn.status); 216 my_dsn.status = "4.0.0"; 217 } 218 219 /* 220 * DSN filter (Postfix 3.0). 221 */ 222 if (delivery_status_filter != 0 223 && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) { 224 if (dsn_res->status[0] == '5') 225 return (bounce_append_intern(flags, id, stats, rcpt, relay, tstats, 226 dsn_res)); 227 my_dsn = *dsn_res; 228 } 229 return (defer_append_intern(flags, id, stats, rcpt, relay, tstats, 230 &my_dsn)); 231 } 232 233 /* defer_append_intern - defer message delivery */ 234 235 int defer_append_intern(int flags, const char *id, MSG_STATS *stats, 236 RECIPIENT *rcpt, const char *relay, 237 const POL_STATS *tstats, DSN *dsn) 238 { 239 const char *rcpt_domain; 240 DSN my_dsn = *dsn; 241 int status; 242 243 /* 244 * MTA-requested address verification information is stored in the verify 245 * service database. 246 */ 247 if (flags & DEL_REQ_FLAG_MTA_VRFY) { 248 my_dsn.action = "undeliverable"; 249 status = verify_append(id, stats, rcpt, relay, tstats, &my_dsn, 250 DEL_RCPT_STAT_DEFER); 251 return (status); 252 } 253 254 /* 255 * User-requested address verification information is logged and mailed 256 * to the requesting user. 257 */ 258 if (flags & DEL_REQ_FLAG_USR_VRFY) { 259 my_dsn.action = "undeliverable"; 260 status = trace_append(flags, id, stats, rcpt, relay, tstats, &my_dsn); 261 return (status); 262 } 263 264 /* 265 * Normal mail delivery. May also send a delivery record to the user. 266 * 267 * XXX DSN We write all deferred recipients to the defer logfile regardless 268 * of DSN NOTIFY options, because those options don't apply to mailq(1) 269 * reports or to postmaster notifications. 270 */ 271 else { 272 273 /* 274 * Supply default action. 275 */ 276 my_dsn.action = "delayed"; 277 278 if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service, 279 MAIL_ATTR_PROTO_BOUNCE, 280 SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND), 281 SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags), 282 SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id), 283 SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt), 284 SEND_ATTR_FUNC(dsn_print, (const void *) &my_dsn), 285 ATTR_TYPE_END) != 0) 286 msg_warn("%s: %s service failure", id, var_defer_service); 287 log_adhoc(id, stats, rcpt, relay, tstats, &my_dsn, "deferred"); 288 289 /* 290 * Traced delivery. 291 */ 292 if (flags & DEL_REQ_FLAG_RECORD) 293 if (trace_append(flags, id, stats, rcpt, relay, tstats, 294 &my_dsn) != 0) 295 msg_warn("%s: %s service failure", id, var_trace_service); 296 297 /* 298 * Notify the fast flush service. XXX Should not this belong in the 299 * bounce/defer daemon? Well, doing it here is more robust. 300 */ 301 if ((rcpt_domain = strrchr(rcpt->address, '@')) != 0 302 && *++rcpt_domain != 0) 303 switch (flush_add(rcpt_domain, id)) { 304 case FLUSH_STAT_OK: 305 case FLUSH_STAT_DENY: 306 break; 307 default: 308 msg_warn("%s: %s service failure", id, var_flush_service); 309 break; 310 } 311 return (-1); 312 } 313 } 314 315 /* defer_flush - flush the defer log and deliver to the sender */ 316 317 int defer_flush(int flags, const char *queue, const char *id, 318 const char *encoding, int sendopts, 319 const char *sender, const char *dsn_envid, 320 int dsn_ret) 321 { 322 flags |= BOUNCE_FLAG_DELRCPT; 323 324 if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service, 325 MAIL_ATTR_PROTO_BOUNCE, 326 SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH), 327 SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags), 328 SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue), 329 SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id), 330 SEND_ATTR_STR(MAIL_ATTR_ENCODING, encoding), 331 SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, sendopts), 332 SEND_ATTR_STR(MAIL_ATTR_SENDER, sender), 333 SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, dsn_envid), 334 SEND_ATTR_INT(MAIL_ATTR_DSN_RET, dsn_ret), 335 ATTR_TYPE_END) == 0) { 336 return (0); 337 } else { 338 return (-1); 339 } 340 } 341 342 /* defer_warn - send a copy of the defer log to the sender as a warning bounce 343 * do not flush the log */ 344 345 int defer_warn(int flags, const char *queue, const char *id, 346 const char *encoding, int sendopts, 347 const char *sender, const char *envid, int dsn_ret) 348 { 349 if (mail_command_client(MAIL_CLASS_PRIVATE, var_defer_service, 350 MAIL_ATTR_PROTO_BOUNCE, 351 SEND_ATTR_INT(MAIL_ATTR_NREQ, BOUNCE_CMD_WARN), 352 SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags), 353 SEND_ATTR_STR(MAIL_ATTR_QUEUE, queue), 354 SEND_ATTR_STR(MAIL_ATTR_QUEUEID, id), 355 SEND_ATTR_STR(MAIL_ATTR_ENCODING, encoding), 356 SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, sendopts), 357 SEND_ATTR_STR(MAIL_ATTR_SENDER, sender), 358 SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, envid), 359 SEND_ATTR_INT(MAIL_ATTR_DSN_RET, dsn_ret), 360 ATTR_TYPE_END) == 0) { 361 return (0); 362 } else { 363 return (-1); 364 } 365 } 366 367 /* defer_one - defer mail for one recipient */ 368 369 int defer_one(int flags, const char *queue, const char *id, 370 const char *encoding, int sendopts, 371 const char *sender, const char *dsn_envid, 372 int dsn_ret, MSG_STATS *stats, RECIPIENT *rcpt, 373 const char *relay, const POL_STATS *tstats, DSN *dsn) 374 { 375 DSN my_dsn = *dsn; 376 DSN *dsn_res; 377 378 /* 379 * Sanity check. 380 */ 381 if (my_dsn.status[0] != '4' || !dsn_valid(my_dsn.status)) { 382 msg_warn("defer_one: ignoring dsn code \"%s\"", my_dsn.status); 383 my_dsn.status = "4.0.0"; 384 } 385 386 /* 387 * DSN filter (Postfix 3.0). 388 */ 389 if (delivery_status_filter != 0 390 && (dsn_res = dsn_filter_lookup(delivery_status_filter, &my_dsn)) != 0) { 391 if (dsn_res->status[0] == '5') 392 return (bounce_one_intern(flags, queue, id, encoding, sendopts, 393 sender, dsn_envid, dsn_ret, stats, 394 rcpt, relay, tstats, dsn_res)); 395 my_dsn = *dsn_res; 396 } 397 return (defer_append_intern(flags, id, stats, rcpt, relay, tstats, 398 &my_dsn)); 399 } 400