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