1 /*	$NetBSD: resolve_local.c,v 1.1.1.1 2009/06/23 10:08:47 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	resolve_local 3
6 /* SUMMARY
7 /*	determine if domain resolves to local mail system
8 /* SYNOPSIS
9 /*	#include <resolve_local.h>
10 /*
11 /*	void	resolve_local_init()
12 /*
13 /*	int	resolve_local(domain)
14 /*	const char *domain;
15 /* DESCRIPTION
16 /*	resolve_local() determines if the named domain resolves to the
17 /*	local mail system, either by case-insensitive exact match
18 /*	against the domains, files or tables listed in $mydestination,
19 /*	or by a match of an [address-literal] against of the network
20 /*	addresses listed in $inet_interfaces or in $proxy_interfaces.
21 /*
22 /*	resolve_local_init() performs initialization. If this routine is
23 /*	not called explicitly ahead of time, it will be called on the fly.
24 /* BUGS
25 /*	Calling resolve_local_init() on the fly is an incomplete solution.
26 /*	It is bound to fail with applications that enter a chroot jail.
27 /* SEE ALSO
28 /*	own_inet_addr(3), find out my own network interfaces
29 /*	match_list(3), generic pattern matching engine
30 /*	match_ops(3), generic pattern matching operators
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /*	The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /*	Wietse Venema
37 /*	IBM T.J. Watson Research
38 /*	P.O. Box 704
39 /*	Yorktown Heights, NY 10598, USA
40 /*--*/
41 
42 /* System library. */
43 
44 #include <sys_defs.h>
45 
46 /* Utility library. */
47 
48 #include <msg.h>
49 #include <mymalloc.h>
50 #include <string_list.h>
51 #include <myaddrinfo.h>
52 #include <valid_mailhost_addr.h>
53 
54 /* Global library. */
55 
56 #include <mail_params.h>
57 #include <own_inet_addr.h>
58 #include <resolve_local.h>
59 
60 /* Application-specific */
61 
62 static STRING_LIST *resolve_local_list;
63 
64 /* resolve_local_init - initialize lookup table */
65 
66 void    resolve_local_init(void)
67 {
68     if (resolve_local_list)
69 	msg_panic("resolve_local_init: duplicate initialization");
70     resolve_local_list = string_list_init(MATCH_FLAG_NONE, var_mydest);
71 }
72 
73 /* resolve_local - match domain against list of local destinations */
74 
75 int     resolve_local(const char *addr)
76 {
77     char   *saved_addr = mystrdup(addr);
78     char   *dest;
79     const char *bare_dest;
80     struct addrinfo *res0 = 0;
81     ssize_t len;
82 
83     /*
84      * The optimizer will eliminate tests that always fail.
85      */
86 #define RETURN(x) \
87     do { \
88 	myfree(saved_addr); \
89 	if (res0) \
90 	    freeaddrinfo(res0); \
91 	return(x); \
92     } while (0)
93 
94     if (resolve_local_list == 0)
95 	resolve_local_init();
96 
97     /*
98      * Strip one trailing dot but not dot-dot.
99      *
100      * XXX This should not be distributed all over the code. Problem is,
101      * addresses can enter the system via multiple paths: networks, local
102      * forward/alias/include files, even as the result of address rewriting.
103      */
104     len = strlen(saved_addr);
105     if (len == 0)
106 	RETURN(0);
107     if (saved_addr[len - 1] == '.')
108 	saved_addr[--len] = 0;
109     if (len == 0 || saved_addr[len - 1] == '.')
110 	RETURN(0);
111 
112     /*
113      * Compare the destination against the list of destinations that we
114      * consider local.
115      */
116     if (string_list_match(resolve_local_list, saved_addr))
117 	RETURN(1);
118 
119     /*
120      * Compare the destination against the list of interface addresses that
121      * we are supposed to listen on.
122      *
123      * The destination may be an IPv6 address literal that was buried somewhere
124      * inside a deeply recursively nested address. This information comes
125      * from an untrusted source, and Wietse is not confident that everyone's
126      * getaddrinfo() etc. implementation is sufficiently robust. The syntax
127      * is complex enough with null field compression and with IPv4-in-IPv6
128      * addresses that errors are likely.
129      *
130      * The solution below is ad-hoc. We neutralize the string as soon as we
131      * realize that its contents could be harmful. We neutralize the string
132      * here, instead of neutralizing it in every resolve_local() caller.
133      * That's because resolve_local knows how the address is going to be
134      * parsed and converted into binary form.
135      *
136      * There are several more structural solutions to this.
137      *
138      * - One solution is to disallow address literals. This is not as bad as it
139      * seems: I have never seen actual legitimate use of address literals.
140      *
141      * - Another solution is to label each string with a trustworthiness label
142      * and to expect that all Postfix infrastructure will exercise additional
143      * caution when given a string with untrusted content. This is not likely
144      * to happen.
145      *
146      * FIX 200501 IPv6 patch did not require "IPv6:" prefix in numerical
147      * addresses.
148      */
149     dest = saved_addr;
150     if (*dest == '[' && dest[len - 1] == ']') {
151 	dest++;
152 	dest[len -= 2] = 0;
153 	if ((bare_dest = valid_mailhost_addr(dest, DO_GRIPE)) != 0
154 	    && hostaddr_to_sockaddr(bare_dest, (char *) 0, 0, &res0) == 0) {
155 	    if (own_inet_addr(res0->ai_addr) || proxy_inet_addr(res0->ai_addr))
156 		RETURN(1);
157 	}
158     }
159 
160     /*
161      * Must be remote, or a syntax error.
162      */
163     RETURN(0);
164 }
165 
166 #ifdef TEST
167 
168 #include <vstream.h>
169 #include <mail_conf.h>
170 
171 int     main(int argc, char **argv)
172 {
173     if (argc != 2)
174 	msg_fatal("usage: %s domain", argv[0]);
175     mail_conf_read();
176     vstream_printf("%s\n", resolve_local(argv[1]) ? "yes" : "no");
177     vstream_fflush(VSTREAM_OUT);
178     return (0);
179 }
180 
181 #endif
182