Annotation of src/usr.bin/ssh/match.c, Revision 1.22
1.1 deraadt 1: /*
1.3 deraadt 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.
1.6 markus 6: *
1.9 deraadt 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".
1.3 deraadt 12: */
1.12 markus 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: */
1.1 deraadt 36:
37: #include "includes.h"
1.21 stevesk 38:
39: #include <ctype.h>
1.1 deraadt 40:
1.11 markus 41: #include "match.h"
1.12 markus 42: #include "xmalloc.h"
1.1 deraadt 43:
1.4 markus 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: */
1.2 markus 48:
1.6 markus 49: int
1.2 markus 50: match_pattern(const char *s, const char *pattern)
1.1 deraadt 51: {
1.2 markus 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 != '*') {
1.4 markus 67: /*
68: * Look instances of the next character in
69: * pattern, and try to match starting from
70: * those.
71: */
1.2 markus 72: for (; *s; s++)
73: if (*s == *pattern &&
74: match_pattern(s + 1, pattern + 1))
75: return 1;
76: /* Failed. */
77: return 0;
78: }
1.4 markus 79: /*
80: * Move ahead one character at a time and try to
81: * match at each position.
82: */
1.2 markus 83: for (; *s; s++)
84: if (match_pattern(s, pattern))
85: return 1;
86: /* Failed. */
87: return 0;
88: }
1.4 markus 89: /*
90: * There must be at least one more character in the string.
91: * If we are at the end, fail.
92: */
1.2 markus 93: if (!*s)
94: return 0;
95:
1.4 markus 96: /* Check if the next character of the string is acceptable. */
1.2 markus 97: if (*pattern != '?' && *pattern != *s)
98: return 0;
99:
1.4 markus 100: /* Move to the next character, both in string and in pattern. */
1.2 markus 101: s++;
102: pattern++;
103: }
104: /* NOTREACHED */
1.5 markus 105: }
106:
107: /*
1.15 markus 108: * Tries to match the string against the
1.5 markus 109: * comma-separated sequence of subpatterns (each possibly preceded by ! to
1.7 markus 110: * indicate negation). Returns -1 if negation matches, 1 if there is
111: * a positive match, 0 if there is no match at all.
1.5 markus 112: */
113:
114: int
1.15 markus 115: match_pattern_list(const char *string, const char *pattern, u_int len,
116: int dolower)
1.5 markus 117: {
118: char sub[1024];
119: int negated;
120: int got_positive;
1.10 markus 121: u_int i, subi;
1.5 markus 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;
1.16 deraadt 137: i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
138: subi++, i++)
1.15 markus 139: sub[subi] = dolower && isupper(pattern[i]) ?
1.16 deraadt 140: tolower(pattern[i]) : pattern[i];
1.5 markus 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:
1.15 markus 152: /* Try to match the subpattern against the string. */
153: if (match_pattern(string, sub)) {
1.5 markus 154: if (negated)
1.7 markus 155: return -1; /* Negative */
1.5 markus 156: else
1.7 markus 157: got_positive = 1; /* Positive */
1.5 markus 158: }
159: }
160:
161: /*
162: * Return success if got a positive match. If there was a negative
1.7 markus 163: * match, we have already returned -1 and never get here.
1.5 markus 164: */
165: return got_positive;
1.15 markus 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: */
174: int
175: match_hostname(const char *host, const char *pattern, u_int len)
176: {
177: return match_pattern_list(host, pattern, len, 1);
1.12 markus 178: }
179:
1.13 markus 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: */
184: int
185: match_host_and_ip(const char *host, const char *ipaddr,
186: const char *patterns)
187: {
188: int mhost, mip;
1.12 markus 189:
1.13 markus 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;
1.14 markus 200: }
201:
202: /*
203: * match user, user@host_or_ip, user@host_or_ip_list against pattern
204: */
205: int
1.19 markus 206: match_user(const char *user, const char *host, const char *ipaddr,
1.14 markus 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)
1.19 markus 220: ret = match_host_and_ip(host, ipaddr, p);
1.14 markus 221: xfree(pat);
222:
223: return ret;
1.13 markus 224: }
225:
226: /*
227: * Returns first item from client-list that is also supported by server-list,
228: * caller must xfree() returned string.
229: */
1.17 markus 230: #define MAX_PROP 40
1.12 markus 231: #define SEP ","
232: char *
233: match_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';
1.16 deraadt 243: (p = strsep(&sp, SEP)), i++) {
1.12 markus 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';
1.16 deraadt 252: (p = strsep(&cp, SEP)), i++) {
1.12 markus 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) ?
1.20 djm 258: strlen(c) : (u_int)(cp - c);
1.12 markus 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;
1.1 deraadt 270: }