Home | History | Annotate | Line # | Download | only in global
      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