match.c revision 60573
157429Smarkm/* 260573Skris * 357429Smarkm * match.c 460573Skris * 557429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 660573Skris * 757429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 857429Smarkm * All rights reserved 960573Skris * 1057429Smarkm * Created: Thu Jun 22 01:17:50 1995 ylo 1160573Skris * 1257429Smarkm * Simple pattern matching, with '*' and '?' as wildcards. 1360573Skris * 1457429Smarkm */ 1557429Smarkm 1657429Smarkm#include "includes.h" 1760573SkrisRCSID("$Id: match.c,v 1.6 2000/04/14 10:30:31 markus Exp $"); 1857429Smarkm 1957429Smarkm#include "ssh.h" 2057429Smarkm 2157429Smarkm/* 2257429Smarkm * Returns true if the given string matches the pattern (which may contain ? 2357429Smarkm * and * as wildcards), and zero if it does not match. 2457429Smarkm */ 2557429Smarkm 2660573Skrisint 2757429Smarkmmatch_pattern(const char *s, const char *pattern) 2857429Smarkm{ 2957429Smarkm for (;;) { 3057429Smarkm /* If at end of pattern, accept if also at end of string. */ 3157429Smarkm if (!*pattern) 3257429Smarkm return !*s; 3357429Smarkm 3457429Smarkm if (*pattern == '*') { 3557429Smarkm /* Skip the asterisk. */ 3657429Smarkm pattern++; 3757429Smarkm 3857429Smarkm /* If at end of pattern, accept immediately. */ 3957429Smarkm if (!*pattern) 4057429Smarkm return 1; 4157429Smarkm 4257429Smarkm /* If next character in pattern is known, optimize. */ 4357429Smarkm if (*pattern != '?' && *pattern != '*') { 4457429Smarkm /* 4557429Smarkm * Look instances of the next character in 4657429Smarkm * pattern, and try to match starting from 4757429Smarkm * those. 4857429Smarkm */ 4957429Smarkm for (; *s; s++) 5057429Smarkm if (*s == *pattern && 5157429Smarkm match_pattern(s + 1, pattern + 1)) 5257429Smarkm return 1; 5357429Smarkm /* Failed. */ 5457429Smarkm return 0; 5557429Smarkm } 5657429Smarkm /* 5757429Smarkm * Move ahead one character at a time and try to 5857429Smarkm * match at each position. 5957429Smarkm */ 6057429Smarkm for (; *s; s++) 6157429Smarkm if (match_pattern(s, pattern)) 6257429Smarkm return 1; 6357429Smarkm /* Failed. */ 6457429Smarkm return 0; 6557429Smarkm } 6657429Smarkm /* 6757429Smarkm * There must be at least one more character in the string. 6857429Smarkm * If we are at the end, fail. 6957429Smarkm */ 7057429Smarkm if (!*s) 7157429Smarkm return 0; 7257429Smarkm 7357429Smarkm /* Check if the next character of the string is acceptable. */ 7457429Smarkm if (*pattern != '?' && *pattern != *s) 7557429Smarkm return 0; 7657429Smarkm 7757429Smarkm /* Move to the next character, both in string and in pattern. */ 7857429Smarkm s++; 7957429Smarkm pattern++; 8057429Smarkm } 8157429Smarkm /* NOTREACHED */ 8257429Smarkm} 8358582Skris 8458582Skris/* 8558582Skris * Tries to match the host name (which must be in all lowercase) against the 8658582Skris * comma-separated sequence of subpatterns (each possibly preceded by ! to 8758582Skris * indicate negation). Returns true if there is a positive match; zero 8858582Skris * otherwise. 8958582Skris */ 9058582Skris 9158582Skrisint 9258582Skrismatch_hostname(const char *host, const char *pattern, unsigned int len) 9358582Skris{ 9458582Skris char sub[1024]; 9558582Skris int negated; 9658582Skris int got_positive; 9758582Skris unsigned int i, subi; 9858582Skris 9958582Skris got_positive = 0; 10058582Skris for (i = 0; i < len;) { 10158582Skris /* Check if the subpattern is negated. */ 10258582Skris if (pattern[i] == '!') { 10358582Skris negated = 1; 10458582Skris i++; 10558582Skris } else 10658582Skris negated = 0; 10758582Skris 10858582Skris /* 10958582Skris * Extract the subpattern up to a comma or end. Convert the 11058582Skris * subpattern to lowercase. 11158582Skris */ 11258582Skris for (subi = 0; 11358582Skris i < len && subi < sizeof(sub) - 1 && pattern[i] != ','; 11458582Skris subi++, i++) 11558582Skris sub[subi] = isupper(pattern[i]) ? tolower(pattern[i]) : pattern[i]; 11658582Skris /* If subpattern too long, return failure (no match). */ 11758582Skris if (subi >= sizeof(sub) - 1) 11858582Skris return 0; 11958582Skris 12058582Skris /* If the subpattern was terminated by a comma, skip the comma. */ 12158582Skris if (i < len && pattern[i] == ',') 12258582Skris i++; 12358582Skris 12458582Skris /* Null-terminate the subpattern. */ 12558582Skris sub[subi] = '\0'; 12658582Skris 12758582Skris /* Try to match the subpattern against the host name. */ 12858582Skris if (match_pattern(host, sub)) { 12958582Skris if (negated) 13058582Skris return 0; /* Fail */ 13158582Skris else 13258582Skris got_positive = 1; 13358582Skris } 13458582Skris } 13558582Skris 13658582Skris /* 13758582Skris * Return success if got a positive match. If there was a negative 13858582Skris * match, we have already returned zero and never get here. 13958582Skris */ 14058582Skris return got_positive; 14158582Skris} 142