jcs's openbsd hax
openbsd
at jcs 164 lines 4.4 kB view raw
1/* $OpenBSD: addrmatch.c,v 1.19 2026/02/14 00:18:34 jsg Exp $ */ 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 <netinet/in.h> 21 22#include <string.h> 23#include <stdlib.h> 24#include <stdio.h> 25#include <stdarg.h> 26 27#include "addr.h" 28#include "match.h" 29#include "log.h" 30 31/* 32 * Match "addr" against list pattern list "_list", which may contain a 33 * mix of CIDR addresses and old-school wildcards. 34 * 35 * If addr is NULL, then no matching is performed, but _list is parsed 36 * and checked for well-formedness. 37 * 38 * Returns 1 on match found (never returned when addr == NULL). 39 * Returns 0 on if no match found, or no errors found when addr == NULL. 40 * Returns -1 on negated match found (never returned when addr == NULL). 41 * Returns -2 on invalid list entry. 42 */ 43int 44addr_match_list(const char *addr, const char *_list) 45{ 46 char *list, *cp, *o; 47 struct xaddr try_addr, match_addr; 48 u_int masklen, neg; 49 int ret = 0, r; 50 51 if (addr != NULL && addr_pton(addr, &try_addr) != 0) { 52 debug2_f("couldn't parse address %.100s", addr); 53 return 0; 54 } 55 if ((o = list = strdup(_list)) == NULL) 56 return -1; 57 while ((cp = strsep(&list, ",")) != NULL) { 58 neg = *cp == '!'; 59 if (neg) 60 cp++; 61 if (*cp == '\0') { 62 ret = -2; 63 break; 64 } 65 /* Prefer CIDR address matching */ 66 r = addr_pton_cidr(cp, &match_addr, &masklen); 67 if (r == -2) { 68 debug2_f("inconsistent mask length for " 69 "match network \"%.100s\"", cp); 70 ret = -2; 71 break; 72 } else if (r == 0) { 73 if (addr != NULL && addr_netmatch(&try_addr, 74 &match_addr, masklen) == 0) { 75 foundit: 76 if (neg) { 77 ret = -1; 78 break; 79 } 80 ret = 1; 81 } 82 continue; 83 } else { 84 /* If CIDR parse failed, try wildcard string match */ 85 if (addr != NULL && match_pattern(addr, cp) == 1) 86 goto foundit; 87 } 88 } 89 free(o); 90 91 return ret; 92} 93 94/* 95 * Match "addr" against list CIDR list "_list". Lexical wildcards and 96 * negation are not supported. If "addr" == NULL, will verify structure 97 * of "_list". 98 * 99 * Returns 1 on match found (never returned when addr == NULL). 100 * Returns 0 on if no match found, or no errors found when addr == NULL. 101 * Returns -1 on error 102 */ 103int 104addr_match_cidr_list(const char *addr, const char *_list) 105{ 106 char *list, *cp, *o; 107 struct xaddr try_addr, match_addr; 108 u_int masklen; 109 int ret = 0, r; 110 111 if (addr != NULL && addr_pton(addr, &try_addr) != 0) { 112 debug2_f("couldn't parse address %.100s", addr); 113 return 0; 114 } 115 if ((o = list = strdup(_list)) == NULL) 116 return -1; 117 while ((cp = strsep(&list, ",")) != NULL) { 118 if (*cp == '\0') { 119 error_f("empty entry in list \"%.100s\"", o); 120 ret = -1; 121 break; 122 } 123 124 /* 125 * NB. This function is called in pre-auth with untrusted data, 126 * so be extra paranoid about junk reaching getaddrinfo (via 127 * addr_pton_cidr). 128 */ 129 130 /* Stop junk from reaching getaddrinfo. +3 is for masklen */ 131 if (strlen(cp) > INET6_ADDRSTRLEN + 3) { 132 error_f("list entry \"%.100s\" too long", cp); 133 ret = -1; 134 break; 135 } 136#define VALID_CIDR_CHARS "0123456789abcdefABCDEF.:/" 137 if (strspn(cp, VALID_CIDR_CHARS) != strlen(cp)) { 138 error_f("list entry \"%.100s\" contains invalid " 139 "characters", cp); 140 ret = -1; 141 } 142 143 /* Prefer CIDR address matching */ 144 r = addr_pton_cidr(cp, &match_addr, &masklen); 145 if (r == -1) { 146 error("Invalid network entry \"%.100s\"", cp); 147 ret = -1; 148 break; 149 } else if (r == -2) { 150 error("Inconsistent mask length for " 151 "network \"%.100s\"", cp); 152 ret = -1; 153 break; 154 } else if (r == 0 && addr != NULL) { 155 if (addr_netmatch(&try_addr, &match_addr, 156 masklen) == 0) 157 ret = 1; 158 continue; 159 } 160 } 161 free(o); 162 163 return ret; 164}