X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/212380e3f42f585dc1ea927402252eb943f91f7b..d25c6eb1b223d1a0993dde9a28c97ef95e54bceb:/src/match.c diff --git a/src/match.c b/src/match.c index 6b13f82..a0509c4 100644 --- a/src/match.c +++ b/src/match.c @@ -16,14 +16,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: match.c 708 2006-02-05 22:44:03Z jilles $ + * $Id: match.c 3532 2007-07-14 13:32:18Z jilles $ * */ #include "stdinc.h" #include "config.h" #include "client.h" #include "ircd.h" -#include "irc_string.h" +#include "match.h" /* * Compare if a given string (name) matches the given @@ -105,20 +105,18 @@ int match(const char *mask, const char *name) } } -/** Check a string against a mask. +/** Check a mask against a mask. * This test checks using traditional IRC wildcards only: '*' means * match zero or more characters of any type; '?' means match exactly - * one character of any type; '#' means match exactly one character - * that is a number. - * - * This function supports escaping, so that a wildcard may be matched - * exactly. + * one character of any type. + * The difference between mask_match() and match() is that in mask_match() + * a '?' in mask does not match a '*' in name. * - * @param[in] mask Wildcard-containing mask. - * @param[in] name String to check against \a mask. - * @return Zero if \a mask matches \a name, non-zero if no match. + * @param[in] mask Existing wildcard-containing mask. + * @param[in] name New wildcard-containing mask. + * @return 1 if \a name is equal to or more specific than \a mask, 0 otherwise. */ -int match_esc(const char *mask, const char *name) +int mask_match(const char *mask, const char *name) { const char *m = mask, *n = name; const char *m_tmp = mask, *n_tmp = name; @@ -140,12 +138,6 @@ int match_esc(const char *mask, const char *name) m = m_tmp; n = ++n_tmp; break; - case '\\': - m++; - /* allow escaping to force capitalization */ - if (*m++ != *n++) - goto backtrack; - break; case '*': case '?': for (star_p = 0;; m++) @@ -154,8 +146,10 @@ int match_esc(const char *mask, const char *name) star_p = 1; else if (*m == '?') { - if (!*n++) + /* changed for mask_match() */ + if (*n == '*' || !*n) goto backtrack; + n++; } else break; @@ -164,23 +158,6 @@ int match_esc(const char *mask, const char *name) { if (!*m) return 1; - else if (*m == '\\') - { - m_tmp = ++m; - if (!*m) - return 0; - for (n_tmp = n; *n && *n != *m; n++); - } - else if (*m == '#') - { - m_tmp = m; - for (n_tmp = n; *n && !IsDigit(*n); n++); - } - else if (*m == '@') - { - m_tmp = m; - for (n_tmp = n; *n && !IsLetter(*n); n++); - } else { m_tmp = m; @@ -191,17 +168,7 @@ int match_esc(const char *mask, const char *name) default: if (!*n) return (*m != '\0' ? 0 : 1); - if (*m == '#') - { - if (!IsDigit(*n)) - goto backtrack; - } - else if (*m == '@') - { - if (!IsLetter(*n)) - goto backtrack; - } - else if (ToLower(*m) != ToLower(*n)) + if (ToLower(*m) != ToLower(*n)) goto backtrack; m++; n++; @@ -210,6 +177,137 @@ int match_esc(const char *mask, const char *name) } } + +#define MATCH_MAX_CALLS 512 /* ACK! This dies when it's less that this + and we have long lines to parse */ +/** Check a string against a mask. + * This test checks using extended wildcards: '*' means match zero + * or more characters of any type; '?' means match exactly one + * character of any type; '#' means match exactly one character that + * is a number; '@' means match exactly one character that is a + * letter; '\s' means match a space. + * + * This function supports escaping, so that a wildcard may be matched + * exactly. + * + * @param[in] mask Wildcard-containing mask. + * @param[in] name String to check against \a mask. + * @return Zero if \a mask matches \a name, non-zero if no match. + */ +int +match_esc(const char *mask, const char *name) +{ + const unsigned char *m = (const unsigned char *)mask; + const unsigned char *n = (const unsigned char *)name; + const unsigned char *ma = (const unsigned char *)mask; + const unsigned char *na = (const unsigned char *)name; + int wild = 0; + int calls = 0; + int quote = 0; + int match1 = 0; + + s_assert(mask != NULL); + s_assert(name != NULL); + + if(!mask || !name) + return 0; + + /* if the mask is "*", it matches everything */ + if((*m == '*') && (*(m + 1) == '\0')) + return 1; + + while(calls++ < MATCH_MAX_CALLS) + { + if(quote) + quote++; + if(quote == 3) + quote = 0; + if(*m == '\\' && !quote) + { + m++; + quote = 1; + continue; + } + if(!quote && *m == '*') + { + /* + * XXX - shouldn't need to spin here, the mask should have been + * collapsed before match is called + */ + while(*m == '*') + m++; + + wild = 1; + ma = m; + na = n; + + if(*m == '\\') + { + m++; + /* This means it is an invalid mask -A1kmm. */ + if(!*m) + return 0; + quote++; + continue; + } + } + + if(!*m) + { + if(!*n) + return 1; + if(quote) + return 0; + for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--);; + + if(*m == '*' && (m > (const unsigned char *)mask)) + return 1; + if(!wild) + return 0; + m = ma; + n = ++na; + } + else if(!*n) + { + /* + * XXX - shouldn't need to spin here, the mask should have been + * collapsed before match is called + */ + if(quote) + return 0; + while(*m == '*') + m++; + return (*m == 0); + } + + if(quote) + match1 = *m == 's' ? *n == ' ' : ToLower(*m) == ToLower(*n); + else if(*m == '?') + match1 = 1; + else if(*m == '@') + match1 = IsLetter(*n); + else if(*m == '#') + match1 = IsDigit(*n); + else + match1 = ToLower(*m) == ToLower(*n); + if(match1) + { + if(*m) + m++; + if(*n) + n++; + } + else + { + if(!wild) + return 0; + m = ma; + n = ++na; + } + } + return 0; +} + int comp_with_mask(void *addr, void *dest, u_int mask) { if (memcmp(addr, dest, mask / 8) == 0) @@ -234,7 +332,7 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask iaddr = &((struct sockaddr_in *)addr)->sin_addr; idest = &((struct sockaddr_in *)dest)->sin_addr; } -#ifdef IPV6 +#ifdef RB_IPV6 else { iaddr = &((struct sockaddr_in6 *)addr)->sin6_addr; @@ -253,7 +351,7 @@ int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, u_int mask */ int match_ips(const char *s1, const char *s2) { - struct irc_sockaddr_storage ipaddr, maskaddr; + struct rb_sockaddr_storage ipaddr, maskaddr; char mask[BUFSIZE]; char address[HOSTLEN + 1]; char *len; @@ -273,7 +371,7 @@ int match_ips(const char *s1, const char *s2) if (cidrlen == 0) return 0; -#ifdef IPV6 +#ifdef RB_IPV6 if (strchr(mask, ':') && strchr(address, ':')) { aftype = AF_INET6; @@ -291,8 +389,8 @@ int match_ips(const char *s1, const char *s2) else return 0; - inetpton(aftype, address, ipptr); - inetpton(aftype, mask, maskptr); + rb_inet_pton(aftype, address, ipptr); + rb_inet_pton(aftype, mask, maskptr); if (comp_with_mask(ipptr, maskptr, cidrlen)) return 1; else @@ -307,7 +405,7 @@ int match_ips(const char *s1, const char *s2) int match_cidr(const char *s1, const char *s2) { - struct irc_sockaddr_storage ipaddr, maskaddr; + struct rb_sockaddr_storage ipaddr, maskaddr; char mask[BUFSIZE]; char address[NICKLEN + USERLEN + HOSTLEN + 6]; char *ipmask; @@ -341,7 +439,7 @@ int match_cidr(const char *s1, const char *s2) if (cidrlen == 0) return 0; -#ifdef IPV6 +#ifdef RB_IPV6 if (strchr(ip, ':') && strchr(ipmask, ':')) { aftype = AF_INET6; @@ -359,8 +457,8 @@ int match_cidr(const char *s1, const char *s2) else return 0; - inetpton(aftype, ip, ipptr); - inetpton(aftype, ipmask, maskptr); + rb_inet_pton(aftype, ip, ipptr); + rb_inet_pton(aftype, ipmask, maskptr); if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address)) return 1; else @@ -599,12 +697,12 @@ const unsigned int CharAttrs[] = { /* ' */ PRINT_C | CHAN_C | NONEOS_C, /* ( */ PRINT_C | CHAN_C | NONEOS_C, /* ) */ PRINT_C | CHAN_C | NONEOS_C, -/* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C | SERV_C, +/* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C, /* + */ PRINT_C | CHAN_C | NONEOS_C, /* , */ PRINT_C | NONEOS_C, /* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C, /* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C, -/* / */ PRINT_C | CHAN_C | NONEOS_C, +/* / */ PRINT_C | CHAN_C | NONEOS_C | HOST_C, /* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C, /* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C, /* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,