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 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 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 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