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