Author: Isomer <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / s_conf.c
index ab575d3526d3a2edee0f7378b874016e83820af3..a6b7d13299b5ab75c74d0e3178393c22694617bf 100644 (file)
@@ -32,6 +32,8 @@
 #include "ircd_alloc.h"
 #include "ircd_chattr.h"
 #include "ircd_log.h"
+#include "ircd_reply.h"
+#include "ircd_snprintf.h"
 #include "ircd_string.h"
 #include "list.h"
 #include "listener.h"
@@ -73,80 +75,6 @@ struct TRecord*  tdata = NULL;
 struct tm        motd_tm;
 
 
-/*
- *  is the K line field an interval or a comment? - Mmmm
- */
-static int is_comment(const char *comment)
-{
-  unsigned int i;
-  unsigned int len = strlen(comment);
-  for (i = 0; i < len; ++i) {
-    if (!IsKTimeChar(comment[i]))
-      return 1;
-  }
-  return 0;
-}
-
-/*
- *  check against a set of time intervals
- */
-static int check_time_interval(char *interval, char *reply)
-{
-  struct tm* tptr;
-  char*      p;
-  int        perm_min_hours;
-  int        perm_min_minutes;
-  int        perm_max_hours;
-  int        perm_max_minutes;
-  int        nowm;
-  int        perm_min;
-  int        perm_max;
-
-  tptr = localtime(&CurrentTime);
-  nowm = tptr->tm_hour * 60 + tptr->tm_min;
-
-  while (interval) {
-    p = strchr(interval, ',');
-    if (p)
-      *p = '\0';
-    if (sscanf(interval, "%2d%2d-%2d%2d", &perm_min_hours, &perm_min_minutes,
-               &perm_max_hours, &perm_max_minutes) != 4)
-    {
-      if (p)
-        *p = ',';
-      return 0;
-    }
-    if (p)
-      *(p++) = ',';
-    perm_min = 60 * perm_min_hours + perm_min_minutes;
-    perm_max = 60 * perm_max_hours + perm_max_minutes;
-    /*
-     * The following check allows intervals over midnight ...
-     */
-    if ((perm_min < perm_max)
-        ? (perm_min <= nowm && nowm <= perm_max)
-        : (perm_min <= nowm || nowm <= perm_max))
-    {
-      sprintf_irc(reply, ":%%s %%d %%s :%s %d:%02d to %d:%02d.",
-                  "You are not allowed to connect from",
-                  perm_min_hours, perm_min_minutes,
-                  perm_max_hours, perm_max_minutes);
-      return (ERR_YOUREBANNEDCREEP);
-    }
-    if ((perm_min < perm_max)
-        ? (perm_min <= nowm + 5 && nowm + 5 <= perm_max)
-        : (perm_min <= nowm + 5 || nowm + 5 <= perm_max))
-    {
-      sprintf_irc(reply, ":%%s %%d %%s :%d minute%s%s",
-                  perm_min - nowm, (perm_min - nowm) > 1 ? "s " : " ",
-                  "and you will be denied for further access");
-      return (ERR_YOUWILLBEBANNED);
-    }
-    interval = p;
-  }
-  return 0;
-}
-
 /*
  * output the reason for being k lined from a file  - Mmmm
  * sptr is server
@@ -157,15 +85,14 @@ static void killcomment(struct Client *sptr, char *parv, char *filename)
 {
   FBFILE*     file = NULL;
   char        line[80];
-  char*       tmp;
+  char*       tmp = NULL;
   struct stat sb;
   struct tm*  tm;
 
   if (NULL == (file = fbopen(filename, "r"))) {
-    sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
-    sendto_one(sptr,
-        ":%s %d %s :Connection from your host is refused on this server.",
-        me.name, ERR_YOUREBANNEDCREEP, parv);
+    send_reply(sptr, ERR_NOMOTD);
+    send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+              ":Connection from your host is refused on this server.");
     return;
   }
   fbstat(&sb, file);
@@ -175,14 +102,10 @@ static void killcomment(struct Client *sptr, char *parv, char *filename)
       *tmp = '\0';
     if ((tmp = strchr(line, '\r')))
       *tmp = '\0';
-    /* sendto_one(sptr,
-     * ":%s %d %s : %s.",
-     * me.name, ERR_YOUREBANNEDCREEP, parv,line); */
-    sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line);
+    send_reply(sptr, RPL_MOTD, line);
   }
