fix possible crash on user deletion
[srvx.git] / src / tools.c
index a626386e47a3cbbd87f261bbdaf20bed55b71157..b10bc7be4379b5b573008142c58bb539ffe9c9c3 100644 (file)
@@ -313,9 +313,11 @@ irc_pton(irc_in_addr_t *addr, unsigned char *bits, const char *input)
                 addr->in6[cpos + jj] = 0;
         }
     } else if (dot) {
-        unsigned int ip4;
+        uint32_t ip4;
         pos = irc_pton_ip4(input, bits, &ip4);
         if (pos) {
+/* glibc's htons() macro is not -Wshadow-safe. */
+#undef htons
             addr->in6[5] = htons(65535);
             addr->in6[6] = htons(ntohl(ip4) >> 16);
             addr->in6[7] = htons(ntohl(ip4) & 65535);
@@ -385,25 +387,33 @@ irccasestr(const char *haystack, const char *needle) {
     return NULL;
 }
 
+char *
+ircstrlower(char *str) {
+    size_t ii;
+    for (ii = 0; str[ii] != '\0'; ++ii)
+        str[ii] = tolower(str[ii]);
+    return str;
+}
+
 int
 split_line(char *line, int irc_colon, int argv_size, char *argv[])
 {
     int argc = 0;
     int n;
     while (*line && (argc < argv_size)) {
-       while (*line == ' ')
+        while (*line == ' ')
             *line++ = 0;
-       if (*line == ':' && irc_colon && argc > 0) {
-           /* the rest is a single parameter */
-           argv[argc++] = line + 1;
-           break;
-       }
+        if (*line == ':' && irc_colon && argc > 0) {
+            /* the rest is a single parameter */
+            argv[argc++] = line + 1;
+            break;
+        }
         if (!*line)
             break;
-       argv[argc++] = line;
-       if (argc >= argv_size)
+        argv[argc++] = line;
+        if (argc >= argv_size)
             break;
-       while (*line != ' ' && *line)
+        while (*line != ' ' && *line)
             line++;
     }
 #ifdef NDEBUG
@@ -430,7 +440,7 @@ int mmatch(const char *old_mask, const char *new_mask)
     if (*m == '*')
     {
       while (*m == '*')
-       m++;
+        m++;
       wild = 1;
       ma = m;
       na = n;
@@ -439,25 +449,25 @@ int mmatch(const char *old_mask, const char *new_mask)
     if (!*m)
     {
       if (!*n)
-       return 0;
+        return 0;
       for (m--; (m > old_mask) && (*m == '?'); m--)
-       ;
+        ;
       if ((*m == '*') && (m > old_mask) && (m[-1] != '\\'))
-       return 0;
+        return 0;
       if (!wild)
-       return 1;
+        return 1;
       m = ma;
 
       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
-       ++na;
+        ++na;
 
       n = ++na;
     }
     else if (!*n)
     {
       while (*m == '*')
-       m++;
+        m++;
       return (*m != 0);
     }
     if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?')))
@@ -494,23 +504,23 @@ int mmatch(const char *old_mask, const char *new_mask)
  *  cases upfront (which took 2 hours!)).
  */
     if ((*m == '*' && !mq) ||
-       ((!mq || nq) && tolower(*m) == tolower(*n)) ||
-       (*m == '?' && !mq && (*n != '*' || nq)))
+        ((!mq || nq) && tolower(*m) == tolower(*n)) ||
+        (*m == '?' && !mq && (*n != '*' || nq)))
     {
       if (*m)
-       m++;
+        m++;
       if (*n)
-       n++;
+        n++;
     }
     else
     {
       if (!wild)
-       return 1;
+        return 1;
       m = ma;
 
       /* Added to `mmatch' : Because '\?' and '\*' now is one character: */
       if ((*na == '\\') && ((na[1] == '*') || (na[1] == '?')))
-       ++na;
+        ++na;
 
       n = ++na;
     }
@@ -533,12 +543,14 @@ match_ircglob(const char *text, const char *glob)
             return 0;
         m = m_tmp;
         n = ++n_tmp;
+        if (!*n)
+            return 0;
         break;
     case '\\':
         m++;
         /* allow escaping to force capitalization */
         if (*m++ != *n++)
-            return 0;
+            goto backtrack;
         break;
     case '*': case '?':
         for (star_p = 0; ; m++) {
@@ -577,17 +589,19 @@ match_ircglob(const char *text, const char *glob)
 extern const char *hidden_host_suffix;
 
 int
-user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick)
+user_matches_glob(struct userNode *user, const char *orig_glob, int flags)
 {
+    irc_in_addr_t mask;
     char *glob, *marker;
+    unsigned char mask_bits;
 
     /* Make a writable copy of the glob */
     glob = alloca(strlen(orig_glob)+1);
     strcpy(glob, orig_glob);
     /* Check the nick, if it's present */
-    if (include_nick) {
+    if (flags & MATCH_USENICK) {
         if (!(marker = strchr(glob, '!'))) {
-            log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user->nick, orig_glob, include_nick);
+            log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include a '!'", user->nick, orig_glob, flags);
             return 0;
         }
         *marker = 0;
@@ -596,17 +610,14 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick
     }
     /* Check the ident */
     if (!(marker = strchr(glob, '@'))) {
-        log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user->nick, orig_glob, include_nick);
+        log_module(MAIN_LOG, LOG_ERROR, "user_matches_glob(\"%s\", \"%s\", %d) called, and glob doesn't include an '@'", user->nick, orig_glob, flags);
         return 0;
     }
     *marker = 0;
-    if (!match_ircglob(user->ident, glob))
+    if (((IsFakeIdent(user) && IsHiddenHost(user) && (flags & MATCH_VISIBLE)) || !match_ircglob(user->ident, glob)) &&
+        !(IsFakeIdent(user) && match_ircglob(user->fakeident, glob)))
         return 0;
     glob = marker + 1;
-    /* If it might be an IP glob, test that. */
-    if (!glob[strspn(glob, "0123456789./*?")]
-        && match_ircglob(irc_ntoa(&user->ip), glob))
-        return 1;
     /* Check for a fakehost match. */
     if (IsFakeHost(user) && match_ircglob(user->fakehost, glob))
         return 1;
@@ -617,6 +628,14 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int include_nick
         if (match_ircglob(hidden_host, glob))
             return 1;
     }
+    /* If only matching the visible hostnames, bail early. */
+    if ((flags & MATCH_VISIBLE) && IsHiddenHost(user)
+        && (IsFakeHost(user) || (hidden_host_suffix && user->handle_info)))
+        return 0;
+    /* If it might be an IP glob, test that. */
+    if (irc_pton(&mask, &mask_bits, glob)
+        && irc_check_mask(&user->ip, &mask, mask_bits))
+        return 1;
     /* None of the above; could only be a hostname match. */
     return match_ircglob(user->hostname, glob);
 }
