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

Revision 16801, 6.7 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16800, 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.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
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 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
113int
114match_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 */
169int
170match_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 */
190int
191match_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     ","
217char *
218match_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}
Note: See TracBrowser for help on using the repository browser.