-  sendto_one(sptr,
-      ":%s %d %s :Connection from your host is refused on this server.",
-      me.name, ERR_YOUREBANNEDCREEP, parv);
+  send_reply(sptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+            ":Connection from your host is refused on this server.");
   fbclose(file);
 }
 
@@ -490,38 +413,33 @@ static int validate_hostent(struct hostent* hp)
 
 /*
  * check_limit_and_attach - check client limits and attach I:line
+ *
+ * Made it accept 1 charactor, and 2 charactor limits (0->99 now), 
+ * and dislallow more than 255 people here as well as in ipcheck.
+ * removed the old "ONE" scheme too.
+ *  -- Isomer 2000-06-22
  */
-static int check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf)
+static enum AuthorizationCheckResult
+check_limit_and_attach(struct Client* cptr, struct ConfItem* aconf)
 {
+  int number = 255;
+  
   if (aconf->passwd) {
-    /* Special case: exactly one digit */
-    if (IsDigit(*aconf->passwd) && !aconf->passwd[1]) {
-      /*
-       * Refuse connections when there are already <digit>
-       * clients connected with the same IP number
-       */
-      unsigned short nr = *aconf->passwd - '0';
-      if (IPcheck_nr(cptr) > nr)
-        return ACR_TOO_MANY_FROM_IP; /* Already got nr with that ip# */
-    }
-#ifdef USEONE
-    else if (0 == strcmp(aconf->passwd, "ONE")) {
-      int i;
-      for (i = HighestFd; i > -1; --i) {
-        if (LocalClientArray[i] && MyUser(LocalClientArray[i]) &&
-            LocalClientArray[i]->ip.s_addr == cptr->ip.s_addr)
-          return ACR_TOO_MANY_FROM_IP; /* Already got one with that ip# */
-      }
-    }
-#endif
+    if (IsDigit(*aconf->passwd) && !aconf->passwd[1])
+      number = *aconf->passwd-'0';
+    else if (IsDigit(*aconf->passwd) && IsDigit(aconf->passwd[1]) && 
+             !aconf->passwd[2])
+      number = (*aconf->passwd-'0')*10+(aconf->passwd[1]-'0');
   }
+  if (ip_registry_count(cptr->ip.s_addr) > number)
+    return ACR_TOO_MANY_FROM_IP;
   return attach_conf(cptr, aconf);
 }
 
 /*
  * Find the first (best) I line to attach.
  */
-int attach_iline(struct Client*  cptr)
+enum AuthorizationCheckResult attach_iline(struct Client*  cptr)
 {
   struct ConfItem* aconf;
   const char*      hname;
@@ -634,7 +552,7 @@ static int is_attached(struct ConfItem *aconf, struct Client *cptr)
  * connection). Note, that this automaticly changes the
  * attachment if there was an old one...
  */
