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 
deliver_resolve_addr(LOCAL_STATE state,USER_ATTR usr_attr,char * addr)73 int     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 
deliver_resolve_tree(LOCAL_STATE state,USER_ATTR usr_attr,TOK822 * addr)86 int     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