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