-int attach_conf(struct Client *cptr, struct ConfItem *aconf)
+enum AuthorizationCheckResult attach_conf(struct Client *cptr, struct ConfItem *aconf)
 {
   struct SLink *lp;
 
@@ -740,11 +658,8 @@ struct ConfItem* find_conf_exact(const char* name, const char* user,
   struct ConfItem *tmp;
   char userhost[USERLEN + HOSTLEN + 3];
 
-  /*
-   * XXX - buffer overflow possible, unchecked variables
-   */
   if (user)
-    sprintf_irc(userhost, "%s@%s", user, host);
+    ircd_snprintf(0, userhost, sizeof(userhost), "%s@%s", user, host);
   else
     ircd_strncpy(userhost, host, sizeof(userhost) - 1);
 
@@ -797,7 +712,7 @@ struct ConfItem* find_conf_byname(struct SLink* lp, const char* name,
 struct ConfItem* find_conf_byhost(struct SLink* lp, const char* host,
                                   int statmask)
 {
-  struct ConfItem* tmp;
+  struct ConfItem* tmp = NULL;
   assert(0 != host);
 
   if (HOSTLEN < strlen(host))
@@ -897,7 +812,8 @@ int rehash(struct Client *cptr, int sig)
   int               found_g = 0;
 
   if (1 == sig)
-    sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
+    sendto_opmask_butone(0, SNO_OLDSNO,
+                        "Got signal SIGHUP, reloading ircd conf. file");
 
   while ((tmp2 = *tmp)) {
     if (tmp2->clients) {
@@ -974,10 +890,16 @@ int rehash(struct Client *cptr, int sig)
         attach_confs_byname(acptr, acptr->name,
                             CONF_HUB | CONF_LEAF | CONF_UWORLD);
       }
+      /* Because admin's are getting so uppity about people managing to
+       * get past K/G's etc, we'll "fix" the bug by actually explaining
+       * whats going on.
+       */
       if ((found_g = find_kill(acptr))) {
-        sendto_op_mask(found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
-            found_g == -2 ? "G-line active for %s" : "K-line active for %s",
-            get_client_name(acptr, HIDE_IP));
+        sendto_opmask_butone(0, found_g == -2 ? SNO_GLINE : SNO_OPERKILL,
+                            found_g == -2 ? "G-line active for %s%s" :
+                            "K-line active for %s%s",
+                            IsUnknown(acptr) ? "Unregistered Client ":"",                   
+                            get_client_name(acptr, HIDE_IP));
         if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
             "K-lined") == CPTR_KILLED)
           ret = CPTR_KILLED;
@@ -1071,6 +993,7 @@ int conf_init(void)
     /* Could we test if it's conf line at all?      -Vesa */
     if (line[1] != ':') {
       Debug((DEBUG_ERROR, "Bad config line: %s", line));
+      sendto_op_mask(SNO_OLDSNO,"Bad Config line");
       continue;
     }
     if (aconf)
@@ -1149,6 +1072,7 @@ int conf_init(void)
       break;
     default:
       Debug((DEBUG_ERROR, "Error in config file: %s", line));
+      sendto_op_mask(SNO_OLDSNO,"Unknown prefix in config file: %c",*tmp);
       break;
     }
     if (IsIllegal(aconf))
@@ -1172,9 +1096,9 @@ int conf_init(void)
       if (aconf->status & CONF_ME) {
         if (!tmp) {
           Debug((DEBUG_FATAL, "Your M: line must have the Numeric, "
-              "assigned to you by routing-com, behind the port number!\n"));
+              "assigned to you by routing-com!\n"));
           ircd_log(L_WARNING, "Your M: line must have the Numeric, "
-              "assigned to you by routing-com, behind the port number!\n");
+              "assigned to you by routing-com!\n");
           exit(-1);
         }
         SetYXXServerName(&me, atoi(tmp));        /* Our Numeric Nick */
@@ -1251,7 +1175,7 @@ int conf_init(void)
         len += strlen(aconf->host);
         newhost = (char*) MyMalloc(len);
         assert(0 != newhost);
-        sprintf_irc(newhost, "*@%s", aconf->host);
+       ircd_snprintf(0, newhost, len, "*@%s", aconf->host);
         MyFree(aconf->host);
         aconf->host = newhost;
       }
@@ -1283,6 +1207,31 @@ int conf_init(void)
     if (aconf->status == CONF_ME) {
       ircd_strncpy(me.info, aconf->name, REALLEN);
     }
