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