1 /* $NetBSD: deliver_pass.c,v 1.4 2025/02/25 19:15: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 /* 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
deliver_pass_initial_reply(VSTREAM * stream)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
deliver_pass_send_request(VSTREAM * stream,DELIVER_REQUEST * request,const char * nexthop,RECIPIENT * rcpt)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
deliver_pass_final_reply(VSTREAM * stream,DSN_BUF * dsb)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
deliver_pass(const char * class,const char * service,DELIVER_REQUEST * request,RECIPIENT * rcpt)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", &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", &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
deliver_pass_all(const char * class,const char * service,DELIVER_REQUEST * request)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