@@ -699,20 +718,20 @@ sanitize_ircmask(char *input)
     mask = input;
     while(*input++ != '!')
     {
-       length++;
+        length++;
     }
     if(length > NICKLEN)
     {
-       mask += NICKLEN;
-       *mask++ = '!';
+        mask += NICKLEN;
+        *mask++ = '!';
 
-       /* This flag is used to indicate following parts should
-          be shifted. */
-       flag = 1;
+        /* This flag is used to indicate following parts should
+           be shifted. */
+        flag = 1;
     }
     else
     {
-       mask = input;
+        mask = input;
     }
 
     /* The ident and host must be truncated at the beginning and
@@ -721,46 +740,46 @@ sanitize_ircmask(char *input)
     start = input;
     while(*input++ != '@')
     {
-       length++;
+        length++;
     }
     if(length > USERLEN || flag)
     {
-       if(length > USERLEN)
-       {
-           start = input - USERLEN;
-           *mask++ = '*';
-       }
-       while(*start != '@')
-       {
-           *mask++ = *start++;
-       }
-       *mask++ = '@';
-
-       flag = 1;
+        if(length > USERLEN)
+        {
+            start = input - USERLEN;
+            *mask++ = '*';
+        }
+        while(*start != '@')
+        {
+            *mask++ = *start++;
+        }
+        *mask++ = '@';
+
+        flag = 1;
     }
     else
     {
-       mask = input;
+        mask = input;
     }
 
     length = 0;
     start = input;
     while(*input++)
     {
-       length++;
+        length++;
     }
     if(length > HOSTLEN || flag)
     {
-       if(length > HOSTLEN)
-       {
-           start = input - HOSTLEN;
-           *mask++ = '*';
-       }
-       while(*start)
-       {
-           *mask++ = *start++;
-       }
-       *mask = '\0';
+        if(length > HOSTLEN)
+        {
+            start = input - HOSTLEN;
+            *mask++ = '*';
+        }
+        while(*start)
+        {
+            *mask++ = *start++;
+        }
+        *mask = '\0';
     }
 
     return output;
@@ -790,12 +809,14 @@ ParseInterval(const char *interval)
 
     /* process the string, resetting the count if we find a unit character */
     while ((c = *interval++)) {
-       if (isdigit((int)c)) {
-           partial = partial*10 + c - '0';
-       } else {
-           seconds += TypeLength(c) * partial;
-           partial = 0;
-       }
+        if (isdigit((int)c)) {
+            partial = partial*10 + c - '0';
+        } else if (strchr("yMwdhms", c)) {
+            seconds += TypeLength(c) * partial;
+            partial = 0;
+        } else {
+            return 0;
+        }
     }
     /* assume the last chunk is seconds (the normal case) */
     return seconds + partial;
@@ -847,12 +868,12 @@ unsplit_string(char *set[], unsigned int max, char *dest)
 }
 
 char *
-intervalString(char *output, time_t interval, struct handle_info *hi)
+intervalString(char *output, unsigned long interval, struct handle_info *hi)
 {
     static const struct {
         const char *msg_single;
         const char *msg_plural;
-        long length;
+        unsigned long length;
     } unit[] = {
         { "MSG_YEAR",   "MSG_YEARS", 365 * 24 * 60 * 60 },
         { "MSG_WEEK",   "MSG_WEEKS",   7 * 24 * 60 * 60 },
@@ -869,13 +890,13 @@ intervalString(char *output, time_t interval, struct handle_info *hi)
     if(!interval)
     {
         msg = language_find_message(lang, "MSG_0_SECONDS");
-       return strcpy(output, msg);
+        return strcpy(output, msg);
     }
 
     for (type = 0, words = pos = 0;
          interval && (words < 2) && (type < ArrayLength(unit));
          type++) {
-       if (interval < unit[type].length)
+        if (interval < unit[type].length)
             continue;
         count = interval / unit[type].length;
         interval = interval % unit[type].length;