File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / access.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 07:51:14 2013 UTC (10 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: RSYNC3_1_0, HEAD
v 3.1.0

    1: /*
    2:  * Routines to authenticate access to a daemon (hosts allow/deny).
    3:  *
    4:  * Copyright (C) 1998 Andrew Tridgell
    5:  * Copyright (C) 2004-2013 Wayne Davison
    6:  *
    7:  * This program is free software; you can redistribute it and/or modify
    8:  * it under the terms of the GNU General Public License as published by
    9:  * the Free Software Foundation; either version 3 of the License, or
   10:  * (at your option) any later version.
   11:  *
   12:  * This program is distributed in the hope that it will be useful,
   13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:  * GNU General Public License for more details.
   16:  *
   17:  * You should have received a copy of the GNU General Public License along
   18:  * with this program; if not, visit the http://fsf.org website.
   19:  */
   20: 
   21: #include "rsync.h"
   22: 
   23: static int allow_forward_dns;
   24: 
   25: extern const char undetermined_hostname[];
   26: 
   27: static int match_hostname(const char **host_ptr, const char *addr, const char *tok)
   28: {
   29: 	struct hostent *hp;
   30: 	unsigned int i;
   31: 	const char *host = *host_ptr;
   32: 
   33: 	if (!host || !*host)
   34: 		return 0;
   35: 
   36: 	/* First check if the reverse-DNS-determined hostname matches. */
   37: 	if (iwildmatch(tok, host))
   38: 		return 1;
   39: 
   40: 	if (!allow_forward_dns)
   41: 		return 0;
   42: 
   43: 	/* Fail quietly if tok is an address or wildcarded entry, not a simple hostname. */
   44: 	if (!tok[strspn(tok, ".0123456789")] || tok[strcspn(tok, ":/*?[")])
   45: 		return 0;
   46: 
   47: 	/* Now try forward-DNS on the token (config-specified hostname) and see if the IP matches. */
   48: 	if (!(hp = gethostbyname(tok)))
   49: 		return 0;
   50: 
   51: 	for (i = 0; hp->h_addr_list[i] != NULL; i++) {
   52: 		if (strcmp(addr, inet_ntoa(*(struct in_addr*)(hp->h_addr_list[i]))) == 0) {
   53: 			/* If reverse lookups are off, we'll use the conf-specified
   54: 			 * hostname in preference to UNDETERMINED. */
   55: 			if (host == undetermined_hostname) {
   56: 				if (!(*host_ptr = strdup(tok)))
   57: 					*host_ptr = undetermined_hostname;
   58: 			}
   59: 			return 1;
   60: 		}
   61: 	}
   62: 
   63: 	return 0;
   64: }
   65: 
   66: static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
   67: {
   68: 	int i;
   69: 
   70: 	for (i = 0; i < addrlen; i++) {
   71: 		if ((b1[i] ^ b2[i]) & mask[i])
   72: 			return 0;
   73: 	}
   74: 
   75: 	return 1;
   76: }
   77: 
   78: static void make_mask(char *mask, int plen, int addrlen)
   79: {
   80: 	int w, b;
   81: 
   82: 	w = plen >> 3;
   83: 	b = plen & 0x7;
   84: 
   85: 	if (w)
   86: 		memset(mask, 0xff, w);
   87: 	if (w < addrlen)
   88: 		mask[w] = 0xff & (0xff<<(8-b));
   89: 	if (w+1 < addrlen)
   90: 		memset(mask+w+1, 0, addrlen-w-1);
   91: 
   92: 	return;
   93: }
   94: 
   95: static int match_address(const char *addr, const char *tok)
   96: {
   97: 	char *p;
   98: 	struct addrinfo hints, *resa, *rest;
   99: 	int gai;
  100: 	int ret = 0;
  101: 	int addrlen = 0;
  102: #ifdef HAVE_STRTOL
  103: 	long int bits;
  104: #else
  105: 	int bits;
  106: #endif
  107: 	char mask[16];
  108: 	char *a = NULL, *t = NULL;
  109: 
  110: 	if (!addr || !*addr)
  111: 		return 0;
  112: 
  113: 	p = strchr(tok,'/');
  114: 	if (p)
  115: 		*p = '\0';
  116: 
  117: 	/* Fail quietly if tok is a hostname, not an address. */
  118: 	if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
  119: 		if (p)
  120: 			*p = '/';
  121: 		return 0;
  122: 	}
  123: 
  124: 	memset(&hints, 0, sizeof(hints));
  125: 	hints.ai_family = PF_UNSPEC;
  126: 	hints.ai_socktype = SOCK_STREAM;
  127: #ifdef AI_NUMERICHOST
  128: 	hints.ai_flags = AI_NUMERICHOST;
  129: #endif
  130: 
  131: 	if (getaddrinfo(addr, NULL, &hints, &resa) != 0) {
  132: 		if (p)
  133: 			*p = '/';
  134: 		return 0;
  135: 	}
  136: 
  137: 	gai = getaddrinfo(tok, NULL, &hints, &rest);
  138: 	if (p)
  139: 		*p++ = '/';
  140: 	if (gai != 0) {
  141: 		rprintf(FLOG, "error matching address %s: %s\n",
  142: 			tok, gai_strerror(gai));
  143: 		freeaddrinfo(resa);
  144: 		return 0;
  145: 	}
  146: 
  147: 	if (rest->ai_family != resa->ai_family) {
  148: 		ret = 0;
  149: 		goto out;
  150: 	}
  151: 
  152: 	switch(resa->ai_family) {
  153: 	case PF_INET:
  154: 		a = (char *)&((struct sockaddr_in *)resa->ai_addr)->sin_addr;
  155: 		t = (char *)&((struct sockaddr_in *)rest->ai_addr)->sin_addr;
  156: 		addrlen = 4;
  157: 
  158: 		break;
  159: 
  160: #ifdef INET6
  161: 	case PF_INET6:
  162: 	    {
  163: 		struct sockaddr_in6 *sin6a, *sin6t;
  164: 
  165: 		sin6a = (struct sockaddr_in6 *)resa->ai_addr;
  166: 		sin6t = (struct sockaddr_in6 *)rest->ai_addr;
  167: 
  168: 		a = (char *)&sin6a->sin6_addr;
  169: 		t = (char *)&sin6t->sin6_addr;
  170: 
  171: 		addrlen = 16;
  172: 
  173: #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
  174: 		if (sin6t->sin6_scope_id &&
  175: 		    sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
  176: 			ret = 0;
  177: 			goto out;
  178: 		}
  179: #endif
  180: 
  181: 		break;
  182: 	    }
  183: #endif
  184: 	default:
  185: 	    rprintf(FLOG, "unknown family %u\n", rest->ai_family);
  186: 	    ret = 0;
  187: 	    goto out;
  188: 	}
  189: 
  190: 	bits = -1;
  191: 	if (p) {
  192: 		if (inet_pton(resa->ai_addr->sa_family, p, mask) <= 0) {
  193: #ifdef HAVE_STRTOL
  194: 			char *ep = NULL;
  195: #else
  196: 			unsigned char *pp;
  197: #endif
  198: 
  199: #ifdef HAVE_STRTOL
  200: 			bits = strtol(p, &ep, 10);
  201: 			if (!*p || *ep) {
  202: 				rprintf(FLOG, "malformed mask in %s\n", tok);
  203: 				ret = 0;
  204: 				goto out;
  205: 			}
  206: #else
  207: 			for (pp = (unsigned char *)p; *pp; pp++) {
  208: 				if (!isascii(*pp) || !isdigit(*pp)) {
  209: 					rprintf(FLOG, "malformed mask in %s\n", tok);
  210: 					ret = 0;
  211: 					goto out;
  212: 				}
  213: 			}
  214: 			bits = atoi(p);
  215: #endif
  216: 			if (bits == 0) {
  217: 				ret = 1;
  218: 				goto out;
  219: 			}
  220: 			if (bits < 0 || bits > (addrlen << 3)) {
  221: 				rprintf(FLOG, "malformed mask in %s\n", tok);
  222: 				ret = 0;
  223: 				goto out;
  224: 			}
  225: 		}
  226: 	} else {
  227: 		bits = 128;
  228: 	}
  229: 
  230: 	if (bits >= 0)
  231: 		make_mask(mask, bits, addrlen);
  232: 
  233: 	ret = match_binary(a, t, mask, addrlen);
  234: 
  235:   out:
  236: 	freeaddrinfo(resa);
  237: 	freeaddrinfo(rest);
  238: 	return ret;
  239: }
  240: 
  241: static int access_match(const char *list, const char *addr, const char **host_ptr)
  242: {
  243: 	char *tok;
  244: 	char *list2 = strdup(list);
  245: 
  246: 	if (!list2)
  247: 		out_of_memory("access_match");
  248: 
  249: 	strlower(list2);
  250: 
  251: 	for (tok = strtok(list2, " ,\t"); tok; tok = strtok(NULL, " ,\t")) {
  252: 		if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
  253: 			free(list2);
  254: 			return 1;
  255: 		}
  256: 	}
  257: 
  258: 	free(list2);
  259: 	return 0;
  260: }
  261: 
  262: int allow_access(const char *addr, const char **host_ptr, int i)
  263: {
  264: 	const char *allow_list = lp_hosts_allow(i);
  265: 	const char *deny_list = lp_hosts_deny(i);
  266: 
  267: 	if (allow_list && !*allow_list)
  268: 		allow_list = NULL;
  269: 	if (deny_list && !*deny_list)
  270: 		deny_list = NULL;
  271: 
  272: 	allow_forward_dns = lp_forward_lookup(i);
  273: 
  274: 	/* If we match an allow-list item, we always allow access. */
  275: 	if (allow_list) {
  276: 		if (access_match(allow_list, addr, host_ptr))
  277: 			return 1;
  278: 		/* For an allow-list w/o a deny-list, disallow non-matches. */
  279: 		if (!deny_list)
  280: 			return 0;
  281: 	}
  282: 
  283: 	/* If we match a deny-list item (and got past any allow-list
  284: 	 * items), we always disallow access. */
  285: 	if (deny_list && access_match(deny_list, addr, host_ptr))
  286: 		return 0;
  287: 
  288: 	/* Allow all other access. */
  289: 	return 1;
  290: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>