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