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

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.4 ! misho       5:  * Copyright (C) 2004-2020 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"
1.1.1.4 ! misho      22: #include "ifuncs.h"
1.1       misho      23: 
1.1.1.2   misho      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)
1.1       misho      29: {
1.1.1.2   misho      30:        struct hostent *hp;
                     31:        unsigned int i;
                     32:        const char *host = *host_ptr;
                     33: 
1.1       misho      34:        if (!host || !*host)
                     35:                return 0;
1.1.1.2   misho      36: 
1.1.1.4 ! misho      37: #ifdef HAVE_INNETGR
        !            38:        if (*tok == '@' && tok[1])
        !            39:                return innetgr(tok + 1, host, NULL, NULL);
        !            40: #endif
        !            41: 
1.1.1.2   misho      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. */
1.1.1.4 ! misho      61:                        if (host == undetermined_hostname)
        !            62:                                *host_ptr = strdup(tok);
1.1.1.2   misho      63:                        return 1;
                     64:                }
                     65:        }
                     66: 
                     67:        return 0;
1.1       misho      68: }
                     69: 
1.1.1.2   misho      70: static int match_binary(const char *b1, const char *b2, const char *mask, int addrlen)
1.1       misho      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: 
1.1.1.2   misho      99: static int match_address(const char *addr, const char *tok)
1.1       misho     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,'/');
1.1.1.2   misho     118:        if (p)
1.1       misho     119:                *p = '\0';
                    120: 
1.1.1.2   misho     121:        /* Fail quietly if tok is a hostname, not an address. */
                    122:        if (tok[strspn(tok, ".0123456789")] && strchr(tok, ':') == NULL) {
1.1       misho     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
1.1.1.4 ! misho     165:        case PF_INET6: {
1.1       misho     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
1.1.1.4 ! misho     177:                if (sin6t->sin6_scope_id && sin6a->sin6_scope_id != sin6t->sin6_scope_id) {
1.1       misho     178:                        ret = 0;
                    179:                        goto out;
                    180:                }
                    181: #endif
                    182: 
                    183:                break;
1.1.1.4 ! misho     184:        }
1.1       misho     185: #endif
                    186:        default:
1.1.1.4 ! misho     187:                rprintf(FLOG, "unknown family %u\n", rest->ai_family);
        !           188:                ret = 0;
        !           189:                goto out;
1.1       misho     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: 
1.1.1.2   misho     243: static int access_match(const char *list, const char *addr, const char **host_ptr)
1.1       misho     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")) {
1.1.1.2   misho     251:                if (match_hostname(host_ptr, addr, tok) || match_address(addr, tok)) {
1.1       misho     252:                        free(list2);
                    253:                        return 1;
                    254:                }
                    255:        }
                    256: 
                    257:        free(list2);
                    258:        return 0;
                    259: }
                    260: 
1.1.1.2   misho     261: int allow_access(const char *addr, const char **host_ptr, int i)
1.1       misho     262: {
1.1.1.2   misho     263:        const char *allow_list = lp_hosts_allow(i);
                    264:        const char *deny_list = lp_hosts_deny(i);
                    265: 
1.1       misho     266:        if (allow_list && !*allow_list)
                    267:                allow_list = NULL;
                    268:        if (deny_list && !*deny_list)
                    269:                deny_list = NULL;
                    270: 
1.1.1.2   misho     271:        allow_forward_dns = lp_forward_lookup(i);
                    272: 
1.1       misho     273:        /* If we match an allow-list item, we always allow access. */
                    274:        if (allow_list) {
1.1.1.2   misho     275:                if (access_match(allow_list, addr, host_ptr))
1.1       misho     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. */
1.1.1.2   misho     284:        if (deny_list && access_match(deny_list, addr, host_ptr))
1.1       misho     285:                return 0;
                    286: 
                    287:        /* Allow all other access. */
                    288:        return 1;
                    289: }

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