Annotation of embedaddon/rsync/access.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * Routines to authenticate access to a daemon (hosts allow/deny).
                      3:  *
                      4:  * Copyright (C) 1998 Andrew Tridgell
1.1.1.3 ! misho       5:  * Copyright (C) 2004-2015 Wayne Davison
1.1       misho       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: 
1.1.1.2   misho      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)
1.1       misho      28: {
1.1.1.2   misho      29:        struct hostent *hp;
                     30:        unsigned int i;
                     31:        const char *host = *host_ptr;
                     32: 
1.1       misho      33:        if (!host || !*host)
                     34:                return 0;
1.1.1.2   misho      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;
1.1       misho      64: }
                     65: 
1.1.1.2   misho      66: static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
1.1       misho      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: 
1.1.1.2   misho      95: static int match_address(const char *addr, const char *tok)
1.1       misho      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,'/');
1.1.1.2   misho     114:        if (p)
1.1       misho     115:                *p = '\0';
                    116: 
1.1.1.2   misho     117:        /* Fail quietly if tok is a hostname, not an address. */
                    118:        if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
1.1       misho     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: 
1.1.1.2   misho     241: static int access_match(const char *list, const char *addr, const char **host_ptr)
1.1       misho     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")) {
1.1.1.2   misho     252:                if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
1.1       misho     253:                        free(list2);
                    254:                        return 1;
                    255:                }
                    256:        }
                    257: 
                    258:        free(list2);
                    259:        return 0;
                    260: }
                    261: 
1.1.1.2   misho     262: int allow_access(const char *addr, const char **host_ptr, int i)
1.1       misho     263: {
1.1.1.2   misho     264:        const char *allow_list = lp_hosts_allow(i);
                    265:        const char *deny_list = lp_hosts_deny(i);
                    266: 
1.1       misho     267:        if (allow_list && !*allow_list)
                    268:                allow_list = NULL;
                    269:        if (deny_list && !*deny_list)
                    270:                deny_list = NULL;
                    271: 
1.1.1.2   misho     272:        allow_forward_dns = lp_forward_lookup(i);
                    273: 
1.1       misho     274:        /* If we match an allow-list item, we always allow access. */
                    275:        if (allow_list) {
1.1.1.2   misho     276:                if (access_match(allow_list, addr, host_ptr))
1.1       misho     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. */
1.1.1.2   misho     285:        if (deny_list && access_match(deny_list, addr, host_ptr))
1.1       misho     286:                return 0;
                    287: 
                    288:        /* Allow all other access. */
                    289:        return 1;
                    290: }

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