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: }