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