source: trunk/third/openssh/match.c @ 18759

Revision 18759, 7.1 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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"
38RCSID("$OpenBSD: match.c,v 1.19 2002/03/01 13:12:10 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
48int
49match_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 string 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
113int
114match_pattern_list(const char *string, const char *pattern, u_int len,
115    int dolower)
116{
117        char sub[1024];
118        int negated;
119        int got_positive;
120        u_int i, subi;
121
122        got_positive = 0;
123        for (i = 0; i < len;) {
124                /* Check if the subpattern is negated. */
125                if (pattern[i] == '!') {
126                        negated = 1;
127                        i++;
128                } else
129                        negated = 0;
130
131                /*
132                 * Extract the subpattern up to a comma or end.  Convert the
133                 * subpattern to lowercase.
134                 */
135                for (subi = 0;
136                    i < len && subi < sizeof(sub) - 1 && pattern[i] != ',';
137                    subi++, i++)
138                        sub[subi] = dolower && isupper(pattern[i]) ?
139                            tolower(pattern[i]) : pattern[i];
140                /* If subpattern too long, return failure (no match). */
141                if (subi >= sizeof(sub) - 1)
142                        return 0;
143
144                /* If the subpattern was terminated by a comma, skip the comma. */
145                if (i < len && pattern[i] == ',')
146                        i++;
147
148                /* Null-terminate the subpattern. */
149                sub[subi] = '\0';
150
151                /* Try to match the subpattern against the string. */
152                if (match_pattern(string, sub)) {
153                        if (negated)
154                                return -1;              /* Negative */
155                        else
156                                got_positive = 1;       /* Positive */
157                }
158        }
159
160        /*
161         * Return success if got a positive match.  If there was a negative
162         * match, we have already returned -1 and never get here.
163         */
164        return got_positive;
165}
166
167/*
168 * Tries to match the host name (which must be in all lowercase) against the
169 * comma-separated sequence of subpatterns (each possibly preceded by ! to
170 * indicate negation).  Returns -1 if negation matches, 1 if there is
171 * a positive match, 0 if there is no match at all.
172 */
173int
174match_hostname(const char *host, const char *pattern, u_int len)
175{
176        return match_pattern_list(host, pattern, len, 1);
177}
178
179/*
180 * returns 0 if we get a negative match for the hostname or the ip
181 * or if we get no match at all.  returns 1 otherwise.
182 */
183int
184match_host_and_ip(const char *host, const char *ipaddr,
185    const char *patterns)
186{
187        int mhost, mip;
188
189        /* negative ipaddr match */
190        if ((mip = match_hostname(ipaddr, patterns, strlen(patterns))) == -1)
191                return 0;
192        /* negative hostname match */
193        if ((mhost = match_hostname(host, patterns, strlen(patterns))) == -1)
194                return 0;
195        /* no match at all */
196        if (mhost == 0 && mip == 0)
197                return 0;
198        return 1;
199}
200
201/*
202 * match user, user@host_or_ip, user@host_or_ip_list against pattern
203 */
204int
205match_user(const char *user, const char *host, const char *ipaddr,
206    const char *pattern)
207{
208        char *p, *pat;
209        int ret;
210
211        if ((p = strchr(pattern,'@')) == NULL)
212                return match_pattern(user, pattern);
213
214        pat = xstrdup(pattern);
215        p = strchr(pat, '@');
216        *p++ = '\0';
217
218        if ((ret = match_pattern(user, pat)) == 1)
219                ret = match_host_and_ip(host, ipaddr, p);
220        xfree(pat);
221
222        return ret;
223}
224
225/*
226 * Returns first item from client-list that is also supported by server-list,
227 * caller must xfree() returned string.
228 */
229#define MAX_PROP        40
230#define SEP     ","
231char *
232match_list(const char *client, const char *server, u_int *next)
233{
234        char *sproposals[MAX_PROP];
235        char *c, *s, *p, *ret, *cp, *sp;
236        int i, j, nproposals;
237
238        c = cp = xstrdup(client);
239        s = sp = xstrdup(server);
240
241        for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
242            (p = strsep(&sp, SEP)), i++) {
243                if (i < MAX_PROP)
244                        sproposals[i] = p;
245                else
246                        break;
247        }
248        nproposals = i;
249
250        for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
251            (p = strsep(&cp, SEP)), i++) {
252                for (j = 0; j < nproposals; j++) {
253                        if (strcmp(p, sproposals[j]) == 0) {
254                                ret = xstrdup(p);
255                                if (next != NULL)
256                                        *next = (cp == NULL) ?
257                                            strlen(c) : cp - c;
258                                xfree(c);
259                                xfree(s);
260                                return ret;
261                        }
262                }
263        }
264        if (next != NULL)
265                *next = strlen(c);
266        xfree(c);
267        xfree(s);
268        return NULL;
269}
Note: See TracBrowser for help on using the repository browser.