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