+    
+    if (aconf->status == CONF_IPKILL) {
+      /* 
+       * Here we use the same kludge as in listener.c to parse
+       * a.b.c.d, or a.b.c.*, or a.b.c.d/e.
+       */
+      int class;
+      char ipname[16];
+      int ad[4] = { 0 };
+      int bits2=0;
+      class=sscanf(aconf->host,"%d.%d.%d.%d/%d",
+                   &ad[0], &ad[1], &ad[2], &ad[3], &bits2);
+      if (class!=5) {
+        aconf->bits=class*8;
+      }
+      else {
+        aconf->bits=bits2;
+      }
+      sprintf_irc(ipname,"%d.%d.%d.%d",ad[0], ad[1], ad[2], ad[3]);
+      
+      /* This ensures endian correctness */
+      aconf->ipnum.s_addr = inet_addr(ipname);
+      Debug((DEBUG_DEBUG,"IPkill: %s = %08x/%i (%08x)",ipname,
+       aconf->ipnum.s_addr,aconf->bits,NETMASK(aconf->bits)));
+    }
 
     /*
      * Juped nicks are listed in the 'password' field of U:lines,
@@ -1362,9 +1311,19 @@ void read_tlines()
   }
 }
 
+/*
+ * find_kill
+ * input:
+ *  client pointer
+ * returns:
+ *  0: Client may continue to try and connect
+ * -1: Client was K/k:'d - sideeffect: reason was sent.
+ * -2: Client was G/g:'d - sideeffect: reason was sent.
+ * sideeffects:
+ *  Client may have been sent a reason why they are denied, as above.
+ */
 int find_kill(struct Client *cptr)
 {
-  char             reply[256];
   const char*      host;
   const char*      name;
   struct ConfItem* tmp;
@@ -1378,58 +1337,50 @@ int find_kill(struct Client *cptr)
   host = cptr->sockhost;
   name = cptr->user->username;
 
-#if 0
-  /*
-   * whee :)
-   * XXX - if this ever happens, we're already screwed
+  assert(strlen(host) <= HOSTLEN);
+  assert((name ? strlen(name) : 0) <= HOSTLEN);
+  
+  /* 2000-07-14: Rewrote this loop for massive speed increases.
+   *             -- Isomer
    */
-  if (strlen(host) > HOSTLEN ||
-      (name ? strlen(name) : 0) > HOSTLEN)
-    return (0);
-#endif
-
-  reply[0] = '\0';
-
   for (tmp = GlobalConfList; tmp; tmp = tmp->next) {
-    /* Added a check against the user's IP address as well.
-     * If the line is either CONF_KILL or CONF_IPKILL, check it; if and only
-     * if it's CONF_IPKILL, check the IP address as well (the && below will
-     * short circuit and the match won't even get run) -Kev
+  
+    if ((tmp->status & CONF_KLINE) == 0)
+       continue;
+       
+    /*
+     * What is this for?  You can K: by port?!
+     *   -- Isomer
      */
-    if ((tmp->status & CONF_KLINE) && tmp->host && tmp->name &&
-        (match(tmp->host, host) == 0 ||
-        ((tmp->status == CONF_IPKILL) &&
-        match(tmp->host, ircd_ntoa((const char*) &cptr->ip)) == 0)) &&
-        (!name || match(tmp->name, name) == 0) &&
-        (!tmp->port || (tmp->port == cptr->listener->port)))
-    {
-      /*
-       * Can short-circuit evaluation - not taking chances
-       * because check_time_interval destroys tmp->passwd
-       * - Mmmm
-       */
-      if (EmptyString(tmp->passwd))
-        break;
-      else if (is_comment(tmp->passwd))
-        break;
-      else if (check_time_interval(tmp->passwd, reply))
-        break;
+    if (tmp->port && tmp->port != cptr->listener->port)
+       continue;
+
+    if (!tmp->name || match(tmp->name, name) != 0)
+       continue;
+       
+    if (!tmp->host)
+       break;
+    
+    if (tmp->status != CONF_IPKILL) {
+       if (match(tmp->host, host) == 0)
+         break;
+    }
+    else { /* k: by IP */
+       Debug((DEBUG_DEBUG, "ip: %08x network: %08x/%i mask: %08x",
+               cptr->ip.s_addr, tmp->ipnum.s_addr, tmp->bits, 
+               NETMASK(tmp->bits)));
+       if ((cptr->ip.s_addr & NETMASK(tmp->bits)) == tmp->ipnum.s_addr)
+               break;
     }
   }
-  if (reply[0])
-    sendto_one(cptr, reply, me.name, ERR_YOUREBANNEDCREEP, cptr->name);
-  else if (tmp) {
+  if (tmp) {
     if (EmptyString(tmp->passwd))
-      sendto_one(cptr,
-          ":%s %d %s :Connection from your host is refused on this server.",
-          me.name, ERR_YOUREBANNEDCREEP, cptr->name);
+      send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP,
+                ":Connection from your host is refused on this server.");
     else {
       if (*tmp->passwd == '"') {
-        char *sbuf =
-            sprintf_irc(sendbuf, ":%s %d %s :%s", me.name, ERR_YOUREBANNEDCREEP,
-            cptr->name, &tmp->passwd[1]);
-        sbuf[-1] = '.';                /* Overwrite last quote with a dot */
-        sendbufto_one(cptr);
+       send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%*s.",
+                  strlen(tmp->passwd + 1) - 1, tmp->passwd + 1);
       }
       else if (*tmp->passwd == '!')
         killcomment(cptr, cptr->name, &tmp->passwd[1]);
@@ -1437,21 +1388,26 @@ int find_kill(struct Client *cptr)
 #ifdef COMMENT_IS_FILE
         killcomment(cptr, cptr->name, tmp->passwd);
 #else
-        sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
-            cptr->name, tmp->passwd);
+       send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.",
+                  tmp->passwd);
 #endif
     }
   }
 
   /* find active glines */
   /* added a check against the user's IP address to find_gline() -Kev */
