match.c revision 1.22
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 39#include <ctype.h> 40 41#include "match.h" 42#include "xmalloc.h" 43 44/* 45 * Returns true if the given string matches the pattern (which may contain ? 46 * and * as wildcards), and zero if it does not match. 47 */ 48 49int 50match_pattern(const char *s, const char *pattern) 51{ 52 for (;;) { 53 /* If at end of pattern, accept if also at end of string. */ 54 if (!*pattern) 55 return !*s; 56 57 if (*pattern == '*') { 58 /* Skip the asterisk. */ 59 pattern++; 60 61 /* If at end of pattern, accept immediately. */ 62 if (!*pattern) 63 return 1; 64 65 /* If next character in pattern is known, optimize. */ 66 if (*pattern != '?' && *pattern != '*') { 67 /* 68 * Look instances of the next character in 69 * pattern, and try to match starting from 70 * those. 71 */ 72 for (; *s; s++) 73 if (*s == *pattern && 74 match_pattern(s + 1, pattern + 1)) 75 return 1; 76 /* Failed. */ 77 return 0; 78 } 79 /* 80 * Move ahead one character at a time and try to 81 * match at each position. 82 */ 83 for (; *s; s++) 84 if (match_pattern(s, pattern)) 85 return 1; 86 /* Failed. */ 87 return 0; 88 } 89 /* 90 * There must be at least one more character in the string. 91 * If we are at the end, fail. 92 */ 93 if (!*s) 94 return 0; 95 96 /* Check if the next character of the string is acceptable. */ 97 if (*pattern != '?' && *pattern != *s) 98 return 0; 99 100 /* Move to the next character, both in string and in pattern. */ 101 s++; 102 pattern++; 103 } 104 /* NOTREACHED */ 105} 106 107/* 108 * Tries to match the string against the 109 * comma-separated sequence of subpatterns (each possibly preceded by ! to 110 * indicate negation). Returns -1 if negation matches, 1 if there is 111 * a positive match, 0 if there is no match at all. 112 */ 113 114int 115match_pattern_list(const char *string, const char *pattern, u_int len, 116 int dolower) 117{ 118 char sub[1024]; 119 int negated; 120 int got_positive; 121 u_int i, subi; 122 123 got_positive = 0; 124 for (i = 0; i < len;) { 125 /* Check if the subpattern is negated. */ 126 if (pattern[i] == '!') { 127 negated = 1; 128 i++; 129 } else 130 negated = 0; 131 132 /* 133 * Extract the subpattern up to a comma or end. Convert the 134 * subpattern to lowercase. 135 */ 136 for (subi = 0; 137 i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; 138 subi++, i++) 139 sub[subi] = dolower && isupper(pattern[i]) ? 140 tolower(pattern[i]) : pattern[i]; 141 /* If subpattern too long, return failure (no match). */ 142 if (subi >= sizeof(sub) - 1) 143 return 0; 144 145 /* If the subpattern was terminated by a comma, skip the comma. */ 146 if (i < len && pattern[i] == ',') 147 i++; 148 149 /* Null-terminate the subpattern. */ 150 sub[subi] = '\0'; 151 152 /* Try to match the subpattern against the string. */ 153 if (match_pattern(string, sub)) { 154 if (negated) 155 return -1; /* Negative */ 156 else 157 got_positive = 1; /* Positive */ 158 } 159 } 160 161 /* 162 * Return success if got a positive match. If there was a negative 163 * match, we have already returned -1 and never get here. 164 */ 165 return got_positive; 166} 167 168/* 169 * Tries to match the host name (which must be in all lowercase) against the 170 * comma-separated sequence of subpatterns (each possibly preceded by ! to 171 * indicate negation). Returns -1 if negation matches, 1 if there is 172 * a positive match, 0 if there is no match at all. 173 */ 174int 175match_hostname(const char *host, const char *pattern, u_int len) 176{ 177 return match_pattern_list(host, pattern, len, 1); 178} 179 180/* 181 * returns 0 if we get a negative match for the hostname or the ip 182 * or if we get no match at all. returns 1 otherwise. 183 */ 184int 185match_host_and_ip(const char *host, const char *ipaddr, 186 const char *patterns) 187{ 188 int mhost, mip; 189 190 /* negative ipaddr match */ 191 if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1) 192 return 0; 193 /* negative hostname match */ 194 if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1) 195 return 0; 196 /* no match at all */ 197 if (mhost == 0 && mip == 0) 198 return 0; 199 return 1; 200} 201 202/* 203 * match user, user@host_or_ip, user@host_or_ip_list against pattern 204 */ 205int 206match_user(const char *user, const char *host, const char *ipaddr, 207 const char *pattern) 208{ 209 char *p, *pat; 210 int ret; 211 212 if ((p = strchr(pattern,'@')) == NULL) 213 return match_pattern(user, pattern); 214 215 pat = xstrdup(pattern); 216 p = strchr(pat, '@'); 217 *p++ = '\0'; 218 219 if ((ret = match_pattern(user, pat)) == 1) 220 ret = match_host_and_ip(host, ipaddr, p); 221 xfree(pat); 222 223 return ret; 224} 225 226/* 227 * Returns first item from client-list that is also supported by server-list, 228 * caller must xfree() returned string. 229 */ 230#define MAX_PROP 40 231#define SEP "," 232char * 233match_list(const char *client, const char *server, u_int *next) 234{ 235 char *sproposals[MAX_PROP]; 236 char *c, *s, *p, *ret, *cp, *sp; 237 int i, j, nproposals; 238 239 c = cp = xstrdup(client); 240 s = sp = xstrdup(server); 241 242 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; 243 (p = strsep(&sp, SEP)), i++) { 244 if (i < MAX_PROP) 245 sproposals[i] = p; 246 else 247 break; 248 } 249 nproposals = i; 250 251 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; 252 (p = strsep(&cp, SEP)), i++) { 253 for (j = 0; j < nproposals; j++) { 254 if (strcmp(p, sproposals[j]) == 0) { 255 ret = xstrdup(p); 256 if (next != NULL) 257 *next = (cp == NULL) ? 258 strlen(c) : (u_int)(cp - c); 259 xfree(c); 260 xfree(s); 261 return ret; 262 } 263 } 264 } 265 if (next != NULL) 266 *next = strlen(c); 267 xfree(c); 268 xfree(s); 269 return NULL; 270} 271