File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / access.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

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