-  else if ((agline = find_gline(cptr, NULL)) && GlineIsActive(agline))
-    sendto_one(cptr, ":%s %d %s :%s.", me.name, ERR_YOUREBANNEDCREEP,
-        cptr->name, agline->reason);
+  else if ((agline = gline_lookup(cptr, 0)) && GlineIsActive(agline))
+    send_reply(cptr, SND_EXPLICIT | ERR_YOUREBANNEDCREEP, ":%s.",
+              GlineReason(agline));
   else
     agline = NULL;                /* if a gline was found, it was inactive */
 
-  return (tmp ? -1 : (agline ? -2 : 0));
+  if (tmp)
+    return -1;
+  if (agline)
+    return -2;
+    
+  return 0;
 }
 
 struct MotdItem* read_motd(const char* motdfile)
@@ -1500,7 +1456,7 @@ struct MotdItem* read_motd(const char* motdfile)
  */
 enum AuthorizationCheckResult conf_check_client(struct Client *cptr)
 {
-  int acr;
+  enum AuthorizationCheckResult acr = ACR_OK;
 
   ClearAccess(cptr);
 
@@ -1547,7 +1503,8 @@ int conf_check_server(struct Client *cptr)
   if (IsConnecting(cptr) || IsHandshake(cptr)) {
     c_conf = find_conf_byname(lp, cptr->name, CONF_SERVER);
     if (!c_conf) {
-      sendto_ops("Connect Error: lost C:line for %s", cptr->name);
+      sendto_opmask_butone(0, SNO_OLDSNO, "Connect Error: lost C:line for %s",
+                          cptr->name);
       det_confs_butmask(cptr, 0);
       return -1;
     }