]> jfr.im git - irc/quakenet/newserv.git/commitdiff
Fix a buffer overflow in newsearch.
authorChris Porter <redacted>
Fri, 25 Jan 2008 15:46:29 +0000 (15:46 +0000)
committerChris Porter <redacted>
Fri, 25 Jan 2008 15:46:29 +0000 (15:46 +0000)
Add better custom kill/gline reasons, with support for the following format specifiers:
  - %h: hostname
  - %n: nickname
  - %i: ident
  - %I: ip address
  - %u: %n!%i@%I

newsearch/newsearch.c
newsearch/newsearch.h
newsearch/ns-gline.c
newsearch/ns-kill.c

index 932d4b368898dda6961a30cde6755431ce939418..226379ef17c1dd7ec82f67aa75e51d5095ce9ee4 100644 (file)
@@ -676,3 +676,93 @@ struct searchNode *search_parse(int type, char *input) {
     return thenode;
   }    
 }
+
+struct bufs {
+  char *buf;
+  int capacity;
+  int len;
+};
+
+static int addchar(struct bufs *buf, char c) {
+  if(buf->len >= buf->capacity - 1)
+    return 0;
+
+  buf->buf[buf->len++] = c;
+
+  return 1;
+}
+
+static int addstr(struct bufs *buf, char *c) {
+  int remaining = buf->capacity - buf->len - 1;
+  char *p;
+
+  for(p=c;*p;p++) {
+    if(remaining-- <= 0)
+      return 0;
+
+    buf->buf[buf->len++] = *p;
+  }
+
+  return 1;
+}
+
+void nssnprintf(char *buf, size_t size, const char *format, nick *np) {
+  struct bufs b;
+  const char *p;
+  char *c;
+  char hostbuf[512];
+
+  if(size == 0)
+    return;
+
+  b.buf = buf;
+  b.capacity = size;
+  b.len = 0;
+
+  for(p=format;*p;p++) {
+    if(*p != '%') {
+      if(!addchar(&b, *p))
+        break;
+      continue;
+    }
+    p++;
+    if(*p == '\0')
+      break;
+    if(*p == '%') {
+      if(!addchar(&b, *p))
+        break;
+      continue;
+    }
+
+    c = NULL;
+    switch(*p) {
+      case 'n':
+        c = np->nick; break;
+      case 'i':
+        c = np->ident; break;
+      case 'h':
+        c = np->host->name->content; break;
+      case 'I':
+        snprintf(hostbuf, sizeof(hostbuf), "%s", IPtostr(np->p_ipaddr));
+        c = hostbuf;
+        break;
+      case 'u':
+        snprintf(hostbuf, sizeof(hostbuf), "%s!%s@%s", np->nick, np->ident, IPtostr(np->p_ipaddr));
+        c = hostbuf;
+        break;
+      default:
+        c = "(bad format specifier)";
+    }
+    if(c)
+      if(!addstr(&b, c))
+        break;
+  }
+
+  buf[b.len] = '\0';
+
+  /* not required */
+  /*
+  buf[size-1] = '\0';
+  */
+}
+
index bfb9797a287950d826fb56fdc3a534cb322881e9..5d001249d5926fe4ea3d5d72295c1e6c1ab4160f 100644 (file)
@@ -99,6 +99,9 @@ void unregchandisp(const char *name, ChanDisplayFunc handler);
 void regnickdisp(const char *name, NickDisplayFunc handler);
 void unregnickdisp(const char *name, NickDisplayFunc handler);
 
+/* Special nick* printf */
+void nssnprintf(char *, size_t, const char *, nick *);
+
 typedef struct searchNode {
   int returntype;
   exeFunc  exe;
index 270f64c2bda34a0b2bb573283a39b83a8a227ad5..7803cdb428f1f1e91349a613a6122ab6e9042ee6 100644 (file)
 #include "../control/control.h" /* controlreply() */
 #include "../irc/irc.h" /* irc_send() */
 #include "../lib/irc_string.h" /* IPtostr(), longtoduration(), durationtolong() */
+#include "../lib/strlfunc.h"
 
 /* used for *_free functions that need to warn users of certain things
    i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
 extern nick *senderNSExtern;
+static const char *defaultreason = "You (%u) have been g-lined for violating our terms of service";
 
 void *gline_exe(struct searchNode *thenode, void *theinput);
 void gline_free(struct searchNode *thenode);
@@ -31,6 +33,7 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
   struct gline_localdata *localdata;
   struct searchNode *thenode;
   int len;
+  char *p;
 
   if (!(localdata = (struct gline_localdata *) malloc(sizeof(struct gline_localdata)))) {
     parseError = "malloc: could not allocate memory for this search.";
@@ -46,7 +49,7 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
   switch (argc) {
   case 0:
     localdata->duration = NSGLINE_DURATION;
-    snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+    strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
     break;
 
   case 1:
@@ -55,14 +58,20 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
       /* error checking on gline duration */
       if (localdata->duration == 0)
         localdata->duration = NSGLINE_DURATION;
-      snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+      strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
     }
     else { /* reason specified */
       localdata->duration = NSGLINE_DURATION;
-      len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[0]);
-      /* strip leading and trailing '"'s */
-      localdata->reason[1] = ' ';
-      localdata->reason[len-1] = '\0';
+
+      p = argv[0];
+      if(*p == '\"')
+        *p++;
+      len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+      if(len >= sizeof(localdata->reason)) {
+        localdata->reason[sizeof(localdata->reason)-1] = '\0';
+      } else {
+        localdata->reason[len-1] = '\0';
+      }
     }
     break;
 
