Home | History | Annotate | Line # | Download | only in global
      1 /*	$NetBSD: deliver_pass.c,v 1.5 2026/05/09 18:49:16 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	deliver_pass 3
      6 /* SUMMARY
      7 /*	deliver request pass_through
      8 /* SYNOPSIS
      9 /*	#include <deliver_request.h>
     10 /*
     11 /*	int	deliver_pass(class, service, request, recipient)
     12 /*	const char *class;
     13 /*	const char *service;
     14 /*	DELIVER_REQUEST *request;
     15 /*	RECIPIENT *recipient;
     16 /*
     17 /*	int	deliver_pass_all(class, service, request)
     18 /*	const char *class;
     19 /*	const char *service;
     20 /*	DELIVER_REQUEST *request;
     21 /* DESCRIPTION
     22 /*	This module implements the client side of the `queue manager
     23 /*	to delivery agent' protocol, passing one recipient on from
     24 /*	one delivery agent to another.
     25 /*
     26 /*	deliver_pass() delegates delivery of the named recipient.
     27 /*
     28 /*	deliver_pass_all() delegates an entire delivery request.
     29 /*
     30 /*	Arguments:
     31 /* .IP class
     32 /*	Destination delivery agent service class
     33 /* .IP service
     34 /*	String of the form \fItransport\fR:\fInexthop\fR. Either transport
     35 /*	or nexthop are optional. For details see the transport map manual page.
     36 /* .IP request
     37 /*	Delivery request with queue file information.
     38 /* .IP recipient
     39 /*	Recipient information. See recipient_list(3).
     40 /* DIAGNOSTICS
     41 /* LICENSE
     42 /* .ad
     43 /* .fi
     44 /*	The Secure Mailer license must be distributed with this software.
     45 /* BUGS
     46 /*	One recipient at a time; this is OK for mailbox deliveries.
     47 /*
     48 /*	Hop status information cannot be passed back.
     49 /* AUTHOR(S)
     50 /*	Wietse Venema
     51 /*	IBM T.J. Watson Research
     52 /*	P.O. Box 704
     53 /*	Yorktown Heights, NY 10598, USA
     54 /*
     55 /*	Wietse Venema
     56 /*	Google, Inc.
     57 /*	111 8th Avenue
     58 /*	New York, NY 10011, USA
     59 /*
     60 /*	Wietse Venema
     61 /*	porcupine.org
     62 /*--*/
     63 
     64 /* System library. */
     65 
     66 #include <sys_defs.h>
     67 
     68 /* Utility library. */
     69 
     70 #include <msg.h>
     71 #include <vstring.h>
     72 #include <vstream.h>
     73 #include <split_at.h>
     74 #include <mymalloc.h>
     75 
     76 /* Global library. */
     77 
     78 #include <mail_params.h>
     79 #include <deliver_pass.h>
     80 #include <dsb_scan.h>
     81 #include <defer.h>
     82 #include <rcpt_print.h>
     83 #include <info_log_addr_form.h>
     84 
     85 #define DELIVER_PASS_DEFER	1
     86 #define DELIVER_PASS_UNKNOWN	2
     87 
     88 /* deliver_pass_initial_reply - retrieve initial delivery process response */
     89 
     90 static int deliver_pass_initial_reply(VSTREAM *stream)
     91 {
     92     if (attr_scan(stream, ATTR_FLAG_STRICT,
     93 		  RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_DELIVER),
     94 		  ATTR_TYPE_END) != 0) {
     95 	msg_warn("%s: malformed response", VSTREAM_PATH(stream));
     96 	return (-1);
     97     }
     98     return (0);
     99 }
    100 
    101 /* deliver_pass_send_request - send delivery request to delivery process */
    102 
    103 static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
    104 				             const char *nexthop,
    105 				             RECIPIENT *rcpt)
    106 {
    107     int     stat;
    108 
    109     attr_print(stream, ATTR_FLAG_NONE,
    110 	       SEND_ATTR_INT(MAIL_ATTR_FLAGS, request->flags),
    111 	       SEND_ATTR_STR(MAIL_ATTR_QUEUE, request->queue_name),
    112 	       SEND_ATTR_STR(MAIL_ATTR_QUEUEID, request->queue_id),
    113 	       SEND_ATTR_LONG(MAIL_ATTR_OFFSET, request->data_offset),
    114 	       SEND_ATTR_LONG(MAIL_ATTR_SIZE, request->data_size),
    115 	       SEND_ATTR_STR(MAIL_ATTR_NEXTHOP, nexthop),
    116 	       SEND_ATTR_STR(MAIL_ATTR_ENCODING, request->encoding),
    117 	       SEND_ATTR_INT(MAIL_ATTR_SENDOPTS, request->sendopts),
    118 	       SEND_ATTR_STR(MAIL_ATTR_SENDER, request->sender),
    119 	       SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, request->dsn_envid),
    120 	       SEND_ATTR_INT(MAIL_ATTR_DSN_RET, request->dsn_ret),
    121 	SEND_ATTR_FUNC(msg_stats_print, (const void *) &request->msg_stats),
    122     /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
    123 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_NAME, request->client_name),
    124 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr),
    125 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_PORT, request->client_port),
    126 	     SEND_ATTR_STR(MAIL_ATTR_LOG_PROTO_NAME, request->client_proto),
    127 	       SEND_ATTR_STR(MAIL_ATTR_LOG_HELO_NAME, request->client_helo),
    128     /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
    129 	       SEND_ATTR_STR(MAIL_ATTR_SASL_METHOD, request->sasl_method),
    130 	     SEND_ATTR_STR(MAIL_ATTR_SASL_USERNAME, request->sasl_username),
    131 	       SEND_ATTR_STR(MAIL_ATTR_SASL_SENDER, request->sasl_sender),
    132     /* XXX Ditto if we want to pass TLS certificate info. */
    133 	       SEND_ATTR_STR(MAIL_ATTR_LOG_IDENT, request->log_ident),
    134 	     SEND_ATTR_STR(MAIL_ATTR_RWR_CONTEXT, request->rewrite_context),
    135 	       SEND_ATTR_INT(MAIL_ATTR_RCPT_COUNT, 1),
    136 	       ATTR_TYPE_END);
    137     attr_print(stream, ATTR_FLAG_NONE,
    138 	       SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt),
    139 	       ATTR_TYPE_END);
    140 
    141     if (vstream_fflush(stream)) {
    142 	msg_warn("%s: bad write: %m", VSTREAM_PATH(stream));
    143 	stat = -1;
    144     } else {
    145 	stat = 0;
    146     }
    147     return (stat);
    148 }
    149 
    150 /* deliver_pass_final_reply - retrieve final delivery status response */
    151 
    152 static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb)
    153 {
    154     int     stat;
    155 
    156     if (attr_scan(stream, ATTR_FLAG_STRICT,
    157 		  RECV_ATTR_FUNC(dsb_scan, (void *) dsb),
    158 		  RECV_ATTR_INT(MAIL_ATTR_STATUS, &stat),
    159 		  ATTR_TYPE_END) != 2) {
    160 	msg_warn("%s: malformed response", VSTREAM_PATH(stream));
    161 	return (DELIVER_PASS_UNKNOWN);
    162     } else {
    163 	return (stat ? DELIVER_PASS_DEFER : 0);
    164     }
    165 }
    166 
    167 /* deliver_pass - deliver one per-site queue entry */
    168 
    169 int     deliver_pass(const char *class, const char *service,
    170 		             DELIVER_REQUEST *request,
    171 		             RECIPIENT *rcpt)
    172 {
    173     VSTREAM *stream;
    174     DSN_BUF *dsb;
    175     DSN     dsn;
    176     int     status;
    177     char   *saved_service;
    178     char   *transport;
    179     char   *nexthop;
    180 
    181     /*
    182      * Parse service into transport:nexthop form, and allow for omission of
    183      * optional fields
    184      */
    185     transport = saved_service = mystrdup(service);
    186     if ((nexthop = split_at(saved_service, ':')) == 0 || *nexthop == 0)
    187 	nexthop = request->nexthop;
    188     if (*transport == 0)
    189 	msg_fatal("missing transport name in \"%s\"", service);
    190 
    191     /*
    192      * Initialize.
    193      */
    194     msg_info("%s: passing <%s> to transport=%s",
    195 	     request->queue_id, info_log_addr_form_recipient(rcpt->address),
    196 	     transport);
    197     stream = mail_connect_wait(class, transport);
    198     dsb = dsb_create();
    199 
    200     /*
    201      * Get the delivery process initial response. Send the queue file info
    202      * and recipient info to the delivery process. Retrieve the delivery
    203      * agent status report. The numerical status code indicates if delivery
    204      * should be tried again. The reason text is sent only when a destination
    205      * should be avoided for a while, so that the queue manager can log why
    206      * it does not even try to schedule delivery to the affected recipients.
    207      * XXX Can't pass back hop status info because the problem is with a
    208      * different transport.
    209      */
    210     if (deliver_pass_initial_reply(stream) != 0
    211 	|| deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) {
    212 	(void) DSN_SIMPLE(&dsn, "4.3.0", "mail transport unavailable");
    213 	status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
    214 			      request->queue_id, &request->msg_stats,
    215 			      rcpt, "none", NO_TLS_STATS, &dsn);
    216     } else if ((status = deliver_pass_final_reply(stream, dsb))
    217 	       == DELIVER_PASS_UNKNOWN) {
    218 	(void) DSN_SIMPLE(&dsn, "4.3.0", "unknown mail transport error");
    219 	status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
    220 			      request->queue_id, &request->msg_stats,
    221 			      rcpt, "none", NO_TLS_STATS, &dsn);
    222     }
    223 
    224     /*
    225      * Clean up.
    226      */
    227     vstream_fclose(stream);
    228     dsb_free(dsb);
    229     myfree(saved_service);
    230 
    231     return (status);
    232 }
    233 
    234 /* deliver_pass_all - pass entire delivery request */
    235 
    236 int     deliver_pass_all(const char *class, const char *service,
    237 			         DELIVER_REQUEST *request)
    238 {
    239     RECIPIENT_LIST *list;
    240     RECIPIENT *rcpt;
    241     int     status = 0;
    242 
    243     /*
    244      * XXX We should find out if the target transport can handle
    245      * multi-recipient requests. Unfortunately such code is hard to test,
    246      * rarely used, and therefore will be buggy.
    247      */
    248     list = &request->rcpt_list;
    249     for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
    250 	status |= deliver_pass(class, service, request, rcpt);
    251     return (status);
    252 }
    253