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