/*
* Trojanscan version 2
*
- * Trojanscan copyright (C) Chris Porter 2002-2004
+ * Trojanscan copyright (C) Chris Porter 2002-2009
* Newserv bits copyright (C) David Mansell 2002-2003
*
* TODO: CHECK::
* - Poke splidge about +r'ing bots, potential problems:
- * - users whining about T clone stealing account
+ * - users might whine about T clone stealing account
* - would have to steal one already in use, so if trojans start using /msg q whois they'll see
* (though they have to be authed for this, they could use a clone of their own however)
*/
#include "trojanscan.h"
+#include "../lib/strlfunc.h"
+#include "../lib/version.h"
+#include "../core/nsmalloc.h"
+#include <stdint.h>
+
+#define tmalloc(x) nsmalloc(POOL_TROJANSCAN, x)
+#define tfree(x) nsfree(POOL_TROJANSCAN, x)
+
+MODULE_VERSION(TROJANSCAN_VERSION);
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf);
+char *trojanscan_sanitise(char *input);
+void trojanscan_refresh_settings(void);
+static void trojanscan_part_watch(int hook, void *arg);
+static void trojanscan_connect_nick(void *);
+
+#define TROJANSCAN_SETTING_SIZE 256
+#define TROJANSCAN_MAX_SETTINGS 50
+
+static struct {
+ char setting[TROJANSCAN_SETTING_SIZE];
+ char value[TROJANSCAN_SETTING_SIZE];
+} trojanscan_settings[TROJANSCAN_MAX_SETTINGS];
+
+static int settingcount = 0;
+static char *versionreply;
+static int hooksregistered = 0;
+static void *trojanscan_connect_nick_schedule;
void _init() {
trojanscan_cmds = newcommandtree();
addcommandtotree(trojanscan_cmds, "changelev", TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_OPER, 2, &trojanscan_changelev);
addcommandtotree(trojanscan_cmds, "deluser", TROJANSCAN_ACL_TEAMLEADER | TROJANSCAN_ACL_OPER, 2, &trojanscan_deluser);
- addcommandtotree(trojanscan_cmds, "mew", TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_OPER, 2, &trojanscan_mew);
+ addcommandtotree(trojanscan_cmds, "mew", TROJANSCAN_ACL_STAFF, 2, &trojanscan_mew);
addcommandtotree(trojanscan_cmds, "status", TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_OPER, 0, &trojanscan_status);
addcommandtotree(trojanscan_cmds, "listusers", TROJANSCAN_ACL_TEAMLEADER, 0, &trojanscan_listusers);
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);
if (trojanscan_connect_schedule)
deleteschedule(trojanscan_connect_schedule, &trojanscan_connect, NULL);
+ if (trojanscan_connect_nick_schedule)
+ deleteschedule(trojanscan_connect_nick_schedule, &trojanscan_connect_nick, NULL);
+
if(trojanscan_schedule)
deleteschedule(trojanscan_schedule, &trojanscan_dojoin, NULL);
if(trojanscan_cloneschedule)
deleteschedule(trojanscan_poolschedule, &trojanscan_registerclones, NULL);
+ if(hooksregistered)
+ deregisterhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+
while(rp) {
deleteschedule(rp->schedule, &trojanscan_dopart, (void *)rp);
oldrp = rp;
rp = rp->next;
- free(oldrp);
+ tfree(oldrp);
}
while(rj) {
freesstring(rj->channel);
oldrj = rj;
rj = rj->next;
- free(oldrj);
+ tfree(oldrj);
}
if(trojanscan_initialschedule)
for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
if(trojanscan_swarm[i].clone) {
deregisterlocaluser(trojanscan_swarm[i].clone, NULL);
+ derefnode(iptree, trojanscan_swarm[i].fakeipnode);
trojanscan_swarm[i].clone = NULL;
}
trojanscan_free_database();
for (i=0;i<trojanscan_tailpoolsize;i++)
freesstring(trojanscan_tailpool[i]);
trojanscan_database_close();
+
+ deletecommandfromtree(trojanscan_cmds, "showcommands", &trojanscan_showcommands);
+ deletecommandfromtree(trojanscan_cmds, "help", &trojanscan_help);
+ deletecommandfromtree(trojanscan_cmds, "hello", &trojanscan_hello);
+ deletecommandfromtree(trojanscan_cmds, "join", &trojanscan_userjoin);
+ deletecommandfromtree(trojanscan_cmds, "chanlist", &trojanscan_chanlist);
+ deletecommandfromtree(trojanscan_cmds, "whois", &trojanscan_whois);
+ deletecommandfromtree(trojanscan_cmds, "changelev", &trojanscan_changelev);
+ deletecommandfromtree(trojanscan_cmds, "deluser", &trojanscan_deluser);
+ deletecommandfromtree(trojanscan_cmds, "mew", &trojanscan_mew);
+ deletecommandfromtree(trojanscan_cmds, "status", &trojanscan_status);
+ deletecommandfromtree(trojanscan_cmds, "listusers", &trojanscan_listusers);
+ deletecommandfromtree(trojanscan_cmds, "rehash", &trojanscan_rehash);
+ deletecommandfromtree(trojanscan_cmds, "cat", &trojanscan_cat);
+ deletecommandfromtree(trojanscan_cmds, "reschedule", &trojanscan_reschedule);
+
+ destroycommandtree(trojanscan_cmds);
+ nscheckfreeall(POOL_TROJANSCAN);
+}
+
+static void trojanscan_connect_nick(void *arg) {
+ sstring *mnick, *myident, *myhost, *myrealname, *myauthname;
+ channel *cp;
+
+ mnick = getcopyconfigitem("trojanscan", "nick", "T", NICKLEN);
+ myident = getcopyconfigitem("trojanscan", "ident", "trojanscan", NICKLEN);
+ myhost = getcopyconfigitem("trojanscan", "hostname", "trojanscan.quakenet.org", HOSTLEN);
+ myrealname = getcopyconfigitem("trojanscan", "realname", "Trojanscan v" TROJANSCAN_VERSION, REALLEN);
+ myauthname = getcopyconfigitem("trojanscan", "authname", "T", ACCOUNTLEN);
+
+ trojanscan_nick = registerlocaluser(mnick->content, myident->content, myhost->content, myrealname->content, myauthname->content, UMODE_SERVICE | UMODE_DEAF |
+ UMODE_OPER | UMODE_INV |
+ UMODE_ACCOUNT,
+ &trojanscan_handlemessages);
+ freesstring(mnick);
+ freesstring(myident);
+ freesstring(myhost);
+ freesstring(myrealname);
+ freesstring(myauthname);
+
+ cp = findchannel(TROJANSCAN_OPERCHANNEL);
+ if (!cp) {
+ localcreatechannel(trojanscan_nick, TROJANSCAN_OPERCHANNEL);
+ } else {
+ if(!localjoinchannel(trojanscan_nick, cp))
+ localgetops(trojanscan_nick, cp);
+ }
+
+ cp = findchannel(TROJANSCAN_CHANNEL);
+ if (!cp) {
+ localcreatechannel(trojanscan_nick, TROJANSCAN_CHANNEL);
+ } else {
+ if(!localjoinchannel(trojanscan_nick, cp))
+ localgetops(trojanscan_nick, cp);
+ }
+
+#ifdef TROJANSCAN_PEONCHANNEL
+ cp = findchannel(TROJANSCAN_PEONCHANNEL);
+ if (!cp) {
+ localcreatechannel(trojanscan_nick, TROJANSCAN_PEONCHANNEL);
+ } else {
+ if(!localjoinchannel(trojanscan_nick, cp))
+ localgetops(trojanscan_nick, cp);
+ }
+#endif
}
void trojanscan_connect(void *arg) {
- sstring *mnick, *myident, *myhost, *myrealname, *myauthname;
sstring *dbhost, *dbuser, *dbpass, *db, *dbport, *temp;
- channel *cp;
int length, i;
char buf[10];
trojanscan_database.glines = 0;
trojanscan_database.detections = 0;
- mnick = getcopyconfigitem("trojanscan", "nick", "T", NICKLEN);
- myident = getcopyconfigitem("trojanscan", "ident", "trojanscan", NICKLEN);
- myhost = getcopyconfigitem("trojanscan", "hostname", "trojanscan.slug.netsplit.net", HOSTLEN);
- myrealname = getcopyconfigitem("trojanscan", "realname", "Trojanscan v" TROJANSCAN_VERSION, REALLEN);
- myauthname = getcopyconfigitem("trojanscan", "authname", "T", ACCOUNTLEN);
-
- dbhost = getcopyconfigitem("trojanscan", "dbhost", "localhost", HOSTLEN);
- dbuser = getcopyconfigitem("trojanscan", "dbuser", "", NICKLEN);
- dbpass = getcopyconfigitem("trojanscan", "dbpass", "", REALLEN);
- db = getcopyconfigitem("trojanscan", "db", "", NICKLEN);
+ dbhost = getcopyconfigitem("trojanscan", "dbhost", "localhost", 100);
+ dbuser = getcopyconfigitem("trojanscan", "dbuser", "moo", 100);
+ dbpass = getcopyconfigitem("trojanscan", "dbpass", "changeme", 100);
+ db = getcopyconfigitem("trojanscan", "db", "moo", 100);
- dbport = getcopyconfigitem("trojanscan", "dbport", "3306", ACCOUNTLEN);
+ dbport = getcopyconfigitem("trojanscan", "dbport", "3306", 10);
length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_MAXCHANS);
temp = getcopyconfigitem("trojanscan", "maxchans", buf, length);
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!!");
- return; /* PPA: splidge: do something here 8]! */
+ Error("trojanscan", ERR_FATAL, "Cycletime / maxchans < 1, increase cycletime or decrease maxchans else cycling breaks.");
+ return; /* PPA: module failed to load */
}
length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_MINIMUM_CHANNEL_SIZE);
trojanscan_minchansize = atoi(temp->content);
freesstring(temp);
- trojanscan_nick = registerlocaluser(mnick->content, myident->content, myhost->content, myrealname->content, myauthname->content, UMODE_SERVICE | UMODE_DEAF |
- UMODE_OPER | UMODE_INV |
- UMODE_ACCOUNT,
- &trojanscan_handlemessages);
+ trojanscan_connect_nick(NULL);
if (trojanscan_database_connect(dbhost->content, dbuser->content, dbpass->content, db->content, atoi(dbport->content)) < 0) {
Error("trojanscan", ERR_FATAL, "Cannot connect to database host!");
- return; /* PPA: splidge: do something here 8]! */
+ return; /* PPA: module failed to load */
}
- 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 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), disabled BOOL DEFAULT 0 NOT NULL)");
+ 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);
trojanscan_database_query("CREATE TABLE hits (id INT(10) PRIMARY KEY AUTO_INCREMENT, nickname VARCHAR(%d) NOT NULL, ident VARCHAR(%d) NOT NULL, host VARCHAR(%d) NOT NULL, phrase INT(10) NOT NULL, ts TIMESTAMP, messagetype VARCHAR(1) NOT NULL DEFAULT 'm', glined BOOL DEFAULT 1)", NICKLEN, USERLEN, HOSTLEN);
- trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(15) NOT NULL, value VARCHAR(15) NOT NULL)");
+ trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(255) NOT NULL UNIQUE, value VARCHAR(255) NOT NULL)");
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 WHERE setting = 'rehash' OR setting = 'changed'");
trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('rehash','0')");
trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('changed','0')");
+
+ /* assumption: constants aren't supplied by someone evil */
+ trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('versionreply','" TROJANSCAN_DEFAULT_VERSION_REPLY "')");
+ trojanscan_refresh_settings();
trojanscan_read_database(1);
- cp = findchannel(TROJANSCAN_OPERCHANNEL);
- if (!cp) {
- localcreatechannel(trojanscan_nick, TROJANSCAN_OPERCHANNEL);
- } else {
- localjoinchannel(trojanscan_nick, cp);
- localgetops(trojanscan_nick, cp);
- }
-
- cp = findchannel(TROJANSCAN_CHANNEL);
- if (!cp) {
- localcreatechannel(trojanscan_nick, TROJANSCAN_CHANNEL);
- } else {
- localjoinchannel(trojanscan_nick, cp);
- localgetops(trojanscan_nick, cp);
- }
-
- freesstring(mnick);
- freesstring(myident);
- freesstring(myhost);
- freesstring(myrealname);
- freesstring(myauthname);
freesstring(dbhost);
freesstring(dbuser);
freesstring(dbpass);
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);
+ registerhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
+ hooksregistered = 1;
+}
+
+char *trojanscan_get_setting(char *setting) {
+ int i;
+
+ for(i=0;i<settingcount;i++)
+ if(!strcmp(trojanscan_settings[i].setting, setting))
+ return trojanscan_settings[i].value;
+
+ return NULL;
+}
+
+void trojanscan_refresh_settings(void) {
+ trojanscan_database_res *res;
+ trojanscan_database_row sqlrow;
+ int i = 0;
+
+ if(trojanscan_database_query("SELECT setting, value FROM settings"))
+ return;
+
+ if(!(res = trojanscan_database_store_result(&trojanscan_sql)))
+ return;
+
+ if (trojanscan_database_num_rows(res) <= 0)
+ return;
+
+ while((sqlrow = trojanscan_database_fetch_row(res))) {
+ strlcpy(trojanscan_settings[i].setting, sqlrow[0], TROJANSCAN_SETTING_SIZE);
+ strlcpy(trojanscan_settings[i].value, sqlrow[1], TROJANSCAN_SETTING_SIZE);
+
+ trojanscan_sanitise(trojanscan_settings[i].value);
+
+ if(++i == TROJANSCAN_MAX_SETTINGS)
+ break;
+ }
+
+ settingcount = i;
+
+ trojanscan_database_free_result(res);
+
+ /* optimisation hack */
+ versionreply = trojanscan_get_setting("versionreply");
}
void trojanscan_rehash_schedule(void *arg) {
+ char *v;
trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
- if (!(trojanscan_database_query("SELECT value FROM settings WHERE setting = 'rehash'"))) {
- trojanscan_database_res *res;
- if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
- if (trojanscan_database_num_rows(res) > 0) {
- trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
- if (sqlrow && (sqlrow[0][0] == '1')) {
- trojanscan_mainchanmsg("n: rehash initiated by website. . .");
- trojanscan_read_database(0);
- }
- }
- trojanscan_database_free_result(res);
- }
- }
-
+
+ trojanscan_refresh_settings();
+
+ v = trojanscan_get_setting("rehash");
+ if(v && v[0] == '1') {
+ trojanscan_mainchanmsg("n: rehash initiated by website. . .");
+ trojanscan_read_database(0);
+ }
}
void trojanscan_free_database(void) {
int i;
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);
- }
- free(trojanscan_database.phrases);
+ tfree(trojanscan_database.channels);
+ 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);
+ }
+ tfree(trojanscan_database.phrases);
for(i=0;i<trojanscan_database.total_worms;i++)
freesstring(trojanscan_database.worms[i].name);
- free(trojanscan_database.worms);
+ tfree(trojanscan_database.worms);
trojanscan_database.total_channels = 0;
trojanscan_database.total_phrases = 0;
trojanscan_database.total_worms = 0;
-
+ trojanscan_database.channels = NULL;
+ trojanscan_database.phrases = NULL;
+ trojanscan_database.worms = NULL;
+}
+
+char *trojanscan_sanitise(char *input) {
+ char *p;
+
+ for(p=input;*p;p++)
+ if(*p == '\r' || *p == '\n')
+ *p = '!';
+
+ return input;
}
sstring *trojanscan_getsstring(char *string, int length) {
if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
trojanscan_database.total_channels = trojanscan_database_num_rows(res);
if (trojanscan_database.total_channels > 0) {
- if ((trojanscan_database.channels = (trojanscan_channels *)malloc(sizeof(trojanscan_channels) * trojanscan_database.total_channels))) {
+ if ((trojanscan_database.channels = (trojanscan_channels *)tmalloc(sizeof(trojanscan_channels) * trojanscan_database.total_channels))) {
if ((trojanscan_database.total_channels>0) && trojanscan_database.channels) {
i = 0;
while((sqlrow = trojanscan_database_fetch_row(res))) {
- trojanscan_database.channels[i].name = trojanscan_getsstring(sqlrow[0], strlen(sqlrow[0]));
+ trojanscan_database.channels[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[0]), strlen(sqlrow[0]));
trojanscan_database.channels[i].exempt = (sqlrow[1][0] == '1');
i++;
}
if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
trojanscan_database.total_worms = trojanscan_database_num_rows(res);
if (trojanscan_database.total_worms > 0) {
- if ((trojanscan_database.worms = (trojanscan_worms *)malloc(sizeof(trojanscan_worms) * trojanscan_database.total_worms))) {
+ if ((trojanscan_database.worms = (trojanscan_worms *)tmalloc(sizeof(trojanscan_worms) * trojanscan_database.total_worms))) {
i = 0;
while((sqlrow = trojanscan_database_fetch_row(res))) {
trojanscan_database.worms[i].id = atoi(sqlrow[0]);
- trojanscan_database.worms[i].name = trojanscan_getsstring(sqlrow[1], strlen(sqlrow[1]));
+ trojanscan_database.worms[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[1]), strlen(sqlrow[1]));
tempresult = atoi(sqlrow[2]);
trojanscan_database.worms[i].glineuser = (tempresult == 0);
trojanscan_database.worms[i].glinehost = (tempresult == 1);
}
}
- if (!(trojanscan_database_query("SELECT id, phrase, wormid FROM phrases ORDER BY priority DESC"))) {
+ if (!(trojanscan_database_query("SELECT id, phrase, wormid FROM phrases WHERE disabled = 0 ORDER BY priority DESC"))) {
if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
trojanscan_database.total_phrases = trojanscan_database_num_rows(res);
if (trojanscan_database.total_phrases > 0) {
- if ((trojanscan_database.phrases = (trojanscan_phrases *)malloc(sizeof(trojanscan_phrases) * trojanscan_database.total_phrases))) {
+ if ((trojanscan_database.phrases = (trojanscan_phrases *)tmalloc(sizeof(trojanscan_phrases) * trojanscan_database.total_phrases))) {
i = 0;
while((sqlrow = trojanscan_database_fetch_row(res))) {
trojanscan_database.phrases[i].id = atoi(sqlrow[0]);
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;
}
}
}
trojanscan_database_query("UPDATE settings SET value = '0' where setting = 'rehash'");
-
}
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];
+ patricia_node_t *fakeip;
- i = (int)arg;
+ i = (int)((long)arg);
/* PPA: unlikely to be infinite */
do {
- if ((loops++ < 10) && trojanscan_hostmode) {
+ c_nick[0] = '\0';
+ if (!loops && trojanscan_hostmode) /* only have one go at this */
trojanscan_generatenick(c_nick, NICKLEN);
- } else {
+ if(!c_nick[0])
trojanscan_gennick(c_nick, trojanscan_minmaxrand(7, TROJANSCAN_MMIN(13, NICKLEN)));
- }
- } while (c_nick && (getnickbynick(c_nick) != NULL));
+ loops++;
+ } while ((getnickbynick(c_nick) != NULL));
trojanscan_generateident(c_ident, USERLEN);
- if(!c_ident)
+ if(!c_ident[0])
trojanscan_genident(c_ident, trojanscan_minmaxrand(4, TROJANSCAN_MMIN(8, USERLEN)));
if(trojanscan_hostmode) {
- trojanscan_generatehost(c_host, HOSTLEN);
- if(!c_host) {
- trojanscan_genhost(c_host, HOSTLEN);
- }
+ trojanscan_generatehost(c_host, HOSTLEN, &fakeip);
+ if(!c_host[0])
+ trojanscan_genhost(c_host, HOSTLEN, &fakeip);
} else {
- trojanscan_genhost(c_host, HOSTLEN);
+ trojanscan_genhost(c_host, HOSTLEN, &fakeip);
}
trojanscan_generaterealname(c_real, REALLEN);
- if(!c_real)
+ if(!c_real[0])
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].fakeipnode = 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;
if(trojanscan_chans) {
for(i=0;i<trojanscan_activechans;i++)
freesstring(trojanscan_chans[i].channel);
- free(trojanscan_chans);
+ tfree(trojanscan_chans);
trojanscan_chans = NULL;
trojanscan_activechans = 0;
}
}
for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
- trojanscan_generateclone((void *)i);
+ trojanscan_generateclone((void *)((long)i));
trojanscan_mainchanmsg("n: swarm (%d clones) created.", TROJANSCAN_CLONE_TOTAL);
trojanscan_swarm_created = 1;
+
+ trojanscan_initialschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_fill_channels, NULL);
}
int trojanscan_status(void *sender, int cargc, char **cargv) {
int trojanscan_chanlist(void *sender, int cargc, char **cargv) {
int i;
nick *np = (nick *)sender;
+ char buf[CHANNELLEN * 2 + 20];
trojanscan_reply(np, "Channel list (%d total):", trojanscan_activechans);
- for(i=0;i<trojanscan_activechans;i++)
- trojanscan_reply(np, "%s", trojanscan_chans[i].channel->content);
+ buf[0] = '\0';
+
+ for(i=0;i<trojanscan_activechans;i++) {
+ if(trojanscan_chans[i].channel->length + 3 > sizeof(buf) - strlen(buf)) {
+ trojanscan_reply(np, "%s", buf);
+ buf[0] = '\0';
+ }
+
+ /* if splidge sees this I'm going to die */
+ strlcat(buf, trojanscan_chans[i].channel->content, sizeof(buf));
+ strlcat(buf, " ", sizeof(buf));
+ }
+ if(buf[0])
+ trojanscan_reply(np, "%s", buf);
+
trojanscan_reply(np, "Done.");
return CMD_OK;
}
return CMD_ERROR;
}
for(i=0;i<TROJANSCAN_CLONE_TOTAL;i++) {
- if(trojanscan_swarm[i].clone->nick && !ircd_strcmp(trojanscan_swarm[i].clone->nick, np2->nick)) { /* PPA: ircd_strncmp ? - order of args? */
+ if(trojanscan_swarm[i].clone->nick && !ircd_strcmp(trojanscan_swarm[i].clone->nick, np2->nick)) {
trojanscan_reply(np, "Nickname : %s", np2->nick);
- trojanscan_reply(np, "Swarm nick : yes", trojanscan_swarm[i].clone->nick);
+ trojanscan_reply(np, "Swarm : yes");
return CMD_OK;
}
}
va_end(va);
if (cp) {
- sendmessagetochannel(trojanscan_nick, cp, buf);
+ sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
} else {
- sendmessagetouser(trojanscan_nick, np, buf);
+ sendmessagetouser(trojanscan_nick, np, "%s", buf);
}
}
} else {
trojanscan_reply(np, "Mewed at %s at %s.", cargv[1], np2->nick);
}
+
+ if(!IsOper(np))
+ trojanscan_mainchanmsg("n: mew: %s %s (%s/%s)", cargv[1], cp?cp->index->name->content:np2->nick, np->nick, np->authname);
+
return CMD_OK;
}
return CMD_ERROR;
}
- /* PPA: some opers/admins may not like this.... stuff them 8] */
while (fgets(buf, sizeof(buf) - 1, cat)) {
if ((p = strchr(buf, '\n'))) {
*p = '\0';
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);
}
if ((!rc->remaining) && (!rc->sitting)) {
if (rc->clone) {
deregisterlocaluser(rc->clone, NULL);
+ derefnode(iptree, rc->fakeipnode);
rc->clone = NULL;
}
- trojanscan_generateclone((void *)rc->index);
+ trojanscan_generateclone((void *)((long)rc->index));
}
}
- rc->remaining--;
- rc->sitting++;
}
return rc;
}
+/* hack hack hack */
+int trojanscan_nickbanned(trojanscan_clones *np, channel *cp) {
+ int ret;
+ patricia_node_t *realipnode = np->clone->ipnode;
+
+ np->clone->ipnode = np->fakeipnode;
+
+ ret = nickbanned(np->clone, cp);
+
+ np->clone->ipnode = realipnode;
+
+ return ret;
+}
+
struct trojanscan_realchannels *trojanscan_allocaterc(char *chan) {
struct trojanscan_realchannels *rc;
struct trojanscan_clones *clonep;
trojanscan_errorcode = 6;
return NULL;
}
- if(!nickbanned(clonep->clone, cp))
+ if(!trojanscan_nickbanned(clonep, cp))
break;
} while (--attempts_left > 0);
return NULL;
}
- rc = (struct trojanscan_realchannels *)malloc(sizeof(struct trojanscan_realchannels));
+ rc = (struct trojanscan_realchannels *)tmalloc(sizeof(struct trojanscan_realchannels));
rc->next = NULL;
rc->clone = clonep;
if (rc->clone && rc->clone->clone) {
if (!localjoinchannel(rc->clone->clone, rc->chan)) {
+ rc->clone->remaining--;
+ rc->clone->sitting++;
if (trojanscan_minmaxrand(1, TROJANSCAN_NICKCHANGE_ODDS)%TROJANSCAN_NICKCHANGE_ODDS == 0)
trojanscan_donickchange((void *)rc->clone);
int trojanscan_rehash(void *sender, int cargc, char **cargv) {
nick *np = (void *)sender;
+ trojanscan_refresh_settings();
trojanscan_read_database(0);
trojanscan_log(np, "rehash", "");
trojanscan_reply(np, "Done.");
for(position=*head;position;lastitem=position,position=position->next) {
if (!ircd_strcmp(position->name->content, newitem->name->content)) {
- free(newitem);
+ tfree(newitem);
return 0;
}
if (!location && (position->size < newitem->size)) {
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));
+ markedlist = (struct trojanscan_templist *)tmalloc(count * sizeof(struct trojanscan_templist));
if (!markedlist)
return;
+ memset(markedlist, 0, sizeof(struct trojanscan_templist) * 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) {
channel *cp = findchannel(trojanscan_chans[i].channel->content);
if(cp)
- localpartchannel(trojanscan_chans[i].watch_clone->clone, cp);
+ localpartchannel(trojanscan_chans[i].watch_clone->clone, cp, NULL);
}
}
+ 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);
lp->watch_clone = trojanscan_selectclone(TROJANSCAN_WATCH_CLONES);
if(!lp->watch_clone)
break;
- if(!nickbanned(lp->watch_clone->clone, cp)) {
- localjoinchannel(lp->watch_clone->clone, cp);
+ if(!trojanscan_nickbanned(lp->watch_clone, cp)) {
+ if(localjoinchannel(lp->watch_clone->clone, cp))
+ lp->watch_clone = NULL;
break;
}
} while(--attempts > 0);
}
}
- free(markedlist);
+ tfree(markedlist);
}
void trojanscan_fill_channels(void *arg) {
chanindex *chn;
for (count=i=0;i<trojanscan_database.total_channels;i++) {
- lp = (trojanscan_prechannels *)malloc(sizeof(trojanscan_prechannels));
+ lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
lp->name = trojanscan_database.channels[i].name;
lp->size = 65535;
lp->exempt = trojanscan_database.channels[i].exempt;
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)) {
- lp = (trojanscan_prechannels *)malloc(sizeof(trojanscan_prechannels));
+ if (chn->channel && !IsKey(chn->channel) && !IsInviteOnly(chn->channel) && !IsRegOnly(chn->channel) && (chn->channel->users->totalusers >= trojanscan_minchansize)) {
+ lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
lp->name = chn->name;
lp->size = chn->channel->users->totalusers;
lp->exempt = 0;
count = TROJANSCAN_MMIN(count, trojanscan_maxchans);
- /* TODO */
trojanscan_watch_clone_update(head, count);
trojanscan_free_channels();
- trojanscan_chans = (struct trojanscan_inchannel *)calloc(count, sizeof(struct trojanscan_inchannel));
+ trojanscan_chans = (struct trojanscan_inchannel *)tmalloc(count * sizeof(struct trojanscan_inchannel));
+ memset(trojanscan_chans, 0, count * sizeof(struct trojanscan_inchannel));
trojanscan_activechans = count;
i = 0;
trojanscan_chans[i++].watch_clone = lp->watch_clone;
}
if (last)
- free(last);
+ tfree(last);
}
if (last)
- free(last);
+ tfree(last);
if (trojanscan_activechans > 0) {
tempctime = trojanscan_cycletime / trojanscan_activechans;
return;
}
- if (rc->clone && rc->clone->clone && (!(rc->donotpart))) {
- localpartchannel(rc->clone->clone, rc->chan);
- } else {
-/*
- trojanscan_mainchanmsg("d: clone could not part: %s, most likely due to kill, flag: %d.", rc->chan->index->name->content, rc->donotpart);
-*/
- }
+ if (rc->clone->clone && (!(rc->donotpart)))
+ localpartchannel(rc->clone->clone, rc->chan, NULL);
+
rc->clone->sitting--;
for(rp=trojanscan_realchanlist;rp;rp=rp->next) {
} else {
past->next = rp->next;
}
- free(rp);
+ tfree(rp);
break;
}
past = rp;
} else {
trojanscan_gennick(c_nick, trojanscan_minmaxrand(7, TROJANSCAN_MMIN(13, NICKLEN)));
}
- } while (c_nick && (getnickbynick(c_nick) != NULL));
+ } while (c_nick[0] && (getnickbynick(c_nick) != NULL));
renamelocaluser(clone->clone, c_nick);
}
/* Split the line into params */
cargc = splitline((char *)args[1], cargv, 50, 0);
+ if(cargc == 0 || !cargv[0])
+ return;
cmd=findcommandintree(trojanscan_cmds, cargv[0], 1);
if (!cmd) {
case LU_KILLED:
/* someone killed me? Bastards */
- trojanscan_connect_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect, NULL);
+ trojanscan_connect_nick_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect_nick, NULL);
trojanscan_nick = NULL;
break;
}
}
+static char trojanscan_getmtfromhooktype(int input) {
+ switch(input) {
+ case HOOK_CHANNEL_PART: return 'P';
+ default: return '?';
+ }
+}
+
char trojanscan_getmtfrommessagetype(int input) {
switch(input) {
case LU_PRIVMSG: return 'm';
}
}
+static void trojanscan_process(nick *sender, channel *cp, char mt, char *pretext) {
+ char text[513];
+ unsigned int len;
+ unsigned int i;
+ struct trojanscan_worms *worm;
+ int vector[30], detected = 0;
+
+ trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
+
+ len = strlen(text);
+
+ for(i=0;i<trojanscan_database.total_phrases;i++) {
+ if (
+ (
+ (worm = trojanscan_database.phrases[i].worm)
+ ) &&
+ (
+ (
+ (
+ (mt == 'm') || (mt == 's') || (mt == 'n')
+ ) &&
+ (
+ (trojanscan_database.phrases[i].worm->hitpriv)
+ )
+ ) ||
+ (
+ (
+ (mt == 'M') || (mt == 'N') || (mt == 'P')
+ ) &&
+ (
+ (trojanscan_database.phrases[i].worm->hitchans)
+ )
+ )
+ ) &&
+ (trojanscan_database.phrases[i].phrase)
+ ) {
+ int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
+ if(pre >= 0) {
+ char matchbuf[513];
+ matchbuf[0] = 0;
+ matchbuf[512] = 0; /* hmm */
+
+ if(pre > 1)
+ if(pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
+ matchbuf[0] = 0;
+
+ trojanscan_phrasematch(cp, sender, &trojanscan_database.phrases[i], mt, matchbuf);
+
+ detected = 1;
+ break;
+ }
+ }
+ }
+ if (!detected && (mt != 'N') && (mt != 'M')) {
+ char etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+ trojanscan_database_escape_string(etext, text, len);
+ trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+ trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+ trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+ trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
+ }
+}
+
void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args) {
- char *pretext = NULL, etext[TROJANSCAN_QUERY_TEMP_BUF_SIZE], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE], text[513], detected = 0;
+ char *pretext = NULL;
nick *sender;
struct trojanscan_realchannels *rp;
struct trojanscan_rejoinlist *rj;
- unsigned int i, len;
- struct trojanscan_worms *worm;
- int vector[30];
char mt = trojanscan_getmtfrommessagetype(messagetype);
char *channel_name;
+ channel *cp = NULL;
+ int i;
switch(messagetype) {
case LU_PRIVMSG:
case LU_CHANMSG:
case LU_CHANNOTICE:
-
sender = (nick *)args[0];
+
if (strlen(sender->nick) < 2)
break;
- if (!pretext)
+ if (!pretext) {
pretext = (char *)args[2];
+ cp = args[1];
+ }
if(strncmp(TROJANSCAN_VERSION_DETECT, pretext, sizeof(TROJANSCAN_VERSION_DETECT)-1)==0) {
char p = pretext[sizeof(TROJANSCAN_VERSION_DETECT)-1];
}
}
if (staff) {
- sendnoticetouser(target, sender, "\001VERSION T clone, check T for confirmation.\001");
- sendnoticetouser(trojanscan_nick, sender, "\001VERSION %s is part of my swarm.\001", target->nick);
+ if(trojanscan_nick) {
+ sendnoticetouser(target, sender, "\001VERSION T clone, check T for confirmation.\001");
+ sendnoticetouser(trojanscan_nick, sender, "\001VERSION %s is part of my swarm.\001", target->nick);
+ } else {
+ sendnoticetouser(target, sender, "\001VERSION T clone, though since T is currently gone you'll have to version me again in a minute for confirmation.\001");
+ }
} else {
- sendnoticetouser(target, sender, "\001VERSION " TROJANSCAN_CLONE_VERSION_REPLY "\001");
+ sendnoticetouser(target, sender, "\001VERSION %s\001", versionreply);
}
return;
}
}
- trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
-
- len = strlen(text);
-
- for(i=0;i<trojanscan_database.total_phrases;i++) {
- if (
- (
- (worm = trojanscan_database.phrases[i].worm)
- ) &&
- (
- (
- (
- (messagetype == LU_PRIVMSG) || (messagetype == LU_SECUREMSG) || (messagetype == LU_PRIVNOTICE)
- ) &&
- (
- (trojanscan_database.phrases[i].worm->hitpriv)
- )
- ) ||
- (
- (
- (messagetype == LU_CHANMSG) || (messagetype == LU_CHANNOTICE)
- ) &&
- (
- (trojanscan_database.phrases[i].worm->hitchans)
- )
- )
- ) &&
- (trojanscan_database.phrases[i].phrase)
- ) {
- int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
- if(pre >= 0) {
- char glinemask[HOSTLEN + USERLEN + NICKLEN + 4];
- char *userbit;
- host *hp;
- unsigned int j, usercount, frequency;
- char ip[TROJANSCAN_IPLEN];
- int glining = 1;
- channel *chp = (channel *)args[1];
-
- nick *np = NULL; /* sigh at warnings */
-
- detected = 1;
-
- trojanscan_database.detections++;
-
- if (!(hp=findhost(sender->host->name->content))) {
- trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 1 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
- break;
- }
-
- usercount = 0; /* stupid warnings */
- if (worm->monitor) {
- glining = 0;
- usercount = -1;
- } else if (worm->glinehost) {
-/* snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", sender->host->name->content);*/
- snprintf(glinemask, sizeof(glinemask) - 1, "*@%s", trojanscan_iptostr(ip, sizeof(ip) - 1, sender->ipaddress));
- usercount = hp->clonecount;
- } else if (worm->glineuser) {
- userbit = sender->ident;
- if(userbit[0] == '~')
- userbit++;
-/* snprintf(glinemask, sizeof(glinemask) - 1, "*%s@%s", userbit, sender->host->name->content);*/
- snprintf(glinemask, sizeof(glinemask) - 1, "*%s@%s", userbit, trojanscan_iptostr(ip, sizeof(ip) - 1, sender->ipaddress));
- for (j=0;j<NICKHASHSIZE;j++) {
- for (np=nicktable[j];np;np=np->next) {
- if ((np->host==hp) && (!ircd_strcmp(np->ident,sender->ident)))
- usercount++;
- }
- }
- }
-
- if (!usercount) {
- trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
- break;
- }
-
- if (glining && (usercount > trojanscan_maxusers)) {
- trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
- break;
- }
-
- if (glining && !worm->datalen) {
- trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
- break;
- }
-
- trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
- trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
- trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
-
- frequency = 1;
-
- if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
- trojanscan_database_res *res;
- if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
- trojanscan_database_row sqlrow;
- if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
- frequency = atoi(sqlrow[0]) + 1;
- trojanscan_database_free_result(res);
- }
- }
-
- if (!glining) {
- char matchbuf[513];
- matchbuf[0] = 0;
- matchbuf[512] = 0; /* hmm */
-
- if(pre > 1)
- if (pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
- 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:"");
- } else {
- int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
- if(glinetime > 7 * 24)
- glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
-
- 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 worm (%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);
- //trojanscan_mainchanmsg("%s GL * +%s %d :You are infected with a worm (%s), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, 3600 * TROJANSCAN_FIRST_OFFENSE * frequency, worm->name->content, TROJANSCAN_URL_PREFIX, worm->id, TROJANSCAN_FIRST_OFFENSE * frequency);
-
- 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);
- }
-
- break;
- }
- }
- }
- if (!detected && (mt != 'N') && (mt != 'M')) {
- trojanscan_database_escape_string(etext, text, len);
- trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
- trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
- trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
- trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
- }
+ trojanscan_process(sender, cp, mt, pretext);
break;
case LU_KILLED:
/* someone killed me? Bastards */
- trojanscan_mainchanmsg("d: clone %s killed!", target->nick);
/* PPA: we do NOT rejoin channels at this moment in time, it is possible to do this though */
for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++) {
if (trojanscan_swarm[i].clone == target) {
- scheduleoneshot(time(NULL)+1, &trojanscan_generateclone, (void *)i);
- if(i >= TROJANSCAN_CLONE_MAX) { /* PPA: check this is actually correct, might be > */
+ scheduleoneshot(time(NULL)+1, &trojanscan_generateclone, (void *)((long)i));
+ if(i >= TROJANSCAN_CLONE_MAX) {
int j;
for(j=0;j<trojanscan_activechans;j++)
if(trojanscan_chans[j].watch_clone == &trojanscan_swarm[i])
if ((rp->clone == &(trojanscan_swarm[i])))
rp->donotpart = 1;
}
+ derefnode(iptree, trojanscan_swarm[i].fakeipnode);
trojanscan_swarm[i].clone = NULL;
trojanscan_swarm[i].remaining = 0; /* bah */
break;
/*
trojanscan_mainchanmsg("k: %s on %s by %s", target->nick, ((channel *)args[1])->index->name->content, (((nick *)args[0])->nick)?(((nick *)args[0])->nick):"(server)");
*/
- rj = (struct trojanscan_rejoinlist *)malloc(sizeof(struct trojanscan_rejoinlist));
+ rj = (struct trojanscan_rejoinlist *)tmalloc(sizeof(struct trojanscan_rejoinlist));
if (rj) {
rj->rp = NULL;
for(rp=trojanscan_realchanlist;rp;rp=rp->next)
break;
}
if(!rj->rp) {
- trojanscan_mainchanmsg("d: kicked from %s after parting", ((channel *)args[1])->index->name->content);
- free(rj);
+ tfree(rj);
return;
}
rj->channel = getsstring(((channel *)args[1])->index->name->content, ((channel *)args[1])->index->name->length);
if(!rj->channel) {
trojanscan_mainchanmsg("d: unable to allocate memory for channel: %s upon rejoin", ((channel *)args[1])->index->name->content);
- free(rj);
+ tfree(rj);
return;
}
- rj->clone = target;
+ rj->clone = rp->clone;
rj->next = trojanscan_schedulerejoins;
trojanscan_schedulerejoins = rj;
}
}
+static void trojanscan_part_watch(int hook, void *arg) {
+ void **arglist = (void **)arg;
+ channel *cp = (channel *)arglist[0];
+ nick *np = arglist[1];
+ char *reason = arglist[2];
+
+ if(!cp || !np || !reason || (*reason == '\0'))
+ return;
+
+ trojanscan_process(np, cp, trojanscan_getmtfromhooktype(hook), reason);
+}
+
+static int trojanscan_hostcount(nick *sender, int hostmode, char *mask, int masklen) {
+ int usercount = 0, j;
+ nick *np = NULL; /* sigh at warnings */
+
+ if(hostmode)
+ usercount = sender->ipnode->usercount;
+
+ if(usercount > TROJANSCAN_MAX_HOST_GLINE) {
+ hostmode = 0;
+ usercount = 0;
+ }
+
+ /* should really go through the ipnode I guess */
+ if(!hostmode)
+ for (j=0;j<NICKHASHSIZE;j++)
+ for (np=nicktable[j];np;np=np->next)
+ if (np->ipnode==sender->ipnode && !ircd_strcmp(np->ident, sender->ident))
+ usercount++;
+
+ if(mask)
+ snprintf(mask, masklen, "%s@%s", hostmode?"*":sender->ident, IPtostr(sender->p_ipaddr));
+
+ return usercount;
+}
+
+void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf) {
+ char glinemask[HOSTLEN + USERLEN + NICKLEN + 4], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
+ unsigned int frequency;
+ int glining = 0, usercount;
+ struct trojanscan_worms *worm = phrase->worm;
+
+ trojanscan_database.detections++;
+
+ usercount = 0;
+ if (worm->monitor) {
+ usercount = -1;
+ } else if(worm->glinehost || worm->glineuser) {
+ glining = 1;
+
+ usercount = trojanscan_hostcount(sender, worm->glinehost, glinemask, sizeof(glinemask));
+ }
+
+ if (!usercount) {
+ trojanscan_mainchanmsg("w: user %s!%s@%s triggered infection monitor, yet no hosts found at stage 2 -- worm: %s", sender->nick, sender->ident, sender->host->name->content, worm->name->content);
+ return;
+ }
+
+ if (glining && (usercount > trojanscan_maxusers)) {
+ trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too many users (%d) with mask: *!%s -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, usercount, glinemask, worm->name->content);
+ return;
+ }
+
+ if (glining && !worm->datalen) {
+ trojanscan_mainchanmsg("w: not glining %s!%s@%s due to too lack of removal data with mask: *!%s (%d users) -- worm: %s)", sender->nick, sender->ident, sender->host->name->content, glinemask, usercount, worm->name->content);
+ return;
+ }
+
+ trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
+ trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
+ trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
+
+ frequency = 1;
+
+ if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
+ trojanscan_database_res *res;
+ if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
+ trojanscan_database_row sqlrow;
+ if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
+ frequency = atoi(sqlrow[0]) + 1;
+ trojanscan_database_free_result(res);
+ }
+ }
+
+ if (!glining) {
+ trojanscan_mainchanmsg("m: t: %c u: %s!%s@%s%s%s w: %s p: %d %s%s", messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, phrase->id, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#ifdef TROJANSCAN_PEONCHANNEL
+ trojanscan_peonchanmsg("m: t: %c u: %s!%s@%s%s%s%s w: %s %s%s", messagetype, sender->nick, sender->ident, (IsHideHost(sender)&&IsAccount(sender))?sender->authname:sender->host->name->content, (IsHideHost(sender)&&IsAccount(sender))?"."HIS_HIDDENHOST:"", messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", worm->name->content, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+#endif
+ } else {
+ int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
+ if(glinetime > 7 * 24)
+ glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
+
+ trojanscan_database_query("INSERT INTO hits (nickname, ident, host, phrase, messagetype, glined) VALUES ('%s', '%s', '%s', %d, '%c', %d)", enick, eident, ehost, phrase->id, messagetype, glining);
+ trojanscan_database.glines++;
+
+ irc_send("%s GL * +%s %d %jd :You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours\r\n", mynumeric->content, glinemask, glinetime * 3600, (intmax_t)time(NULL), sender->nick, sender->ident, sender->host->name->content, worm->name->content, phrase->id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
+
+ trojanscan_mainchanmsg("g: *!%s t: %c u: %s!%s@%s%s%s c: %d w: %s%s p: %d f: %d%s%s", glinemask, messagetype, sender->nick, sender->ident, sender->host->name->content, messagetype=='N'||messagetype=='M'||messagetype=='P'?" #: ":"", messagetype=='N'||messagetype=='M'||messagetype=='P'?chp->index->name->content:"", usercount, worm->name->content, worm->epidemic?"(E)":"", phrase->id, frequency, matchbuf[0]?" --: ":"", matchbuf[0]?matchbuf:"");
+ }
+}
+
void trojanscan_rejoin_channel(void *arg) {
struct trojanscan_rejoinlist *rj2, *lrj, *rj = (struct trojanscan_rejoinlist *)arg;
- /* TODO: there is a pretty major bug here */
channel *cp = findchannel(rj->channel->content);
freesstring(rj->channel);
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);
}
}
}
if (rj2 == rj) {
trojanscan_schedulerejoins = rj->next;
- free(rj);
+ tfree(rj);
} else {
for(rj2=trojanscan_schedulerejoins;rj2;lrj=rj2,rj2=rj2->next) {
if (rj2 == rj) {
lrj->next = rj2->next;
- free(rj);
+ tfree(rj);
break;
}
}
sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
}
+#ifdef TROJANSCAN_PEONCHANNEL
+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);
+}
+#endif
+
int trojanscan_minmaxrand(float min, float max) {
return (int)((max-min+1)*rand()/(RAND_MAX+min))+min;
}
ptc[i] = '\0';
}
-void trojanscan_genhost(char *ptc, char size) {
+void trojanscan_genhost(char *ptc, char size, patricia_node_t **fakeipnode) {
int dots = trojanscan_minmaxrand(2, 5), i, dotexist = 0, cur;
-
+ struct irc_in_addr ipaddress;
+
while (!dotexist) {
for (i=0;i<size;i++) {
ptc[i] = trojanscan_genchar(0);
}
}
ptc[i] = '\0';
+
+ memset(&ipaddress, 0, sizeof(ipaddress));
+ ((unsigned short *)(ipaddress.in6_16))[5] = 65535;
+ ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+ ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
+
+ *fakeipnode = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
}
void trojanscan_genreal(char *ptc, char size) {
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)
}
nick *trojanscan_selectuser(void) {
- int target = trojanscan_minmaxrand(0, 500), loops = 50, j;
+ int target = trojanscan_minmaxrand(0, 500), loops = 150, j;
nick *np;
do {
for (j=trojanscan_minmaxrand(0, NICKHASHSIZE-1);j<NICKHASHSIZE;j++)
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;
+}
+
+static int specialuseronhost(host *hp) {
+ nick *np;
+
+ for(np=hp->nicks;np;np=np->nextbyhost)
+ if(IsOper(np) || IsService(np) || IsXOper(np) || NickOnServiceServer(np))
+ return 1;
+
+ return 0;
+}
+
+void trojanscan_generatehost(char *buf, int maxsize, patricia_node_t **fakeip) {
+ struct irc_in_addr ipaddress;
+
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) && !specialuseronhost(hp)) {
+ strlcpy(buf, hp->name->content, maxsize + 1);
+ if(hp->nicks) {
+ *fakeip = hp->nicks->ipnode;
+ patricia_ref_prefix(hp->nicks->ipnode->prefix);
+ } else {
+ memset(&ipaddress, 0, sizeof(ipaddress));
+ ((unsigned short *)(ipaddress.in6_16))[5] = 65535;
+ ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+ ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
+
+ *fakeip = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
+ }
break;
}
} while(--loops > 0);
} else {
char *cpos;
int pieces = trojanscan_minmaxrand(2, 4), totallen = 0, a = 0, i;
- int *choices = malloc(sizeof(int) * (pieces + 1));
- int *lengths = malloc(sizeof(int) * (pieces + 1));
+ int *choices = tmalloc(sizeof(int) * (pieces + 1));
+ int *lengths = tmalloc(sizeof(int) * (pieces + 1));
choices[pieces] = trojanscan_minmaxrand(0, trojanscan_tailpoolsize-1);
lengths[pieces] = strlen(trojanscan_tailpool[choices[pieces]]->content) + 1;
}
buf[a] = '\0';
- free(choices);
- free(lengths);
+ tfree(choices);
+ tfree(lengths);
+
+ memset(&ipaddress, 0, sizeof(ipaddress));
+ ((unsigned short *)(ipaddress.in6_16))[5] = 65535;
+ ((unsigned short *)(ipaddress.in6_16))[6] = trojanscan_minmaxrand(0, 65535);
+ ((unsigned short *)(ipaddress.in6_16))[7] = trojanscan_minmaxrand(0, 65535);
+
+ *fakeip = refnode(iptree, &ipaddress, PATRICIA_MAXBITS);
}
}
void trojanscan_generatenick(char *buf, int maxsize) {
- int bits = trojanscan_minmaxrand(2, 3), loops = 0, wanttocopy, len = 0, i, d = 0;
+ int bits = trojanscan_minmaxrand(2, 3), loops = 0, wanttocopy, len = 0, i, d = 0, newmaxsize = maxsize - trojanscan_minmaxrand(0, 7);
nick *np;
+
+ if(newmaxsize > 2)
+ maxsize = newmaxsize;
+
do {
np = trojanscan_selectuser();
if(np) {
- wanttocopy = trojanscan_minmaxrand(1, (strlen(np->nick) / 2) + 2);
+ wanttocopy = trojanscan_minmaxrand(1, (strlen(np->nick) / 2) + 3);
for(i=0;((i<wanttocopy) && (len<maxsize));i++)
buf[len++] = np->nick[i];
if(++d > bits) {
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) {