@@ -71,12 +80,18 @@ struct searchNode *gline_parse(int type, int argc, char **argv) {
     /* error checking on gline duration */
     if (localdata->duration == 0)
       localdata->duration = NSGLINE_DURATION;
-    len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[1]);
-    /* strip leading and trailing '"'s */
-    localdata->reason[1] = ' ';
-    localdata->reason[len-1] = '\0';
-    break;
 
+    p = argv[1];
+    if(*p == '\"')
+      *p++;
+    len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+    if(len >= sizeof(localdata->reason)) {
+      localdata->reason[sizeof(localdata->reason)-1] = '\0';
+    } else {
+      localdata->reason[len-1] = '\0';
+    }
+
+    break;
   default:
     free(localdata);
     parseError = "gline: invalid number of arguments";
@@ -124,6 +139,7 @@ void gline_free(struct searchNode *thenode) {
   nick *np, *nnp;
   chanindex *cip, *ncip;
   int i, j, safe=0;
+  char msgbuf[512];
 
   localdata = thenode->localdata;
 
@@ -146,15 +162,14 @@ void gline_free(struct searchNode *thenode) {
     
             if ((np=getnickbynumeric(cip->channel->users->content[j]))) {
               if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
+                nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
                 if (np->host->clonecount <= NSMAX_GLINE_CLONES)
-                  irc_send("%s GL * +*@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                    mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
-                else
-                  irc_send("%s GL * +%s@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                    mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
-                }
+                  irc_send("%s GL * +*@%s %u :%s", mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
                 else
-                  safe++;
+                  irc_send("%s GL * +%s@%s %u :%s", mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
+              }
+              else
+                safe++;
             }
           }
         }
@@ -167,12 +182,11 @@ void gline_free(struct searchNode *thenode) {
         nnp = np->next;
         if (np->marker == localdata->marker) {
           if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
+            nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
             if (np->host->clonecount <= NSMAX_GLINE_CLONES)
-              irc_send("%s GL * +*@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+              irc_send("%s GL * +*@%s %u :%s", mynumeric->content, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
             else
-              irc_send("%s GL * +%s@%s %u :You (%s!%s@%s) have been glined for violating our terms of service%s", 
-                mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, np->nick, np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+              irc_send("%s GL * +%s@%s %u :%s", mynumeric->content, np->ident, IPtostr(np->p_ipaddr), localdata->duration, msgbuf);
           }
           else
               safe++;
index 258a3b07fbc39f0c294eaabac08cde7433790fbb..a8166787d63336797a9d460c5d80fd3ebc5e32c4 100644 (file)
@@ -10,6 +10,7 @@
 #include "../control/control.h" /* controlreply() */
 #include "../localuser/localuser.h" /* killuser() */
 #include "../lib/irc_string.h" /* IPtostr() */
+#include "../lib/strlfunc.h"
 
 /* used for *_free functions that need to warn users of certain things
    i.e. hitting too many users in a (kill) or (gline) - declared in newsearch.c */
@@ -17,6 +18,7 @@ extern nick *senderNSExtern;
 
 void *kill_exe(struct searchNode *thenode, void *theinput);
 void kill_free(struct searchNode *thenode);
+static const char *defaultreason = "You (%u) have been disconnected for violating our terms of service";
 
 struct kill_localdata {
   unsigned int marker;
@@ -42,13 +44,18 @@ struct searchNode *kill_parse(int type, int argc, char **argv) {
     localdata->marker = nextnickmarker();
 
   if (argc==1) {
-    len = snprintf(localdata->reason, NSMAX_REASON_LEN, ":%s", argv[0]);
-    /* strip leading and trailing '"'s */
-    localdata->reason[1] = ' ';
-    localdata->reason[len-1] = '\0';
+    char *p = argv[0];
+    if(*p == '\"')
+      *p++;
+    len = strlcpy(localdata->reason, p, sizeof(localdata->reason));
+    if(len >= sizeof(localdata->reason)) {
+      localdata->reason[sizeof(localdata->reason)-1] = '\0';
+    } else {
+      localdata->reason[len-1] = '\0';
+    }
   }
   else
-    snprintf(localdata->reason, NSMAX_REASON_LEN, ".");
+    strlcpy(localdata->reason, defaultreason, sizeof(localdata->reason));
 
   if (!(thenode=(struct searchNode *)malloc(sizeof (struct searchNode)))) {
     /* couldn't malloc() memory for thenode, so free localdata to avoid leakage */
@@ -92,6 +99,7 @@ void kill_free(struct searchNode *thenode) {
   chanindex *cip, *ncip;
   int i, j, safe=0;
   unsigned int nickmarker;
+  char msgbuf[512];
 
   localdata = thenode->localdata;
 
@@ -127,9 +135,10 @@ void kill_free(struct searchNode *thenode) {
     for (i=0;i<NICKHASHSIZE;i++) {
       for(np=nicktable[i];np;np=nnp) {
         nnp = np->next;
-        if (np->marker == nickmarker) 
-          killuser(NULL, np, "You (%s!%s@%s) have been disconnected for violating our terms of service%s", 
-                         np->nick,np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+        if (np->marker == nickmarker) {
+          nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
+          killuser(NULL, np, "%s", msgbuf);
+        }
       }
     }
   }
@@ -139,8 +148,8 @@ void kill_free(struct searchNode *thenode) {
         nnp = np->next;
         if (np->marker == localdata->marker) {
           if (!IsOper(np) && !IsService(np) && !IsXOper(np)) {
-            killuser(NULL, np, "You (%s!%s@%s) have been disconnected for violating our terms of service%s", np->nick,
-              np->ident, IPtostr(np->p_ipaddr), localdata->reason);
+            nssnprintf(msgbuf, sizeof(msgbuf), localdata->reason, np);
+            killuser(NULL, np, "%s", msgbuf);
           }
           else
               safe++;