diff options
Diffstat (limited to 'crypto/openssh/match.c')
-rw-r--r-- | crypto/openssh/match.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/crypto/openssh/match.c b/crypto/openssh/match.c new file mode 100644 index 0000000..c373129 --- /dev/null +++ b/crypto/openssh/match.c @@ -0,0 +1,139 @@ +/* + * Author: Tatu Ylonen <ylo@cs.hut.fi> + * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland + * All rights reserved + * Simple pattern matching, with '*' and '?' as wildcards. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ + +#include "includes.h" +RCSID("$OpenBSD: match.c,v 1.9 2000/09/07 20:27:52 deraadt Exp $"); + +#include "ssh.h" + +/* + * Returns true if the given string matches the pattern (which may contain ? + * and * as wildcards), and zero if it does not match. + */ + +int +match_pattern(const char *s, const char *pattern) +{ + for (;;) { + /* If at end of pattern, accept if also at end of string. */ + if (!*pattern) + return !*s; + + if (*pattern == '*') { + /* Skip the asterisk. */ + pattern++; + + /* If at end of pattern, accept immediately. */ + if (!*pattern) + return 1; + + /* If next character in pattern is known, optimize. */ + if (*pattern != '?' && *pattern != '*') { + /* + * Look instances of the next character in + * pattern, and try to match starting from + * those. + */ + for (; *s; s++) + if (*s == *pattern && + match_pattern(s + 1, pattern + 1)) + return 1; + /* Failed. */ + return 0; + } + /* + * Move ahead one character at a time and try to + * match at each position. + */ + for (; *s; s++) + if (match_pattern(s, pattern)) + return 1; + /* Failed. */ + return 0; + } + /* + * There must be at least one more character in the string. + * If we are at the end, fail. + */ + if (!*s) + return 0; + + /* Check if the next character of the string is acceptable. */ + if (*pattern != '?' && *pattern != *s) + return 0; + + /* Move to the next character, both in string and in pattern. */ + s++; + pattern++; + } + /* NOTREACHED */ +} + +/* + * Tries to match the host name (which must be in all lowercase) against the + * comma-separated sequence of subpatterns (each possibly preceded by ! to + * indicate negation). Returns -1 if negation matches, 1 if there is + * a positive match, 0 if there is no match at all. + */ + +int +match_hostname(const char *host, const char *pattern, unsigned int len) +{ + char sub[1024]; + int negated; + int got_positive; + unsigned int i, subi; + + got_positive = 0; + for (i = 0; i < len;) { + /* Check if the subpattern is negated. */ + if (pattern[i] == '!') { + negated = 1; + i++; + } else + negated = 0; + + /* + * Extract the subpattern up to a comma or end. Convert the + * subpattern to lowercase. + */ + for (subi = 0; + i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; + subi++, i++) + sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i]; + /* If subpattern too long, return failure (no match). */ + if (subi >= sizeof(sub) - 1) + return 0; + + /* If the subpattern was terminated by a comma, skip the comma. */ + if (i < len && pattern[i] == ',') + i++; + + /* Null-terminate the subpattern. */ + sub[subi] = '\0'; + + /* Try to match the subpattern against the host name. */ + if (match_pattern(host, sub)) { + if (negated) + return -1; /* Negative */ + else + got_positive = 1; /* Positive */ + } + } + + /* + * Return success if got a positive match. If there was a negative + * match, we have already returned -1 and never get here. + */ + return got_positive; +} |