]> jfr.im git - irc/quakenet/newserv.git/blobdiff - trojanscan/trojanscan.c
Sigh
[irc/quakenet/newserv.git] / trojanscan / trojanscan.c
index ba60984fa06ac1ce33cb8e8e0b97f9b649e02238..38eacd7b40d4126b61adc64c304981bcb9e666f6 100644 (file)
  */
 
 #include "trojanscan.h"
+#include "../lib/strlfunc.h"
+#include "../lib/version.h"
+
+MODULE_VERSION(TROJANSCAN_VERSION " / $Id: trojanscan.c 663 2006-05-16 17:27:36Z newserv $")
 
 void _init() {
   trojanscan_cmds = newcommandtree();
@@ -32,7 +36,7 @@ void _init() {
 
   addcommandtotree(trojanscan_cmds, "rehash", TROJANSCAN_ACL_WEBSITE, 0, &trojanscan_rehash);
 
-  addcommandtotree(trojanscan_cmds, "cat", TROJANSCAN_ACL_CAT | TROJANSCAN_ACL_OPER, 1, &trojanscan_cat);
+  addcommandtotree(trojanscan_cmds, "cat", TROJANSCAN_ACL_OPER, 1, &trojanscan_cat);
 
   addcommandtotree(trojanscan_cmds, "reschedule", TROJANSCAN_ACL_DEVELOPER | TROJANSCAN_ACL_OPER, 0, &trojanscan_reschedule);
   
@@ -153,6 +157,11 @@ void trojanscan_connect(void *arg) {
   trojanscan_maxusers = atoi(temp->content);
   freesstring(temp);
   
+  length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_MINIMUM_HOSTS_BEFORE_POOL);
+  temp = getcopyconfigitem("trojanscan", "minpoolhosts", buf, length);
+  trojanscan_min_hosts = atoi(temp->content);
+  freesstring(temp);
+
   if ((trojanscan_cycletime / trojanscan_maxchans) < 1) {
     Error("trojanscan", ERR_FATAL, "Cycletime / maxchans < 1, increase cycletime or decrease maxchans else cycling breaks.");
     return; /* PPA: module failed to load */
@@ -174,7 +183,7 @@ void trojanscan_connect(void *arg) {
   }
   
   trojanscan_database_query("CREATE TABLE phrases (id INT(10) PRIMARY KEY AUTO_INCREMENT, wormid INT(10) NOT NULL, phrase TEXT NOT NULL, priority INT(10) DEFAULT 0 NOT NULL, dateadded int(10))");
-  trojanscan_database_query("CREATE TABLE worms (id INT(10) PRIMARY KEY AUTO_INCREMENT, wormname TEXT NOT NULL, glinetype INT DEFAULT 0, data text, hitmsgs BOOL DEFAULT 1, hitchans BOOL DEFAULT 0, epidemic BOOL DEFAULT 0)");
+  trojanscan_database_query("CREATE TABLE worms (id INT(10) PRIMARY KEY AUTO_INCREMENT, wormname TEXT NOT NULL, glinetype INT DEFAULT 0, data text, hitmsgs BOOL DEFAULT 1, hitchans BOOL DEFAULT 0, epidemic BOOL DEFAULT 0, privinfo text)");
   trojanscan_database_query("CREATE TABLE logs (id INT(10) PRIMARY KEY AUTO_INCREMENT, userid INT(10) NOT NULL, act TEXT NOT NULL, description TEXT NOT NULL, ts TIMESTAMP)");
   trojanscan_database_query("CREATE TABLE channels (id INT(10) PRIMARY KEY AUTO_INCREMENT, channel VARCHAR(%d) NOT NULL, exempt BOOL DEFAULT 0)", CHANNELLEN);
   trojanscan_database_query("CREATE TABLE users (id INT(10) PRIMARY KEY AUTO_INCREMENT, authname VARCHAR(%d) NOT NULL, authlevel TINYINT(4) NOT NULL)", ACCOUNTLEN);
@@ -183,7 +192,7 @@ void trojanscan_connect(void *arg) {
   trojanscan_database_query("CREATE TABLE wwwlogs (id INT(10) PRIMARY KEY AUTO_INCREMENT, authid INT(10) NOT NULL, ip VARCHAR(15), action TEXT, ts TIMESTAMP)");
   trojanscan_database_query("CREATE TABLE unknownlog (id INT(10) PRIMARY KEY AUTO_INCREMENT, data TEXT, user VARCHAR(%d) NOT NULL, ts TIMESTAMP)", NICKLEN+USERLEN+HOSTLEN+3);
   
-  trojanscan_database_query("DELETE FROM settings WHERE setting = 'rehash'");
+  trojanscan_database_query("DELETE FROM settings");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('rehash','0')");
   trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('changed','0')");
   
@@ -204,6 +213,14 @@ void trojanscan_connect(void *arg) {
     if(!localjoinchannel(trojanscan_nick, cp))
       localgetops(trojanscan_nick, cp);
   }
+
+  cp = findchannel(TROJANSCAN_PEONCHANNEL);
+  if (!cp) {
+    localcreatechannel(trojanscan_nick, TROJANSCAN_PEONCHANNEL);
+  } else {
+    if(!localjoinchannel(trojanscan_nick, cp))
+      localgetops(trojanscan_nick, cp);
+  }
   
   freesstring(mnick);
   freesstring(myident);
@@ -217,7 +234,6 @@ void trojanscan_connect(void *arg) {
   freesstring(dbport);
   trojanscan_registerclones(NULL);
   
-  trojanscan_initialschedule = scheduleoneshot(time(NULL) + 300, &trojanscan_fill_channels, NULL);
   trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
 
 }
@@ -245,11 +261,12 @@ void trojanscan_free_database(void) {
   for(i=0;i<trojanscan_database.total_channels;i++)
     freesstring(trojanscan_database.channels[i].name);
   free(trojanscan_database.channels);
-  for(i=0;i<trojanscan_database.total_phrases;i++)
-    if (trojanscan_database.phrases[i].phrase) {
-      free(trojanscan_database.phrases[i].phrase);
-      free(trojanscan_database.phrases[i].hint);
-    }
+  for(i=0;i<trojanscan_database.total_phrases;i++) {
+    if (trojanscan_database.phrases[i].phrase)
+      pcre_free(trojanscan_database.phrases[i].phrase);
+    if (trojanscan_database.phrases[i].hint)
+      pcre_free(trojanscan_database.phrases[i].hint);
+  }
   free(trojanscan_database.phrases);
   for(i=0;i<trojanscan_database.total_worms;i++)
     freesstring(trojanscan_database.worms[i].name);
@@ -427,9 +444,10 @@ void trojanscan_read_database(int first_time) {
             if (!(trojanscan_database.phrases[i].phrase = pcre_compile(sqlrow[1], PCRE_CASELESS, &error, &erroroffset, NULL))) {
               Error("trojanscan", ERR_WARNING, "Error compiling expression %s at offset %d: %s", sqlrow[1], erroroffset, error);
             } else {
-              if ((trojanscan_database.phrases[i].hint = pcre_study(trojanscan_database.phrases[i].phrase, 0, &error))) {
+              trojanscan_database.phrases[i].hint = pcre_study(trojanscan_database.phrases[i].phrase, 0, &error);
+              if (error) {
                 Error("trojanscan", ERR_WARNING, "Error studying expression %s: %s", sqlrow[1], error);
-                free(trojanscan_database.phrases[i].phrase);
+                pcre_free(trojanscan_database.phrases[i].phrase);
                 trojanscan_database.phrases[i].phrase = NULL;
               }
             }
@@ -466,6 +484,7 @@ void trojanscan_log(nick *np, char *event, char *details, ...) {
 void trojanscan_generateclone(void *arg) {
   int i, loops = 0, modes = UMODE_XOPER | UMODE_INV;
   char c_nick[NICKLEN+1], c_ident[USERLEN+1], c_host[HOSTLEN+1], c_real[REALLEN+1];
+  long fakeip;
 
   i = (int)arg;
 
@@ -484,11 +503,11 @@ void trojanscan_generateclone(void *arg) {
     trojanscan_genident(c_ident, trojanscan_minmaxrand(4, TROJANSCAN_MMIN(8, USERLEN)));
   
   if(trojanscan_hostmode) {
-    trojanscan_generatehost(c_host, HOSTLEN);
+    trojanscan_generatehost(c_host, HOSTLEN, &fakeip);
     if(!c_host[0])
-      trojanscan_genhost(c_host, HOSTLEN);
+      trojanscan_genhost(c_host, HOSTLEN, &fakeip);
   } else {
-    trojanscan_genhost(c_host, HOSTLEN);
+    trojanscan_genhost(c_host, HOSTLEN, &fakeip);
   }
   
   trojanscan_generaterealname(c_real, REALLEN);
@@ -496,6 +515,13 @@ void trojanscan_generateclone(void *arg) {
     trojanscan_genreal(c_real, trojanscan_minmaxrand(15, TROJANSCAN_MMIN(50, REALLEN)));
 
   trojanscan_swarm[i].clone = registerlocaluser(c_nick, c_ident, c_host, c_real, NULL, modes, &trojanscan_clonehandlemessages);
+  trojanscan_swarm[i].fakeip = fakeip;
+
+  if(trojanscan_swarm[i].clone && !trojanscan_swarm_created) {
+    nick *np = trojanscan_selectuser();
+    if(np) /* select a 'random' sign on time for whois generation */
+      trojanscan_swarm[i].clone->timestamp = np->timestamp;
+  }
   trojanscan_swarm[i].remaining = trojanscan_minmaxrand(5, 100);
 
   trojanscan_swarm[i].sitting = 0;
@@ -540,6 +566,8 @@ void trojanscan_registerclones(void *arg) {
     trojanscan_generateclone((void *)i);
   trojanscan_mainchanmsg("n: swarm (%d clones) created.", TROJANSCAN_CLONE_TOTAL);
   trojanscan_swarm_created = 1;
+
+  trojanscan_initialschedule = scheduleoneshot(time(NULL) + 5, &trojanscan_fill_channels, NULL);
 }
 
 int trojanscan_status(void *sender, int cargc, char **cargv) {
@@ -884,7 +912,7 @@ int trojanscan_user_level_by_authname(char *authname) {
       if (trojanscan_database_num_rows(res) > 0) {
         trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
         result = atoi(sqlrow[0]);
-        strncpy(authname, sqlrow[1], sl);
+        strlcpy(authname, sqlrow[1], sl + 1);
       }
       trojanscan_database_free_result(res);
     }
@@ -948,6 +976,20 @@ struct trojanscan_clones *trojanscan_selectclone(char type) {
 
 }
 
+/* hack hack hack */
+int trojanscan_nickbanned(trojanscan_clones *np, channel *cp) {
+  int ret;
+  long realip = np->clone->ipaddress;
+
+  np->clone->ipaddress = np->fakeip;
+
+  ret = nickbanned(np->clone, cp);
+
+  np->clone->ipaddress = realip;
+
+  return ret;
+}
+
 struct trojanscan_realchannels *trojanscan_allocaterc(char *chan) {
   struct trojanscan_realchannels *rc;
   struct trojanscan_clones *clonep;
@@ -988,7 +1030,7 @@ struct trojanscan_realchannels *trojanscan_allocaterc(char *chan) {
       trojanscan_errorcode = 6;
       return NULL;
     }
-    if(!nickbanned(clonep->clone, cp))
+    if(!trojanscan_nickbanned(clonep, cp))
       break;
   } while (--attempts_left > 0);
 
@@ -1279,7 +1321,7 @@ int trojanscan_add_ll(struct trojanscan_prechannels **head, struct trojanscan_pr
 void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count) {
   int i, j, marked;
   struct trojanscan_prechannels *lp;
-  struct trojanscan_templist *markedlist;
+  struct trojanscan_templist *markedlist = NULL;
 
   if(count > 0) {
     markedlist = (struct trojanscan_templist *)calloc(count, sizeof(struct trojanscan_templist));
@@ -1289,15 +1331,17 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
   
   for(i=0;i<trojanscan_activechans;i++) {
     marked = 0;    
-    for(lp=hp,j=0;j<count&&lp;j++,lp=lp->next) {
-      if(!markedlist[j].active && !lp->exempt && !ircd_strcmp(lp->name->content, trojanscan_chans[i].channel->content)) { /* we're already on the channel */
-        if(trojanscan_chans[i].watch_clone) {
-          markedlist[j].active = 1;
-          markedlist[j].watch_clone = trojanscan_chans[i].watch_clone;
-          lp->watch_clone = trojanscan_chans[i].watch_clone;
+    if(markedlist) {
+      for(lp=hp,j=0;j<count&&lp;j++,lp=lp->next) {
+        if(!markedlist[j].active && !lp->exempt && !ircd_strcmp(lp->name->content, trojanscan_chans[i].channel->content)) { /* we're already on the channel */
+          if(trojanscan_chans[i].watch_clone) {
+            markedlist[j].active = 1;
+            markedlist[j].watch_clone = trojanscan_chans[i].watch_clone;
+            lp->watch_clone = trojanscan_chans[i].watch_clone;
+          }
+          marked = 1;
+          break;
         }
-        marked = 1;
-        break;
       }
     }
     if(!marked && trojanscan_chans[i].watch_clone) {
@@ -1307,6 +1351,9 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
     }
   }
   
+  if(!markedlist)
+    return;
+
   for(j=0,lp=hp;j<count&&lp;j++,lp=lp->next) {
     if((!markedlist[j].active || !markedlist[j].watch_clone) && !lp->exempt) {
       channel *cp = findchannel(lp->name->content);
@@ -1316,7 +1363,7 @@ void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count)
           lp->watch_clone = trojanscan_selectclone(TROJANSCAN_WATCH_CLONES);      
           if(!lp->watch_clone)
             break;
-          if(!nickbanned(lp->watch_clone->clone, cp)) {
+          if(!trojanscan_nickbanned(lp->watch_clone, cp)) {
             if(localjoinchannel(lp->watch_clone->clone, cp))
               lp->watch_clone = NULL;
             break;
@@ -1350,8 +1397,7 @@ void trojanscan_fill_channels(void *arg) {
   
   for (i=0;i<CHANNELHASHSIZE;i++) {
     for(chn=chantable[i];chn;chn=chn->next) {
-      /* TODO, add IsInvite */
-      if (chn->channel && !IsKey(chn->channel) && (chn->channel->users->totalusers >= trojanscan_minchansize)) {
+      if (chn->channel && !IsKey(chn->channel) && !IsInviteOnly(chn->channel) && !IsRegOnly(chn->channel) && (chn->channel->users->totalusers >= trojanscan_minchansize)) {
         lp = (trojanscan_prechannels *)malloc(sizeof(trojanscan_prechannels));
         lp->name = chn->name;
         lp->size = chn->channel->users->totalusers;
@@ -1716,13 +1762,11 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
             if (worm->monitor) {
               glining = 0;
               usercount = -1;
-            } else if (worm->glinehost) {
+            } else if (worm->glinehost && (hp->clonecount <= TROJANSCAN_MAX_HOST_GLINE)) {
               snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", trojanscan_iptostr(ip, sizeof(ip) - 1, sender->ipaddress));
               usercount = hp->clonecount;
             }
-
-            /* if the host is >maxusers then it's a trusted host and we can gline by ident */
-            if (worm->glineuser || (worm->glinehost && (usercount > trojanscan_maxusers))) {
+            else if (worm->glineuser || (worm->glinehost && hp->clonecount > TROJANSCAN_MAX_HOST_GLINE)) {
               userbit = sender->ident;
               if(userbit[0] == '~')
                 userbit++;
@@ -1776,6 +1820,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
                   matchbuf[0] = 0;
               
               trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s %s%s", mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+/*              trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", mt, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:""); */
             } else {
               int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
               if(glinetime > 7 * 24)
@@ -1784,7 +1829,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
               trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, trojanscan_database.phrases[i].id, mt, glining);          
               trojanscan_database.glines++;
               
-              irc_send("%s GL * +%s %d %d :You (%s!%s@%s) are infected with a trojan (%s), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, getnettime(), sender->nick, sender->ident, sender->host->name->content, worm->name->content, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
+              irc_send("%s GL * +%s %d :You (%s!%s@%s) are infected with a trojan (%s), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, sender->nick, sender->ident, sender->host->name->content, worm->name->content, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
 
               trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s f: %d", glinemask, mt, sender->nick, sender->ident, sender->host->name->content, mt=='N'||mt=='M'?" #: ":"", mt=='N'||mt=='M'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", frequency);
             }
@@ -1867,7 +1912,7 @@ void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args)
               return;
             }
 
-            rj->clone = target;
+            rj->clone = rp->clone;
             rj->next = trojanscan_schedulerejoins;
             trojanscan_schedulerejoins = rj;
 
@@ -1892,10 +1937,10 @@ void trojanscan_rejoin_channel(void *arg) {
       rj->rp->donotpart = 1; /* we were the last user on the channel, so we need to be VERY careful freeing it */
     } else {
       if(!rj->rp->donotpart && !rj->rp->kickedout) { /* check we're allowed to join channels (not killed), and we're the last one to join */
-        if (nickbanned(rj->clone, cp)) {
+        if (trojanscan_nickbanned(rj->clone, cp)) {
           rj->rp->donotpart = 1;
         } else {
-          localjoinchannel(rj->clone, cp);
+          localjoinchannel(rj->clone->clone, cp);
         }
       }
     }
@@ -1951,6 +1996,23 @@ void trojanscan_mainchanmsg(char *message, ...) {
   sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
 }
 
+void trojanscan_peonchanmsg(char *message, ...) {
+  char buf[513];
+  va_list va;
+  channel *cp;
+  
+  if (!trojanscan_nick)
+    return;
+  if (!(cp = findchannel(TROJANSCAN_PEONCHANNEL)))
+    return;
+    
+  va_start(va, message);
+  vsnprintf(buf, sizeof(buf) - 1, message, va);
+  va_end(va);
+  
+  sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
+}
+
 int trojanscan_minmaxrand(float min, float max) {
   return (int)((max-min+1)*rand()/(RAND_MAX+min))+min;
 }
@@ -2020,7 +2082,7 @@ void trojanscan_genident(char *ptc, char size) {
   ptc[i] = '\0';
 }
 
-void trojanscan_genhost(char *ptc, char size) {
+void trojanscan_genhost(char *ptc, char size, long *fakeip) {
   int dots = trojanscan_minmaxrand(2, 5), i, dotexist = 0, cur;
   
   while (!dotexist) {
@@ -2042,6 +2104,8 @@ void trojanscan_genhost(char *ptc, char size) {
     }
   }
   ptc[i] = '\0';
+
+  *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
 }
 
 void trojanscan_genreal(char *ptc, char size) {
@@ -2078,7 +2142,7 @@ int trojanscan_generatepool(void) {
     for (np=nicktable[i];np;np=np->next)
       j++;
   
-  if(j < TROJANSCAN_MINIMUM_HOSTS_BEFORE_POOL)
+  if(j < trojanscan_min_hosts)
     return 0;
   
   if(TROJANSCAN_HOST_MODE == TROJANSCAN_STEAL_HOST)
@@ -2137,15 +2201,35 @@ nick *trojanscan_selectuser(void) {
   return NULL;
 }
 
-void trojanscan_generatehost(char *buf, int maxsize) {
+host *trojanscan_selecthost(void) {
+  int target = trojanscan_minmaxrand(0, 500), loops = 150, j;
+  host *hp;
+  do {
+    for (j=trojanscan_minmaxrand(0, HOSTHASHSIZE-1);j<HOSTHASHSIZE;j++)
+      for(hp=hosttable[j];hp;hp=hp->next)
+        if (!--target)
+          return hp;
+  } while(--loops > 0);
+
+  return NULL;
+}
+
+void trojanscan_generatehost(char *buf, int maxsize, long *fakeip) {
   if(TROJANSCAN_HOST_MODE == TROJANSCAN_STEAL_HOST) {
-    nick *np;
+    host *hp;
     int loops = 20;
+
     buf[0] = '\0';
+
     do {
-      np = trojanscan_selectuser();
-      if(np && !trojanscan_isip(np->host->name->content)) {
-        strncpy(buf, np->host->name->content, maxsize);
+      hp = trojanscan_selecthost();
+      if(hp && (hp->clonecount <= TROJANSCAN_MAX_CLONE_COUNT) && !trojanscan_isip(hp->name->content)) {
+        strlcpy(buf, hp->name->content, maxsize + 1);
+        if(hp->nicks) {
+          *fakeip = hp->nicks->ipaddress;
+        } else {
+          *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
+        }
         break;
       }
     } while(--loops > 0);
@@ -2184,6 +2268,8 @@ void trojanscan_generatehost(char *buf, int maxsize) {
     buf[a] = '\0';
     free(choices);
     free(lengths);
+
+    *fakeip = (trojanscan_minmaxrand(0, 65535) << 16) | trojanscan_minmaxrand(0, 65535);
   }
 }
 
@@ -2213,14 +2299,14 @@ void trojanscan_generateident(char *buf, int maxsize) {
   nick *np = trojanscan_selectuser();
   buf[0] = '\0';
   if(np)
-    strncpy(buf, np->ident, maxsize);
+    strlcpy(buf, np->ident, maxsize + 1);
 }
 
 void trojanscan_generaterealname(char *buf, int maxsize) {
   nick *np = trojanscan_selectuser();
   buf[0] = '\0';
   if(np)
-    strncpy(buf, np->realname->name->content, maxsize);
+    strlcpy(buf, np->realname->name->content, maxsize + 1);
 }
 
 void trojanscan_database_close(void) {