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 65static STRING_LIST *resolve_local_list; 66 67/* resolve_local_init - initialize lookup table */ 68 69void 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 80int 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 178int 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