1 /* $NetBSD: resolve.c,v 1.1.1.1 2009/06/23 10:08:49 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* resolve 3 6 /* SUMMARY 7 /* resolve recipient and deliver locally or remotely 8 /* SYNOPSIS 9 /* #include "local.h" 10 /* 11 /* int deliver_resolve_tree(state, usr_attr, addr) 12 /* LOCAL_STATE state; 13 /* USER_ATTR usr_attr; 14 /* TOK822 *addr; 15 /* 16 /* int deliver_resolve_addr(state, usr_attr, addr) 17 /* LOCAL_STATE state; 18 /* USER_ATTR usr_attr; 19 /* char *addr; 20 /* DESCRIPTION 21 /* deliver_resolve_XXX() resolves a recipient that is the result from 22 /* e.g., alias expansion, and delivers locally or via forwarding. 23 /* 24 /* Arguments: 25 /* .IP state 26 /* The attributes that specify the message, sender and more. 27 /* A table with the results from expanding aliases or lists. 28 /* A table with delivered-to: addresses taken from the message. 29 /* .IP addr 30 /* An address from, e.g., alias expansion. 31 /* DIAGNOSTICS 32 /* Fatal errors: out of memory. The result is non-zero when the 33 /* operation should be tried again. Warnings: malformed address. 34 /* SEE ALSO 35 /* recipient(3) local delivery 36 /* indirect(3) deliver via forwarding 37 /* LICENSE 38 /* .ad 39 /* .fi 40 /* The Secure Mailer license must be distributed with this software. 41 /* AUTHOR(S) 42 /* Wietse Venema 43 /* IBM T.J. Watson Research 44 /* P.O. Box 704 45 /* Yorktown Heights, NY 10598, USA 46 /*--*/ 47 48 /* System library. */ 49 50 #include <sys_defs.h> 51 #include <unistd.h> 52 #include <string.h> 53 54 /* Utility library. */ 55 56 #include <msg.h> 57 #include <vstring.h> 58 #include <htable.h> 59 60 /* Global library. */ 61 62 #include <mail_proto.h> 63 #include <resolve_clnt.h> 64 #include <rewrite_clnt.h> 65 #include <tok822.h> 66 #include <mail_params.h> 67 #include <defer.h> 68 69 /* Application-specific. */ 70 71 #include "local.h" 72 73 /* deliver_resolve_addr - resolve and deliver */ 74 75 int deliver_resolve_addr(LOCAL_STATE state, USER_ATTR usr_attr, char *addr) 76 { 77 TOK822 *tree; 78 int result; 79 80 tree = tok822_scan_addr(addr); 81 result = deliver_resolve_tree(state, usr_attr, tree); 82 tok822_free_tree(tree); 83 return (result); 84 } 85 86 /* deliver_resolve_tree - resolve and deliver */ 87 88 int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr) 89 { 90 const char *myname = "deliver_resolve_tree"; 91 RESOLVE_REPLY reply; 92 int status; 93 ssize_t ext_len; 94 char *ratsign; 95 96 /* 97 * Make verbose logging easier to understand. 98 */ 99 state.level++; 100 if (msg_verbose) 101 MSG_LOG_STATE(myname, state); 102 103 /* 104 * Initialize. 105 */ 106 resolve_clnt_init(&reply); 107 108 /* 109 * Rewrite the address to canonical form, just like the cleanup service 110 * does. Then, resolve the address to (transport, nexhop, recipient), 111 * just like the queue manager does. The only part missing here is the 112 * virtual address substitution. Message forwarding fixes most of that. 113 */ 114 tok822_rewrite(addr, REWRITE_CANON); 115 tok822_resolve(addr, &reply); 116 117 /* 118 * First, a healthy portion of error handling. 119 */ 120 if (reply.flags & RESOLVE_FLAG_FAIL) { 121 dsb_simple(state.msg_attr.why, "4.3.0", "address resolver failure"); 122 status = defer_append(BOUNCE_FLAGS(state.request), 123 BOUNCE_ATTR(state.msg_attr)); 124 } else if (reply.flags & RESOLVE_FLAG_ERROR) { 125 dsb_simple(state.msg_attr.why, "5.1.3", 126 "bad recipient address syntax: %s", STR(reply.recipient)); 127 status = bounce_append(BOUNCE_FLAGS(state.request), 128 BOUNCE_ATTR(state.msg_attr)); 129 } else { 130 131 /* 132 * Splice in the optional unmatched address extension. 133 */ 134 if (state.msg_attr.unmatched) { 135 if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) { 136 VSTRING_ADDCH(reply.recipient, *var_rcpt_delim); 137 vstring_strcat(reply.recipient, state.msg_attr.unmatched); 138 } else { 139 ext_len = strlen(state.msg_attr.unmatched); 140 VSTRING_SPACE(reply.recipient, ext_len + 2); 141 if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) 142 msg_panic("%s: recipient @ botch", myname); 143 memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1); 144 *ratsign = *var_rcpt_delim; 145 memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len); 146 VSTRING_SKIP(reply.recipient); 147 } 148 } 149 state.msg_attr.rcpt.address = STR(reply.recipient); 150 151 /* 152 * Delivery to a local or non-local address. For a while there was 153 * some ugly code to force local recursive alias expansions on a host 154 * with no authority over the local domain, but that code was just 155 * too unclean. 156 */ 157 if (strcmp(state.msg_attr.relay, STR(reply.transport)) == 0) { 158 status = deliver_recipient(state, usr_attr); 159 } else { 160 status = deliver_indirect(state); 161 } 162 } 163 164 /* 165 * Cleanup. 166 */ 167 resolve_clnt_free(&reply); 168 169 return (status); 170 } 171