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