[BACK]Return to addrmatch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/addrmatch.c, Revision 1.16

1.16    ! dtucker     1: /*     $OpenBSD: addrmatch.c,v 1.15 2020/10/18 11:32:01 djm Exp $ */
1.1       djm         2:
                      3: /*
                      4:  * Copyright (c) 2004-2008 Damien Miller <djm@mindrot.org>
                      5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
                     18:
                     19: #include <sys/types.h>
                     20: #include <sys/socket.h>
                     21: #include <netinet/in.h>
                     22: #include <arpa/inet.h>
                     23:
                     24: #include <netdb.h>
                     25: #include <string.h>
                     26: #include <stdlib.h>
                     27: #include <stdio.h>
                     28: #include <stdarg.h>
                     29:
1.16    ! dtucker    30: #include "addr.h"
1.1       djm        31: #include "match.h"
                     32: #include "log.h"
                     33:
                     34: /*
                     35:  * Match "addr" against list pattern list "_list", which may contain a
                     36:  * mix of CIDR addresses and old-school wildcards.
                     37:  *
                     38:  * If addr is NULL, then no matching is performed, but _list is parsed
                     39:  * and checked for well-formedness.
                     40:  *
                     41:  * Returns 1 on match found (never returned when addr == NULL).
                     42:  * Returns 0 on if no match found, or no errors found when addr == NULL.
1.3       djm        43:  * Returns -1 on negated match found (never returned when addr == NULL).
                     44:  * Returns -2 on invalid list entry.
1.1       djm        45:  */
                     46: int
                     47: addr_match_list(const char *addr, const char *_list)
                     48: {
                     49:        char *list, *cp, *o;
                     50:        struct xaddr try_addr, match_addr;
                     51:        u_int masklen, neg;
                     52:        int ret = 0, r;
                     53:
1.2       djm        54:        if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
1.15      djm        55:                debug2_f("couldn't parse address %.100s", addr);
1.2       djm        56:                return 0;
                     57:        }
1.1       djm        58:        if ((o = list = strdup(_list)) == NULL)
                     59:                return -1;
                     60:        while ((cp = strsep(&list, ",")) != NULL) {
                     61:                neg = *cp == '!';
                     62:                if (neg)
                     63:                        cp++;
                     64:                if (*cp == '\0') {
1.3       djm        65:                        ret = -2;
1.1       djm        66:                        break;
                     67:                }
                     68:                /* Prefer CIDR address matching */
                     69:                r = addr_pton_cidr(cp, &match_addr, &masklen);
                     70:                if (r == -2) {
1.15      djm        71:                        debug2_f("inconsistent mask length for "
                     72:                            "match network \"%.100s\"", cp);
1.3       djm        73:                        ret = -2;
1.1       djm        74:                        break;
                     75:                } else if (r == 0) {
                     76:                        if (addr != NULL && addr_netmatch(&try_addr,
                     77:                            &match_addr, masklen) == 0) {
                     78:  foundit:
                     79:                                if (neg) {
1.3       djm        80:                                        ret = -1;
1.1       djm        81:                                        break;
                     82:                                }
                     83:                                ret = 1;
1.13      djm        84:                        }
1.1       djm        85:                        continue;
                     86:                } else {
                     87:                        /* If CIDR parse failed, try wildcard string match */
                     88:                        if (addr != NULL && match_pattern(addr, cp) == 1)
                     89:                                goto foundit;
1.5       djm        90:                }
                     91:        }
1.7       djm        92:        free(o);
1.5       djm        93:
                     94:        return ret;
                     95: }
                     96:
                     97: /*
                     98:  * Match "addr" against list CIDR list "_list". Lexical wildcards and
                     99:  * negation are not supported. If "addr" == NULL, will verify structure
                    100:  * of "_list".
                    101:  *
                    102:  * Returns 1 on match found (never returned when addr == NULL).
                    103:  * Returns 0 on if no match found, or no errors found when addr == NULL.
                    104:  * Returns -1 on error
                    105:  */
                    106: int
                    107: addr_match_cidr_list(const char *addr, const char *_list)
                    108: {
                    109:        char *list, *cp, *o;
                    110:        struct xaddr try_addr, match_addr;
                    111:        u_int masklen;
                    112:        int ret = 0, r;
                    113:
                    114:        if (addr != NULL && addr_pton(addr, &try_addr) != 0) {
1.15      djm       115:                debug2_f("couldn't parse address %.100s", addr);
1.5       djm       116:                return 0;
                    117:        }
                    118:        if ((o = list = strdup(_list)) == NULL)
                    119:                return -1;
                    120:        while ((cp = strsep(&list, ",")) != NULL) {
                    121:                if (*cp == '\0') {
1.15      djm       122:                        error_f("empty entry in list \"%.100s\"", o);
1.5       djm       123:                        ret = -1;
                    124:                        break;
                    125:                }
                    126:
                    127:                /*
                    128:                 * NB. This function is called in pre-auth with untrusted data,
                    129:                 * so be extra paranoid about junk reaching getaddrino (via
                    130:                 * addr_pton_cidr).
                    131:                 */
                    132:
                    133:                /* Stop junk from reaching getaddrinfo. +3 is for masklen */
                    134:                if (strlen(cp) > INET6_ADDRSTRLEN + 3) {
1.15      djm       135:                        error_f("list entry \"%.100s\" too long", cp);
1.5       djm       136:                        ret = -1;
                    137:                        break;
                    138:                }
                    139: #define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/"
                    140:                if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) {
1.15      djm       141:                        error_f("list entry \"%.100s\" contains invalid "
                    142:                            "characters", cp);
1.5       djm       143:                        ret = -1;
                    144:                }
                    145:
                    146:                /* Prefer CIDR address matching */
                    147:                r = addr_pton_cidr(cp, &match_addr, &masklen);
                    148:                if (r == -1) {
                    149:                        error("Invalid network entry \"%.100s\"", cp);
                    150:                        ret = -1;
                    151:                        break;
                    152:                } else if (r == -2) {
                    153:                        error("Inconsistent mask length for "
                    154:                            "network \"%.100s\"", cp);
                    155:                        ret = -1;
                    156:                        break;
                    157:                } else if (r == 0 && addr != NULL) {
                    158:                        if (addr_netmatch(&try_addr, &match_addr,
                    159:                            masklen) == 0)
                    160:                                ret = 1;
                    161:                        continue;
1.1       djm       162:                }
                    163:        }
1.7       djm       164:        free(o);
1.1       djm       165:
                    166:        return ret;
                    167: }