Home | History | Annotate | Line # | Download | only in global
      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