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