Annotation of embedaddon/rsync/access.c, revision 1.1
1.1 ! misho 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>