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