File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / access.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

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

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