]> jfr.im git - irc/evilnet/x3.git/blobdiff - src/tools.c
Fix for bug in X3.unban handling
[irc/evilnet/x3.git] / src / tools.c
index 4849e85b9f5352b4862a42db83fed996b3dabf2b..afaed60c9b43421edc1aaec402a1c7244148eac9 100644 (file)
@@ -3,9 +3,9 @@
  *
  * This file is part of x3.
  *
- * srvx is free software; you can redistribute it and/or modify
+ * x3 is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
@@ -313,7 +313,7 @@ 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) {
             addr->in6[5] = htons(65535);
@@ -357,8 +357,20 @@ static char irc_tolower[256];
 #undef tolower
 #define tolower(X) irc_tolower[(unsigned char)(X)]
 
+void
+irc_strtolower(char *str) {
+    char *p;
+    for(p = str;*p;p++) {
+       *p = tolower(*p);
+    }
+}
+
 int
 irccasecmp(const char *stra, const char *strb) {
+    if (!stra)
+      return -1;
+    if (!strb)
+      return 1;
     while (*stra && (tolower(*stra) == tolower(*strb)))
         stra++, strb++;
     return tolower(*stra) - tolower(*strb);
@@ -385,6 +397,14 @@ 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[])
 {
@@ -533,6 +553,8 @@ match_ircglob(const char *text, const char *glob)
             return 0;
         m = m_tmp;
         n = ++n_tmp;
+        if (!*n)
+            return 0;
         break;
     case '\\':
         m++;
@@ -584,13 +606,143 @@ int is_overmask(char *mask)
 }
 
 int
-user_matches_glob(struct userNode *user, const char *orig_glob, int flags)
+user_matches_glob(struct userNode *user, const char *orig_glob, int flags, int shared)
 {
-    char *glob, *marker;
+    char *tmpglob, *glob, *marker;
+    char exttype = 0;
+    int extreverse = 0, is_extended = 0, match = 0, banned = 0;
+    unsigned int count, n;
+    struct modeNode *mn;
+    struct chanNode *channel;
+    struct banNode *ban;
 
     /* Make a writable copy of the glob */
     glob = alloca(strlen(orig_glob)+1);
     strcpy(glob, orig_glob);
+
+    /* Extended bans */
+    tmpglob = alloca(strlen(orig_glob)+1);
+    tmpglob = strdup(orig_glob);
+
+    if (*tmpglob == '~') {
+        tmpglob++; /* get rid of the ~ */
+
+        if (*tmpglob == '!') {
+            extreverse = 1;
+            tmpglob++; /* get rid of the ! */
+        }
+
+        exttype = *tmpglob;
+        tmpglob++; /* get rid of the type */
+
+        if (*tmpglob == ':') {
+            is_extended = 1;
+            tmpglob++; /* get rid of the : */
+            glob = strdup(tmpglob);
+        }
+    }
+
+    if (is_extended) {
+        log_module(MAIN_LOG, LOG_DEBUG, "Extended ban. T (%c) R (%d) M (%s)", exttype, extreverse, glob);
+        switch (exttype) {
+            case 'a':
+                if (user->handle_info) {
+                    if (extreverse) {
+                        if (0 != strcasecmp(glob, user->handle_info->handle))
+                            return 1;
+                    } else {
+                        if (0 == strcasecmp(glob, user->handle_info->handle))
+                            return 1;
+                    }
+                } else {
+                    if (extreverse)
+                        return 1;
+                }
+                return match_ircglob(user->hostname, glob);
+            case 'c':
+                if (!strstr(glob, "#"))
+                    return -1;
+
+                if (extreverse) {
+                    for (n=count=0; n<user->channels.used; n++) {
+                        mn = user->channels.list[n];
+                        match = 0;
+
+                        if (*glob == '#') {
+                            if (0 == strcasecmp(glob, mn->channel->name))
+                                match = 1;
+                        } else {
+                            if (0 == strcasecmp(glob+1, mn->channel->name)) {
+                                if ((*glob == '@') && (mn->modes & MODE_CHANOP))
+                                    match = 1;
+                                else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
+                                    match = 1;
+                                else if ((*glob == '+') && (mn->modes & MODE_VOICE))
+                                    match = 1;
+                             }
+                        }
+
+                        if (match == 0)
+                            banned = 1;
+                        else {
+                            banned = 0;
+                            break;
+                        }
+                    }
+                } else {
+                    for (n=count=0; n<user->channels.used; n++) {
+                        mn = user->channels.list[n];
+                        match = 0;
+
+                        if (*glob == '#') {
+                            if (0 == strcasecmp(glob, mn->channel->name))
+                                match = 1;
+                        } else {
+                            if (0 == strcasecmp(glob+1, mn->channel->name)) {
+                                if ((*glob == '@') && (mn->modes & MODE_CHANOP))
+                                    match = 1;
+                                else if ((*glob == '%') && (mn->modes & MODE_HALFOP))
+                                    match = 1;
+                                else if ((*glob == '+') && (mn->modes & MODE_VOICE))
+                                    match = 1;
+                             }
+                        }
+
+                        if (match == 1)
+                            banned = 1;
+                    }
+                }
+
+                if (banned)
+                    return 1;
+                else
+                    return match_ircglob(user->hostname, glob);
+            case 'j':
+                 if (shared == 0) {
+                     if (*glob != '#')
+                         return -1;
+                     if ((channel = GetChannel(glob))) {
+                         for (n = 0; n < channel->banlist.used; n++) {
+                             ban = channel->banlist.list[n];
+                             if (user_matches_glob(user, ban->ban, flags, 1))
+                                 return 1;
+                         }
+                     }
+                 }
+                 return match_ircglob(user->hostname, glob);
+            case 'n': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 'q': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 't': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            case 'R': /* this is handled ircd side */
+                return match_ircglob(user->hostname, glob);
+            default:
+                return -1;
+        }
+    }
+
     /* Check the nick, if it's present */
     if (flags & MATCH_USENICK) {
         if (!(marker = strchr(glob, '!'))) {
@@ -625,9 +777,19 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int flags)
         if (match_ircglob(hidden_host, glob))
             return 1;
     }
+
+    /* Match crypt hostname */
+    if (match_ircglob(user->crypthost, glob))
+        return 1;
+
+    /* Match crypt IP */
+    if (match_ircglob(user->cryptip, 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)))
+        && (IsFakeHost(user) || (hidden_host_suffix && user->handle_info) ||
+            user->crypthost || user->cryptip))
         return 0;
     /* If it might be an IP glob, test that. */
     if (!glob[strspn(glob, "0123456789./*?")]
@@ -640,6 +802,27 @@ user_matches_glob(struct userNode *user, const char *orig_glob, int flags)
 int
 is_ircmask(const char *text)
 {
+    char *tmptext;
+
+    if (*text == '~') {
+        tmptext = alloca(strlen(text)+1);
+        tmptext = strdup(text);
+
+       tmptext++; /* get rid of the ~ */
+
+        if (*tmptext == '!')
+            tmptext++; /* get rid of the ! if it exists */
+
+        tmptext++; /* get rid of the ext ban type */
+
+        if (*tmptext == ':') {
+            tmptext++; /* get rid of the : */
+            while (*tmptext && !isspace((char)*tmptext))
+                tmptext++;  /* get rid of the rest */
+            return !*tmptext;
+        }
+    }
+
     while (*text && (isalnum((char)*text) || strchr("-_[]|\\`^{}?*", *text)))
         text++;
     if (*text++ != '!')
@@ -825,12 +1008,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;
@@ -1102,6 +1287,23 @@ char *mysep(char **sepstr, char *delim)
   return(retstr);
 }
 
+/* Mallocing snprintf *
+ *
+ * If it overruns size, it will simply be safely truncated.
+ */
+char *
+x3_msnprintf(const int size, const char *format, ...)
+{
+    va_list ap;
+    char* buff = calloc(sizeof(char *), size+1);
+
+    va_start(ap, format);
+    vsnprintf(buff, size, format, ap);
+    va_end(ap);
+    buff = realloc(buff, strlen(buff) + 1);
+    return buff;
+}
+
 char *time2str(time_t thetime)
 {
     char *buf, *tmp;
@@ -1158,3 +1360,125 @@ int valid_email(const char *email)
     return true;
 }
 
+/*
+ * Create a string of form "foo!bar@fubar" given foo, bar and fubar
+ * as the parameters.  If NULL, they become "*".
+ */
+#define NUH_BUFSIZE    (NICKLEN + USERLEN + HOSTLEN + 10)
+static char *make_nick_user_host(char *namebuf, const char *nick,
+                                const char *name, const char *host)
+{
+  snprintf(namebuf, NUH_BUFSIZE, "%s!%s@%s", nick, name, host);
+  return namebuf;
+}
+
+/*
+ * pretty_mask
+ *
+ * by Carlo Wood (Run), 05 Oct 1998.
+ *
+ * Canonify a mask.
+ *
+ * When the nick is longer then NICKLEN, it is cut off (its an error of course).
+ * When the user name or host name are too long (USERLEN and HOSTLEN
+ * respectively) then they are cut off at the start with a '*'.
+ *
+ * The following transformations are made:
+ *
+ * 1)   xxx             -> nick!*@*
+ * 2)   xxx.xxx         -> *!*@host
+ * 3)   xxx!yyy         -> nick!user@*
+ * 4)   xxx@yyy         -> *!user@host
+ * 5)   xxx!yyy@zzz     -> nick!user@host
+ */
+char *pretty_mask(char *mask)
+{
+  static char star[2] = { '*', 0 };
+  static char retmask[NUH_BUFSIZE] = "";
+  char *last_dot = NULL;
+  char *ptr = NULL;
+
+  /* Case 1: default */
+  char *nick = mask;
+  char *user = star;
+  char *host = star;
+
+  /* Do a _single_ pass through the characters of the mask: */
+  for (ptr = mask; *ptr; ++ptr)
+  {
+    if (*ptr == '!')
+    {
+      /* Case 3 or 5: Found first '!' (without finding a '@' yet) */
+      user = ++ptr;
+      host = star;
+    }
+    else if (*ptr == '@')
+    {
+      /* Case 4: Found last '@' (without finding a '!' yet) */
+      nick = star;
+      user = mask;
+      host = ++ptr;
+    }
+    else if (*ptr == '.')
+    {
+      /* Case 2: Found last '.' (without finding a '!' or '@' yet) */
+      last_dot = ptr;
+      continue;
+    }
+    else
+      continue;
+    for (; *ptr; ++ptr)
+    {
+      if (*ptr == '@')
+      {
+        /* Case 4 or 5: Found last '@' */
+        host = ptr + 1;
+      }
+    }
+    break;
+  }
+  if (user == star && last_dot)
+  {
+    /* Case 2: */
+    nick = star;
+    user = star;
+    host = mask;
+  }
+  /* Check lengths */
+  if (nick != star)
+  {
+    char *nick_end = (user != star) ? user - 1 : ptr;
+    if (nick_end - nick > NICKLEN)
+      nick[NICKLEN] = 0;
+    *nick_end = 0;
+  }
+  if (user != star)
+  {
+    char *user_end = (host != star) ? host - 1 : ptr;
+    if (user_end - user > USERLEN)
+    {
+      user = user_end - USERLEN;
+      *user = '*';
+    }
+    *user_end = 0;
+  }
+  if (host != star && ptr - host > HOSTLEN)
+  {
+    host = ptr - HOSTLEN;
+    *host = '*';
+  }
+  return make_nick_user_host(retmask, nick, user, host);
+}
+
+int str_is_number(const char *str)
+{
+    char *ptr;
+    int ret = false;
+    for(ptr = (char *)str;*ptr;ptr++) {
+        if((*ptr >= '0' && *ptr <= '9') || *ptr == '-')
+            ret = true;
+        else
+            return false;
+    }
+    return ret;
+}