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