1 /*	$NetBSD: deliver_pass.c,v 1.3 2022/10/08 16:12:45 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 
61 /* System library. */
62 
63 #include <sys_defs.h>
64 
65 /* Utility library. */
66 
67 #include <msg.h>
68 #include <vstring.h>
69 #include <vstream.h>
70 #include <split_at.h>
71 #include <mymalloc.h>
72 
73 /* Global library. */
74 
75 #include <mail_params.h>
76 #include <deliver_pass.h>
77 #include <dsb_scan.h>
78 #include <defer.h>
79 #include <rcpt_print.h>
80 #include <info_log_addr_form.h>
81 
82 #define DELIVER_PASS_DEFER	1
83 #define DELIVER_PASS_UNKNOWN	2
84 
85 /* deliver_pass_initial_reply - retrieve initial delivery process response */
86 
deliver_pass_initial_reply(VSTREAM * stream)87 static int deliver_pass_initial_reply(VSTREAM *stream)
88 {
89     if (attr_scan(stream, ATTR_FLAG_STRICT,
90 		  RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_DELIVER),
91 		  ATTR_TYPE_END) != 0) {
92 	msg_warn("%s: malformed response", VSTREAM_PATH(stream));
93 	return (-1);
94     }
95     return (0);
96 }
97 
98 /* deliver_pass_send_request - send delivery request to delivery process */
99 
deliver_pass_send_request(VSTREAM * stream,DELIVER_REQUEST * request,const char * nexthop,RECIPIENT * rcpt)100 static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
101 				             const char *nexthop,
102 				             RECIPIENT *rcpt)
103 {
104     int     stat;
105 
106     attr_print(stream, ATTR_FLAG_NONE,
107 	       SEND_ATTR_INT(MAIL_ATTR_FLAGS, request->flags),
108 	       SEND_ATTR_STR(MAIL_ATTR_QUEUE, request->queue_name),
109 	       SEND_ATTR_STR(MAIL_ATTR_QUEUEID, request->queue_id),
110 	       SEND_ATTR_LONG(MAIL_ATTR_OFFSET, request->data_offset),
111 	       SEND_ATTR_LONG(MAIL_ATTR_SIZE, request->data_size),
112 	       SEND_ATTR_STR(MAIL_ATTR_NEXTHOP, nexthop),
113 	       SEND_ATTR_STR(MAIL_ATTR_ENCODING, request->encoding),
114 	       SEND_ATTR_INT(MAIL_ATTR_SMTPUTF8, request->smtputf8),
115 	       SEND_ATTR_STR(MAIL_ATTR_SENDER, request->sender),
116 	       SEND_ATTR_STR(MAIL_ATTR_DSN_ENVID, request->dsn_envid),
117 	       SEND_ATTR_INT(MAIL_ATTR_DSN_RET, request->dsn_ret),
118 	SEND_ATTR_FUNC(msg_stats_print, (const void *) &request->msg_stats),
119     /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
120 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_NAME, request->client_name),
121 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr),
122 	     SEND_ATTR_STR(MAIL_ATTR_LOG_CLIENT_PORT, request->client_port),
123 	     SEND_ATTR_STR(MAIL_ATTR_LOG_PROTO_NAME, request->client_proto),
124 	       SEND_ATTR_STR(MAIL_ATTR_LOG_HELO_NAME, request->client_helo),
125     /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
126 	       SEND_ATTR_STR(MAIL_ATTR_SASL_METHOD, request->sasl_method),
127 	     SEND_ATTR_STR(MAIL_ATTR_SASL_USERNAME, request->sasl_username),
128 	       SEND_ATTR_STR(MAIL_ATTR_SASL_SENDER, request->sasl_sender),
129     /* XXX Ditto if we want to pass TLS certificate info. */
130 	       SEND_ATTR_STR(MAIL_ATTR_LOG_IDENT, request->log_ident),
131 	     SEND_ATTR_STR(MAIL_ATTR_RWR_CONTEXT, request->rewrite_context),
132 	       SEND_ATTR_INT(MAIL_ATTR_RCPT_COUNT, 1),
133 	       ATTR_TYPE_END);
134     attr_print(stream, ATTR_FLAG_NONE,
135 	       SEND_ATTR_FUNC(rcpt_print, (const void *) rcpt),
136 	       ATTR_TYPE_END);
137 
138     if (vstream_fflush(stream)) {
139 	msg_warn("%s: bad write: %m", VSTREAM_PATH(stream));
140 	stat = -1;
141     } else {
142 	stat = 0;
143     }
144     return (stat);
145 }
146 
147 /* deliver_pass_final_reply - retrieve final delivery status response */
148 
deliver_pass_final_reply(VSTREAM * stream,DSN_BUF * dsb)149 static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb)
150 {
151     int     stat;
152 
153     if (attr_scan(stream, ATTR_FLAG_STRICT,
154 		  RECV_ATTR_FUNC(dsb_scan, (void *) dsb),
155 		  RECV_ATTR_INT(MAIL_ATTR_STATUS, &stat),
156 		  ATTR_TYPE_END) != 2) {
157 	msg_warn("%s: malformed response", VSTREAM_PATH(stream));
158 	return (DELIVER_PASS_UNKNOWN);
159     } else {
160 	return (stat ? DELIVER_PASS_DEFER : 0);
161     }
162 }
163 
164 /* deliver_pass - deliver one per-site queue entry */
165 
deliver_pass(const char * class,const char * service,DELIVER_REQUEST * request,RECIPIENT * rcpt)166 int     deliver_pass(const char *class, const char *service,
167 		             DELIVER_REQUEST *request,
168 		             RECIPIENT *rcpt)
169 {
170     VSTREAM *stream;
171     DSN_BUF *dsb;
172     DSN     dsn;
173     int     status;
174     char   *saved_service;
175     char   *transport;
176     char   *nexthop;
177 
178     /*
179      * Parse service into transport:nexthop form, and allow for omission of
180      * optional fields
181      */
182     transport = saved_service = mystrdup(service);
183     if ((nexthop = split_at(saved_service, ':')) == 0 || *nexthop == 0)
184 	nexthop = request->nexthop;
185     if (*transport == 0)
186 	msg_fatal("missing transport name in \"%s\"", service);
187 
188     /*
189      * Initialize.
190      */
191     msg_info("%s: passing <%s> to transport=%s",
192 	     request->queue_id, info_log_addr_form_recipient(rcpt->address),
193 	     transport);
194     stream = mail_connect_wait(class, transport);
195     dsb = dsb_create();
196 
197     /*
198      * Get the delivery process initial response. Send the queue file info
199      * and recipient info to the delivery process. Retrieve the delivery
200      * agent status report. The numerical status code indicates if delivery
201      * should be tried again. The reason text is sent only when a destination
202      * should be avoided for a while, so that the queue manager can log why
203      * it does not even try to schedule delivery to the affected recipients.
204      * XXX Can't pass back hop status info because the problem is with a
205      * different transport.
206      */
207     if (deliver_pass_initial_reply(stream) != 0
208 	|| deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) {
209 	(void) DSN_SIMPLE(&dsn, "4.3.0", "mail transport unavailable");
210 	status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
211 			      request->queue_id, &request->msg_stats,
212 			      rcpt, "none", &dsn);
213     } else if ((status = deliver_pass_final_reply(stream, dsb))
214 	       == DELIVER_PASS_UNKNOWN) {
215 	(void) DSN_SIMPLE(&dsn, "4.3.0", "unknown mail transport error");
216 	status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
217 			      request->queue_id, &request->msg_stats,
218 			      rcpt, "none", &dsn);
219     }
220 
221     /*
222      * Clean up.
223      */
224     vstream_fclose(stream);
225     dsb_free(dsb);
226     myfree(saved_service);
227 
228     return (status);
229 }
230 
231 /* deliver_pass_all - pass entire delivery request */
232 
deliver_pass_all(const char * class,const char * service,DELIVER_REQUEST * request)233 int     deliver_pass_all(const char *class, const char *service,
234 			         DELIVER_REQUEST *request)
235 {
236     RECIPIENT_LIST *list;
237     RECIPIENT *rcpt;
238     int     status = 0;
239 
240     /*
241      * XXX We should find out if the target transport can handle
242      * multi-recipient requests. Unfortunately such code is hard to test,
243      * rarely used, and therefore will be buggy.
244      */
245     list = &request->rcpt_list;
246     for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
247 	status |= deliver_pass(class, service, request, rcpt);
248     return (status);
249 }
250