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