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.12 2001/03/10 17:51:04 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 #define MAX_PROP 20 167 #define SEP "," 168 char * 169 match_list(const char *client, const char *server, u_int *next) 170 { 171 char *sproposals[MAX_PROP]; 172 char *c, *s, *p, *ret, *cp, *sp; 173 int i, j, nproposals; 174 175 c = cp = xstrdup(client); 176 s = sp = xstrdup(server); 177 178 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0'; 179 (p = strsep(&sp, SEP)), i++) { 180 if (i < MAX_PROP) 181 sproposals[i] = p; 182 else 183 break; 184 } 185 nproposals = i; 186 187 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0'; 188 (p = strsep(&cp, SEP)), i++) { 189 for (j = 0; j < nproposals; j++) { 190 if (strcmp(p, sproposals[j]) == 0) { 191 ret = xstrdup(p); 192 if (next != NULL) 193 *next = (cp == NULL) ? 194 strlen(c) : cp - c; 195 xfree(c); 196 xfree(s); 197 return ret; 198 } 199 } 200 } 201 if (next != NULL) 202 *next = strlen(c); 203 xfree(c); 204 xfree(s); 205 return NULL; 206 } 207