1 /* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 5 * Simple pattern matching, with '*' and '?' as wildcards. 6 * 7 * As far as I am concerned, the code I have written for this software 8 * can be used freely for any purpose. Any derived versions of this 9 * software must be clearly marked as such, and if the derived work is 10 * incompatible with the protocol description in the RFC file, it must be 11 * called by a name other than "ssh" or "Secure Shell". 12 */ 13 /* 14 * Copyright (c) 2000 Markus Friedl. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include "includes.h" 38 RCSID("$OpenBSD: match.c,v 1.14 2001/06/27 04:48:53 markus Exp $"); 39 40 #include "match.h" 41 #include "xmalloc.h" 42 43 /* 44 * Returns true if the given string matches the pattern (which may contain ? 45 * and * as wildcards), and zero if it does not match. 46 */ 47 48 int 49 match_pattern(const char *s, const char *pattern) 50 { 51 for (;;) { 52 /* If at end of pattern, accept if also at end of string. */ 53 if (!*pattern) 54 return !*s; 55 56 if (*pattern == '*') { 57 /* Skip the asterisk. */ 58 pattern++; 59 60 /* If at end of pattern, accept immediately. */ 61 if (!*pattern) 62 return 1; 63 64 /* If next character in pattern is known, optimize. */ 65 if (*pattern != '?' && *pattern != '*') { 66 /* 67 * Look instances of the next character in 68 * pattern, and try to match starting from 69 * those. 70 */ 71 for (; *s; s++) 72 if (*s == *pattern && 73 match_pattern(s + 1, pattern + 1)) 74 return 1; 75 /* Failed. */ 76 return 0; 77 } 78 /* 79 * Move ahead one character at a time and try to 80 * match at each position. 81 */ 82 for (; *s; s++) 83 if (match_pattern(s, pattern)) 84 return 1; 85 /* Failed. */ 86 return 0; 87 } 88 /* 89 * There must be at least one more character in the string. 90 * If we are at the end, fail. 91 */ 92 if (!*s) 93 return 0; 94 95 /* Check if the next character of the string is acceptable. */ 96 if (*pattern != '?' && *pattern != *s) 97 return 0; 98 99 /* Move to the next character, both in string and in pattern. */ 100 s++; 101 pattern++; 102 } 103 /* NOTREACHED */ 104 } 105 106 /* 107 * Tries to match the host name (which must be in all lowercase) against the 108 * comma-separated sequence of subpatterns (each possibly preceded by ! to 109 * indicate negation). Returns -1 if negation matches, 1 if there is 110 * a positive match, 0 if there is no match at all. 111 */ 112 113 int 114 match_hostname(const char *host, const char *pattern, u_int len) 115 { 116 char sub[1024]; 117 int negated; 118 int got_positive; 119 u_int i, subi; 120 121 got_positive = 0; 122 for (i = 0; i < len;) { 123 /* Check if the subpattern is negated. */ 124 if (pattern[i] == '!') { 125 negated = 1; 126 i++; 127 } else 128 negated = 0; 129 130 /* 131 * Extract the subpattern up to a comma or end. Convert the 132 * subpattern to lowercase. 133 */ 134 for (subi = 0; 135 i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; 136 subi++, i++) 137 sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i]; 138 /* If subpattern too long, return failure (no match). */ 139 if (subi >= sizeof(sub) - 1) 140 return 0; 141 142 /* If the subpattern was terminated by a comma, skip the comma. */ 143 if (i < len && pattern[i] == ',') 144 i++; 145 146 /* Null-terminate the subpattern. */ 147 sub[subi] = '\0'; 148 149 /* Try to match the subpattern against the host name. */ 150 if (match_pattern(host, sub)) { 151 if (negated) 152 return -1; /* Negative */ 153 else 154 got_positive = 1; /* Positive */ 155 } 156 } 157 158 /* 159 * Return success if got a positive match. If there was a negative 160 * match, we have already returned -1 and never get here. 161 */ 162 return got_positive; 163 } 164 165 /* 166 * returns 0 if we get a negative match for the hostname or the ip 167 * or if we get no match at all. returns 1 otherwise. 168 */ 169 int 170 match_host_and_ip(const char *host, const char *ipaddr, 171 const char *patterns) 172 { 173 int mhost, mip; 174 175 /* negative ipaddr match */ 176 if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1) 177 return 0; 178 /* negative hostname match */ 179 if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1) 180 return 0; 181 /* no match at all */ 182 if (mhost == 0 && mip == 0) 183 return 0; 184 return 1; 185 } 186 187 /* 188 * match user, user@host_or_ip, user@host_or_ip_list against pattern 189 */ 190 int 191 match_user(const char *user, const char *host, const char *ipaddr, 192 const char *pattern) 193 { 194 char *p, *pat; 195 int ret; 196 197 if ((p = strchr(pattern,'@')) == NULL) 198 return match_pattern(user, pattern); 199 200 pat = xstrdup(pattern); 201 p = strchr(pat, '@'); 202 *p++ = '\0'; 203 204 if ((ret = match_pattern(user, pat)) == 1) 205 ret = match_host_and_ip(host, ipaddr, p); 206 xfree(pat); 207 208 return ret; 209 } 210 211 /* 212 * Returns first item from client-list that is also supported by server-list, 213 * caller must xfree() returned string. 214 */ 215 #define MAX_PROP 20 216 #define SEP "," 217 char * 218 match_list(const char *client, const char *server, u_int *next) 219 { 220 char *sproposals[MAX_PROP]; 221 char *c, *s, *p, *ret, *cp, *sp; 222 int i, j, nproposals; 223 224 c = cp = xstrdup(client); 225 s = sp = xstrdup(server); 226 227 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; 228 (p = strsep(&sp, SEP)), i++) { 229 if (i < MAX_PROP) 230 sproposals[i] = p; 231 else 232 break; 233 } 234 nproposals = i; 235 236 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; 237 (p = strsep(&cp, SEP)), i++) { 238 for (j = 0; j < nproposals; j++) { 239 if (strcmp(p, sproposals[j]) == 0) { 240 ret = xstrdup(p); 241 if (next != NULL) 242 *next = (cp == NULL) ? 243 strlen(c) : cp - c; 244 xfree(c); 245 xfree(s); 246 return ret; 247 } 248 } 249 } 250 if (next != NULL) 251 *next = strlen(c); 252 xfree(c); 253 xfree(s); 254 return NULL; 255 } 256