xref: /netbsd-src/external/ibm-public/postfix/dist/src/local/resolve.c (revision 16d67a18c4cbb2d3cb426b01120f4938ca6dbbf9)
1 /*	$NetBSD: resolve.c,v 1.1.1.2 2014/07/06 19:27:52 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 
deliver_resolve_addr(LOCAL_STATE state,USER_ATTR usr_attr,char * addr)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 
deliver_resolve_tree(LOCAL_STATE state,USER_ATTR usr_attr,TOK822 * addr)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     int     rcpt_delim;
96 
97     /*
98      * Make verbose logging easier to understand.
99      */
100     state.level++;
101     if (msg_verbose)
102 	MSG_LOG_STATE(myname, state);
103 
104     /*
105      * Initialize.
106      */
107     resolve_clnt_init(&reply);
108 
109     /*
110      * Rewrite the address to canonical form, just like the cleanup service
111      * does. Then, resolve the address to (transport, nexhop, recipient),
112      * just like the queue manager does. The only part missing here is the
113      * virtual address substitution. Message forwarding fixes most of that.
114      */
115     tok822_rewrite(addr, REWRITE_CANON);
116     tok822_resolve(addr, &reply);
117 
118     /*
119      * First, a healthy portion of error handling.
120      */
121     if (reply.flags & RESOLVE_FLAG_FAIL) {
122 	dsb_simple(state.msg_attr.why, "4.3.0", "address resolver failure");
123 	status = defer_append(BOUNCE_FLAGS(state.request),
124 			      BOUNCE_ATTR(state.msg_attr));
125     } else if (reply.flags & RESOLVE_FLAG_ERROR) {
126 	dsb_simple(state.msg_attr.why, "5.1.3",
127 		   "bad recipient address syntax: %s", STR(reply.recipient));
128 	status = bounce_append(BOUNCE_FLAGS(state.request),
129 			       BOUNCE_ATTR(state.msg_attr));
130     } else {
131 
132 	/*
133 	 * Splice in the optional unmatched address extension.
134 	 */
135 	if (state.msg_attr.unmatched) {
136 	    rcpt_delim = state.msg_attr.local[strlen(state.msg_attr.user)];
137 	    if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0) {
138 		VSTRING_ADDCH(reply.recipient, rcpt_delim);
139 		vstring_strcat(reply.recipient, state.msg_attr.unmatched);
140 	    } else {
141 		ext_len = strlen(state.msg_attr.unmatched);
142 		VSTRING_SPACE(reply.recipient, ext_len + 2);
143 		if ((ratsign = strrchr(STR(reply.recipient), '@')) == 0)
144 		    msg_panic("%s: recipient @ botch", myname);
145 		memmove(ratsign + ext_len + 1, ratsign, strlen(ratsign) + 1);
146 		*ratsign = rcpt_delim;
147 		memcpy(ratsign + 1, state.msg_attr.unmatched, ext_len);
148 		VSTRING_SKIP(reply.recipient);
149 	    }
150 	}
151 	state.msg_attr.rcpt.address = STR(reply.recipient);
152 
153 	/*
154 	 * Delivery to a local or non-local address. For a while there was
155 	 * some ugly code to force local recursive alias expansions on a host
156 	 * with no authority over the local domain, but that code was just
157 	 * too unclean.
158 	 */
159 	if (strcmp(state.msg_attr.relay, STR(reply.transport)) == 0) {
160 	    status = deliver_recipient(state, usr_attr);
161 	} else {
162 	    status = deliver_indirect(state);
163 	}
164     }
165 
166     /*
167      * Cleanup.
168      */
169     resolve_clnt_free(&reply);
170 
171     return (status);
172 }
173