]> jfr.im git - irc/quakenet/newserv.git/blob - trojanscan/trojanscan.c
patrol: Fix usermodes.
[irc/quakenet/newserv.git] / trojanscan / trojanscan.c
1 /*
2 * Trojanscan version 2
3 *
4 * Trojanscan copyright (C) Chris Porter 2002-2009
5 * Newserv bits copyright (C) David Mansell 2002-2003
6 *
7 * TODO: CHECK::
8 * - Poke splidge about +r'ing bots, potential problems:
9 * - users might whine about T clone stealing account
10 * - would have to steal one already in use, so if trojans start using /msg q whois they'll see
11 * (though they have to be authed for this, they could use a clone of their own however)
12 */
13
14 #include "trojanscan.h"
15 #include "../lib/strlfunc.h"
16 #include "../lib/version.h"
17 #include "../core/nsmalloc.h"
18 #include "../glines/glines.h"
19 #include "../patrol/patrol.h"
20 #include <stdint.h>
21
22 #define tmalloc(x) nsmalloc(POOL_TROJANSCAN, x)
23 #define tfree(x) nsfree(POOL_TROJANSCAN, x)
24
25 MODULE_VERSION(TROJANSCAN_VERSION);
26
27 void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf);
28 char *trojanscan_sanitise(char *input);
29 void trojanscan_refresh_settings(void);
30 static void trojanscan_part_watch(int hook, void *arg);
31 static void trojanscan_connect_nick(void *);
32
33 #define TROJANSCAN_SETTING_SIZE 256
34 #define TROJANSCAN_MAX_SETTINGS 50
35
36 static struct {
37 char setting[TROJANSCAN_SETTING_SIZE];
38 char value[TROJANSCAN_SETTING_SIZE];
39 } trojanscan_settings[TROJANSCAN_MAX_SETTINGS];
40
41 static int settingcount = 0;
42 static char *versionreply;
43 static int hooksregistered = 0;
44 static void *trojanscan_connect_nick_schedule;
45
46 static void *db_ping_schedule;
47
48 void _init() {
49 trojanscan_cmds = newcommandtree();
50
51 addcommandtotree(trojanscan_cmds, "showcommands", TROJANSCAN_ACL_UNAUTHED, 0, &trojanscan_showcommands);
52 addcommandtotree(trojanscan_cmds, "help", TROJANSCAN_ACL_UNAUTHED, 1, &trojanscan_help);
53 addcommandtotree(trojanscan_cmds, "hello", TROJANSCAN_ACL_UNAUTHED | TROJANSCAN_ACL_OPER, 1, &trojanscan_hello);
54
55 addcommandtotree(trojanscan_cmds, "join", TROJANSCAN_ACL_STAFF, 1, &trojanscan_userjoin);
56 addcommandtotree(trojanscan_cmds, "chanlist", TROJANSCAN_ACL_STAFF, 0, &trojanscan_chanlist);
57 addcommandtotree(trojanscan_cmds, "whois", TROJANSCAN_ACL_STAFF, 1, &trojanscan_whois);
58
59 addcommandtotree(trojanscan_cmds, "changelev", TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_OPER, 2, &trojanscan_changelev);
60 addcommandtotree(trojanscan_cmds, "deluser", TROJANSCAN_ACL_TEAMLEADER | TROJANSCAN_ACL_OPER, 2, &trojanscan_deluser);
61 addcommandtotree(trojanscan_cmds, "mew", TROJANSCAN_ACL_STAFF, 2, &trojanscan_mew);
62 addcommandtotree(trojanscan_cmds, "status", TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_OPER, 0, &trojanscan_status);
63 addcommandtotree(trojanscan_cmds, "listusers", TROJANSCAN_ACL_TEAMLEADER, 0, &trojanscan_listusers);
64
65 addcommandtotree(trojanscan_cmds, "rehash", TROJANSCAN_ACL_WEBSITE, 0, &trojanscan_rehash);
66
67 addcommandtotree(trojanscan_cmds, "cat", TROJANSCAN_ACL_OPER, 1, &trojanscan_cat);
68
69 addcommandtotree(trojanscan_cmds, "reschedule", TROJANSCAN_ACL_DEVELOPER | TROJANSCAN_ACL_OPER, 0, &trojanscan_reschedule);
70
71 srand((int)time(NULL));
72
73 trojanscan_connect_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect, NULL);
74 }
75
76 void _fini(void) {
77 int i;
78 struct trojanscan_realchannels *rp = trojanscan_realchanlist, *oldrp;
79 struct trojanscan_rejoinlist *rj = trojanscan_schedulerejoins, *oldrj;
80
81 if (trojanscan_nick)
82 deregisterlocaluser(trojanscan_nick, NULL);
83
84 if (trojanscan_connect_schedule)
85 deleteschedule(trojanscan_connect_schedule, &trojanscan_connect, NULL);
86
87 if (trojanscan_connect_nick_schedule)
88 deleteschedule(trojanscan_connect_nick_schedule, &trojanscan_connect_nick, NULL);
89
90 if(trojanscan_schedule)
91 deleteschedule(trojanscan_schedule, &trojanscan_dojoin, NULL);
92
93 if(trojanscan_cloneschedule)
94 deleteschedule(trojanscan_cloneschedule, &trojanscan_registerclones, NULL);
95
96 if(hooksregistered)
97 deregisterhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
98
99 while(rp) {
100 deleteschedule(rp->schedule, &trojanscan_dopart, (void *)rp);
101 oldrp = rp;
102 rp = rp->next;
103 tfree(oldrp);
104 }
105
106 while(rj) {
107 deleteschedule(rj->schedule, &trojanscan_rejoin_channel, (void *)rj);
108 freesstring(rj->channel);
109 oldrj = rj;
110 rj = rj->next;
111 tfree(oldrj);
112 }
113
114 if(trojanscan_initialschedule)
115 deleteschedule(trojanscan_initialschedule, &trojanscan_fill_channels, NULL);
116
117 deleteschedule(trojanscan_rehashschedule, &trojanscan_rehash_schedule, NULL);
118
119 for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
120 if(trojanscan_swarm[i].clone) {
121 deregisterlocaluser(trojanscan_swarm[i].clone, NULL);
122 trojanscan_swarm[i].clone = NULL;
123 }
124 trojanscan_free_database();
125 trojanscan_free_channels();
126
127 trojanscan_database_close();
128
129 deletecommandfromtree(trojanscan_cmds, "showcommands", &trojanscan_showcommands);
130 deletecommandfromtree(trojanscan_cmds, "help", &trojanscan_help);
131 deletecommandfromtree(trojanscan_cmds, "hello", &trojanscan_hello);
132 deletecommandfromtree(trojanscan_cmds, "join", &trojanscan_userjoin);
133 deletecommandfromtree(trojanscan_cmds, "chanlist", &trojanscan_chanlist);
134 deletecommandfromtree(trojanscan_cmds, "whois", &trojanscan_whois);
135 deletecommandfromtree(trojanscan_cmds, "changelev", &trojanscan_changelev);
136 deletecommandfromtree(trojanscan_cmds, "deluser", &trojanscan_deluser);
137 deletecommandfromtree(trojanscan_cmds, "mew", &trojanscan_mew);
138 deletecommandfromtree(trojanscan_cmds, "status", &trojanscan_status);
139 deletecommandfromtree(trojanscan_cmds, "listusers", &trojanscan_listusers);
140 deletecommandfromtree(trojanscan_cmds, "rehash", &trojanscan_rehash);
141 deletecommandfromtree(trojanscan_cmds, "cat", &trojanscan_cat);
142 deletecommandfromtree(trojanscan_cmds, "reschedule", &trojanscan_reschedule);
143
144 destroycommandtree(trojanscan_cmds);
145 nscheckfreeall(POOL_TROJANSCAN);
146 }
147
148 static void trojanscan_connect_nick(void *arg) {
149 sstring *mnick, *myident, *myhost, *myrealname, *myauthname;
150 channel *cp;
151
152 mnick = getcopyconfigitem("trojanscan", "nick", "T", NICKLEN);
153 myident = getcopyconfigitem("trojanscan", "ident", "trojanscan", NICKLEN);
154 myhost = getcopyconfigitem("trojanscan", "hostname", "trojanscan.quakenet.org", HOSTLEN);
155 myrealname = getcopyconfigitem("trojanscan", "realname", "Trojanscan v" TROJANSCAN_VERSION, REALLEN);
156 myauthname = getcopyconfigitem("trojanscan", "authname", "T", ACCOUNTLEN);
157
158 trojanscan_nick = registerlocaluser(mnick->content, myident->content, myhost->content, myrealname->content, myauthname->content, UMODE_SERVICE | UMODE_DEAF |
159 UMODE_OPER | UMODE_INV |
160 UMODE_ACCOUNT,
161 &trojanscan_handlemessages);
162 freesstring(mnick);
163 freesstring(myident);
164 freesstring(myhost);
165 freesstring(myrealname);
166 freesstring(myauthname);
167
168 cp = findchannel(TROJANSCAN_OPERCHANNEL);
169 if (!cp) {
170 localcreatechannel(trojanscan_nick, TROJANSCAN_OPERCHANNEL);
171 } else {
172 if(!localjoinchannel(trojanscan_nick, cp))
173 localgetops(trojanscan_nick, cp);
174 }
175
176 cp = findchannel(TROJANSCAN_CHANNEL);
177 if (!cp) {
178 localcreatechannel(trojanscan_nick, TROJANSCAN_CHANNEL);
179 } else {
180 if(!localjoinchannel(trojanscan_nick, cp))
181 localgetops(trojanscan_nick, cp);
182 }
183
184 #ifdef TROJANSCAN_PEONCHANNEL
185 cp = findchannel(TROJANSCAN_PEONCHANNEL);
186 if (!cp) {
187 localcreatechannel(trojanscan_nick, TROJANSCAN_PEONCHANNEL);
188 } else {
189 if(!localjoinchannel(trojanscan_nick, cp))
190 localgetops(trojanscan_nick, cp);
191 }
192 #endif
193 }
194
195 void trojanscan_connect(void *arg) {
196 sstring *dbhost, *dbuser, *dbpass, *db, *dbport, *temp;
197 int length, i;
198 char buf[10];
199
200 trojanscan_connect_schedule = NULL;
201
202 for(i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
203 trojanscan_swarm[i].index = i; /* sure this could be done with pointer arithmetic... */
204
205 trojanscan_cloneschedule = NULL;
206 trojanscan_realchanlist = NULL;
207 trojanscan_database.glines = 0;
208 trojanscan_database.detections = 0;
209
210 dbhost = getcopyconfigitem("trojanscan", "dbhost", "localhost", 100);
211 dbuser = getcopyconfigitem("trojanscan", "dbuser", "moo", 100);
212 dbpass = getcopyconfigitem("trojanscan", "dbpass", "changeme", 100);
213 db = getcopyconfigitem("trojanscan", "db", "moo", 100);
214
215 dbport = getcopyconfigitem("trojanscan", "dbport", "3306", 10);
216
217 length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_MAXCHANS);
218 temp = getcopyconfigitem("trojanscan", "maxchans", buf, length);
219
220 trojanscan_maxchans = atoi(temp->content);
221 freesstring(temp);
222
223 length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_CYCLETIME);
224 temp = getcopyconfigitem("trojanscan", "cycletime", buf, length);
225
226 trojanscan_cycletime = atoi(temp->content);
227 freesstring(temp);
228
229 length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_PARTTIME);
230 temp = getcopyconfigitem("trojanscan", "parttime", buf, length);
231 trojanscan_part_time = atoi(temp->content);
232 freesstring(temp);
233
234 length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_MAXUSERS);
235 temp = getcopyconfigitem("trojanscan", "maxusers", buf, length);
236 trojanscan_maxusers = atoi(temp->content);
237 freesstring(temp);
238
239 if ((trojanscan_cycletime / trojanscan_maxchans) < 1) {
240 Error("trojanscan", ERR_FATAL, "Cycletime / maxchans < 1, increase cycletime or decrease maxchans else cycling breaks.");
241 freesstring(dbhost);
242 freesstring(dbuser);
243 freesstring(dbpass);
244 freesstring(db);
245 freesstring(dbport);
246 return; /* PPA: module failed to load */
247 }
248
249 length = snprintf(buf, sizeof(buf) - 1, "%d", TROJANSCAN_DEFAULT_MINIMUM_CHANNEL_SIZE);
250 temp = getcopyconfigitem("trojanscan", "minchansize", buf, length);
251 trojanscan_minchansize = atoi(temp->content);
252 freesstring(temp);
253
254 trojanscan_connect_nick(NULL);
255
256 if (trojanscan_database_connect(dbhost->content, dbuser->content, dbpass->content, db->content, atoi(dbport->content)) < 0) {
257 Error("trojanscan", ERR_FATAL, "Cannot connect to database host!");
258 freesstring(dbhost);
259 freesstring(dbuser);
260 freesstring(dbpass);
261 freesstring(db);
262 freesstring(dbport);
263 return; /* PPA: module failed to load */
264 }
265
266 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)");
267 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)");
268 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)");
269 trojanscan_database_query("CREATE TABLE channels (id INT(10) PRIMARY KEY AUTO_INCREMENT, channel VARCHAR(%d) NOT NULL, exempt BOOL DEFAULT 0)", CHANNELLEN);
270 trojanscan_database_query("CREATE TABLE users (id INT(10) PRIMARY KEY AUTO_INCREMENT, authname VARCHAR(%d) NOT NULL, authlevel TINYINT(4) NOT NULL)", ACCOUNTLEN);
271 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);
272 trojanscan_database_query("CREATE TABLE settings (id INT(10) PRIMARY KEY AUTO_INCREMENT, setting VARCHAR(255) NOT NULL UNIQUE, value VARCHAR(255) NOT NULL)");
273 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)");
274 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);
275
276 trojanscan_database_query("DELETE FROM settings WHERE setting = 'rehash' OR setting = 'changed'");
277 trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('rehash','0')");
278 trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('changed','0')");
279
280 /* assumption: constants aren't supplied by someone evil */
281 trojanscan_database_query("INSERT INTO settings (setting, value) VALUES ('versionreply','" TROJANSCAN_DEFAULT_VERSION_REPLY "')");
282
283 trojanscan_refresh_settings();
284 trojanscan_read_database(1);
285
286 freesstring(dbhost);
287 freesstring(dbuser);
288 freesstring(dbpass);
289 freesstring(db);
290 freesstring(dbport);
291 trojanscan_registerclones(NULL);
292
293 trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
294
295 registerhook(HOOK_CHANNEL_PART, trojanscan_part_watch);
296 hooksregistered = 1;
297 }
298
299 char *trojanscan_get_setting(char *setting) {
300 int i;
301
302 for(i=0;i<settingcount;i++)
303 if(!strcmp(trojanscan_settings[i].setting, setting))
304 return trojanscan_settings[i].value;
305
306 return NULL;
307 }
308
309 void trojanscan_refresh_settings(void) {
310 trojanscan_database_res *res;
311 trojanscan_database_row sqlrow;
312 int i = 0;
313
314 if(trojanscan_database_query("SELECT setting, value FROM settings"))
315 return;
316
317 if(!(res = trojanscan_database_store_result(&trojanscan_sql)))
318 return;
319
320 if (trojanscan_database_num_rows(res) <= 0)
321 return;
322
323 while((sqlrow = trojanscan_database_fetch_row(res))) {
324 strlcpy(trojanscan_settings[i].setting, sqlrow[0], TROJANSCAN_SETTING_SIZE);
325 strlcpy(trojanscan_settings[i].value, sqlrow[1], TROJANSCAN_SETTING_SIZE);
326
327 trojanscan_sanitise(trojanscan_settings[i].value);
328
329 if(++i == TROJANSCAN_MAX_SETTINGS)
330 break;
331 }
332
333 settingcount = i;
334
335 trojanscan_database_free_result(res);
336
337 /* optimisation hack */
338 versionreply = trojanscan_get_setting("versionreply");
339 }
340
341 void trojanscan_rehash_schedule(void *arg) {
342 char *v;
343 trojanscan_rehashschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_rehash_schedule, NULL);
344
345 trojanscan_refresh_settings();
346
347 v = trojanscan_get_setting("rehash");
348 if(v && v[0] == '1') {
349 trojanscan_mainchanmsg("n: rehash initiated by website. . .");
350 trojanscan_read_database(0);
351 }
352 }
353
354 void trojanscan_free_database(void) {
355 int i;
356 for(i=0;i<trojanscan_database.total_channels;i++)
357 freesstring(trojanscan_database.channels[i].name);
358 tfree(trojanscan_database.channels);
359 for(i=0;i<trojanscan_database.total_phrases;i++) {
360 if (trojanscan_database.phrases[i].phrase)
361 pcre_free(trojanscan_database.phrases[i].phrase);
362 if (trojanscan_database.phrases[i].hint)
363 pcre_free(trojanscan_database.phrases[i].hint);
364 }
365 tfree(trojanscan_database.phrases);
366 for(i=0;i<trojanscan_database.total_worms;i++)
367 freesstring(trojanscan_database.worms[i].name);
368 tfree(trojanscan_database.worms);
369 trojanscan_database.total_channels = 0;
370 trojanscan_database.total_phrases = 0;
371 trojanscan_database.total_worms = 0;
372 trojanscan_database.channels = NULL;
373 trojanscan_database.phrases = NULL;
374 trojanscan_database.worms = NULL;
375 }
376
377 char *trojanscan_sanitise(char *input) {
378 char *p;
379
380 for(p=input;*p;p++)
381 if(*p == '\r' || *p == '\n')
382 *p = '!';
383
384 return input;
385 }
386
387 sstring *trojanscan_getsstring(char *string, int length) {
388 int i;
389
390 for(i=0;i<length;i++) {
391 if ((string[i] == '\r') || (string[i] == '\n')) {
392 Error("trojanscan", ERR_WARNING, "Error reading %s at position %d, set to ERROR!", string, i+1);
393 return getsstring("ERROR", sizeof("ERROR"));
394 }
395 }
396
397 return getsstring(string, length);
398 }
399
400 int trojanscan_strip_codes(char *buf, size_t max, char *original) {
401 int i, j, length = TROJANSCAN_MMIN(strlen(original), max-1);
402 char *p2 = original, *p3, flag = 0;
403 p3 = buf;
404 for(i=0;i<length+1;i++) {
405 switch (*p2) {
406 case '\002':
407 case '\017':
408 case '\026':
409 case '\037':
410 break;
411 case '\003':
412 for(j=0;j<6;j++) {
413 if ((i + 1) > length)
414 break;
415 if ((j == 4) && flag)
416 break;
417 p2++;
418 i++;
419 if ((j == 0) && (!((*p2 >= '0') && (*p2 <= '9'))))
420 break;
421 if (j == 1) {
422
423 if (*p2 == ',') {
424 if ((i + 1) > length)
425 break;
426 if (!((*(p2 + 1) >= '0') && (*(p2 + 1) <= '9')))
427 break;
428 flag = 1;
429 } else if ((*p2 >= '0') && (*p2 <= '9')) {
430 flag = 0;
431 } else {
432 break;
433 }
434 }
435 if (j == 2) {
436 if (flag) {
437 if (!((*p2 >= '0') && (*p2 <= '9')))
438 break;
439 } else {
440 if (*p2 != ',') {
441 break;
442 } else {
443 if ((i + 1) > length)
444 break;
445 if (!((*(p2 + 1) >= '0') && (*(p2 + 1) <= '9')))
446 break;
447 }
448 }
449 }
450 if ((j == 3) && (!((*p2 >= '0') && (*p2 <= '9'))))
451 break;
452 if ((j == 4) && (!((*p2 >= '0') && (*p2 <= '9'))))
453 break;
454 }
455 p2--;
456 i--;
457 break;
458
459 default:
460 *p3 = *p2;
461 p3++;
462 break;
463 }
464 p2++;
465 }
466 return p3 - buf;
467 }
468
469 struct trojanscan_worms *trojanscan_find_worm_by_id(int id) {
470 int i;
471 for(i=0;i<trojanscan_database.total_worms;i++)
472 if (trojanscan_database.worms[i].id == id)
473 return &trojanscan_database.worms[i];
474 return NULL;
475 }
476
477 void trojanscan_read_database(int first_time) {
478 const char *error;
479 int erroroffset, i, tempresult;
480
481 trojanscan_database_res *res;
482 trojanscan_database_row sqlrow;
483
484 if (!first_time) {
485 trojanscan_free_database();
486 } else {
487 trojanscan_database.total_channels = 0;
488 trojanscan_database.total_phrases = 0;
489 trojanscan_database.total_worms = 0;
490 }
491
492 if (!(trojanscan_database_query("SELECT channel, exempt FROM channels"))) {
493 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
494 trojanscan_database.total_channels = trojanscan_database_num_rows(res);
495 if (trojanscan_database.total_channels > 0) {
496 if ((trojanscan_database.channels = (trojanscan_channels *)tmalloc(sizeof(trojanscan_channels) * trojanscan_database.total_channels))) {
497 if ((trojanscan_database.total_channels>0) && trojanscan_database.channels) {
498 i = 0;
499 while((sqlrow = trojanscan_database_fetch_row(res))) {
500 trojanscan_database.channels[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[0]), strlen(sqlrow[0]));
501 trojanscan_database.channels[i].exempt = (sqlrow[1][0] == '1');
502 i++;
503 }
504 }
505 }
506 }
507 trojanscan_database_free_result(res);
508 }
509 }
510
511 if (!(trojanscan_database_query("SELECT id, wormname, glinetype, length(data), hitmsgs, hitchans, epidemic FROM worms"))) {
512 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
513 trojanscan_database.total_worms = trojanscan_database_num_rows(res);
514 if (trojanscan_database.total_worms > 0) {
515 if ((trojanscan_database.worms = (trojanscan_worms *)tmalloc(sizeof(trojanscan_worms) * trojanscan_database.total_worms))) {
516 i = 0;
517 while((sqlrow = trojanscan_database_fetch_row(res))) {
518 trojanscan_database.worms[i].id = atoi(sqlrow[0]);
519 trojanscan_database.worms[i].name = trojanscan_getsstring(trojanscan_sanitise(sqlrow[1]), strlen(sqlrow[1]));
520 tempresult = atoi(sqlrow[2]);
521 trojanscan_database.worms[i].glineuser = (tempresult == 0);
522 trojanscan_database.worms[i].glinehost = (tempresult == 1);
523 trojanscan_database.worms[i].monitor = (tempresult == 2);
524 if(sqlrow[3]) {
525 trojanscan_database.worms[i].datalen = ((atoi(sqlrow[3]) == 0) ? 0 : 1);
526 } else {
527 trojanscan_database.worms[i].datalen = 0;
528 }
529
530 trojanscan_database.worms[i].hitpriv = (atoi(sqlrow[4]) == 1);
531 trojanscan_database.worms[i].hitchans = (atoi(sqlrow[5]) == 1);
532 trojanscan_database.worms[i].epidemic = (atoi(sqlrow[6]) == 1);
533
534 i++;
535 }
536 }
537 }
538 trojanscan_database_free_result(res);
539 }
540 }
541
542 if (!(trojanscan_database_query("SELECT id, phrase, wormid FROM phrases WHERE disabled = 0 ORDER BY priority DESC"))) {
543 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
544 trojanscan_database.total_phrases = trojanscan_database_num_rows(res);
545 if (trojanscan_database.total_phrases > 0) {
546 if ((trojanscan_database.phrases = (trojanscan_phrases *)tmalloc(sizeof(trojanscan_phrases) * trojanscan_database.total_phrases))) {
547 i = 0;
548 while((sqlrow = trojanscan_database_fetch_row(res))) {
549 trojanscan_database.phrases[i].id = atoi(sqlrow[0]);
550 trojanscan_database.phrases[i].worm = trojanscan_find_worm_by_id(atoi(sqlrow[2]));
551 if (!(trojanscan_database.phrases[i].phrase = pcre_compile(sqlrow[1], PCRE_CASELESS, &error, &erroroffset, NULL))) {
552 Error("trojanscan", ERR_WARNING, "Error compiling expression %s at offset %d: %s", sqlrow[1], erroroffset, error);
553 } else {
554 trojanscan_database.phrases[i].hint = pcre_study(trojanscan_database.phrases[i].phrase, 0, &error);
555 if (error) {
556 Error("trojanscan", ERR_WARNING, "Error studying expression %s: %s", sqlrow[1], error);
557 pcre_free(trojanscan_database.phrases[i].phrase);
558 trojanscan_database.phrases[i].phrase = NULL;
559 }
560 }
561 i++;
562 }
563 }
564 }
565 trojanscan_database_free_result(res);
566 }
567 }
568
569 trojanscan_database_query("UPDATE settings SET value = '0' where setting = 'rehash'");
570 }
571
572 void trojanscan_log(nick *np, char *event, char *details, ...) {
573 int nickid = 0;
574 char eevent[TROJANSCAN_QUERY_TEMP_BUF_SIZE], edetails[TROJANSCAN_QUERY_TEMP_BUF_SIZE], buf[513];
575 va_list va;
576
577 va_start(va, details);
578 vsnprintf(buf, sizeof(buf) - 1, details, va);
579 va_end(va);
580
581 if (np)
582 if (IsAccount(np))
583 nickid = trojanscan_user_id_by_authname(np->authname);
584
585 trojanscan_database_escape_string(eevent, event, strlen(event));
586 trojanscan_database_escape_string(edetails, buf, strlen(buf));
587 trojanscan_database_query("INSERT INTO logs (userid, act, description) VALUES ('%d', '%s', '%s')", nickid, eevent, edetails);
588 }
589
590 void trojanscan_generateclone(void *arg) {
591 int i;
592
593 i = (int)((long)arg);
594
595 trojanscan_swarm[i].clone = patrol_generateclone(0, &trojanscan_clonehandlemessages);
596
597 if(trojanscan_swarm[i].clone && !trojanscan_swarm_created) {
598 nick *np = trojanscan_selectuser();
599 if(np) /* select a 'random' sign on time for whois generation */
600 trojanscan_swarm[i].clone->timestamp = np->timestamp;
601 }
602 trojanscan_swarm[i].remaining = trojanscan_minmaxrand(5, 100);
603
604 trojanscan_swarm[i].sitting = 0;
605
606 }
607
608 void trojanscan_free_channels(void) {
609 int i;
610 if(trojanscan_chans) {
611 for(i=0;i<trojanscan_activechans;i++)
612 freesstring(trojanscan_chans[i].channel);
613 tfree(trojanscan_chans);
614 trojanscan_chans = NULL;
615 trojanscan_activechans = 0;
616 }
617 }
618
619 void trojanscan_registerclones(void *arg) {
620 unsigned int i;
621
622 if (!patrol_repool()) {
623 trojanscan_cloneschedule = scheduleoneshot(time(NULL) + 10, &trojanscan_registerclones, NULL);
624 return;
625 }
626
627 trojanscan_cloneschedule = NULL;
628
629 for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++)
630 trojanscan_generateclone((void *)((long)i));
631 trojanscan_mainchanmsg("n: swarm (%d clones) created.", TROJANSCAN_CLONE_TOTAL);
632 trojanscan_swarm_created = 1;
633
634 trojanscan_initialschedule = scheduleoneshot(time(NULL) + 60, &trojanscan_fill_channels, NULL);
635 }
636
637 int trojanscan_status(void *sender, int cargc, char **cargv) {
638 nick *np = (nick *)sender;
639 trojanscan_log(np, "status", "");
640 trojanscan_reply(np, "Channels in schedule: %d", trojanscan_activechans);
641 trojanscan_reply(np, "Channels in database: %d", trojanscan_database.total_channels);
642 trojanscan_reply(np, "Phrases: %d", trojanscan_database.total_phrases);
643 trojanscan_reply(np, "Worms: %d", trojanscan_database.total_worms);
644 trojanscan_reply(np, "Detections: %d", trojanscan_database.detections);
645 trojanscan_reply(np, "Glines: %d", trojanscan_database.glines);
646 trojanscan_reply(np, "Cycletime: %d", trojanscan_cycletime);
647 trojanscan_reply(np, "Clones: %d", TROJANSCAN_CLONE_TOTAL);
648 return CMD_OK;
649 }
650
651 int trojanscan_chanlist(void *sender, int cargc, char **cargv) {
652 int i;
653 nick *np = (nick *)sender;
654 char buf[CHANNELLEN * 2 + 20];
655 trojanscan_reply(np, "Channel list (%d total):", trojanscan_activechans);
656 buf[0] = '\0';
657
658 for(i=0;i<trojanscan_activechans;i++) {
659 if(trojanscan_chans[i].channel->length + 3 > sizeof(buf) - strlen(buf)) {
660 trojanscan_reply(np, "%s", buf);
661 buf[0] = '\0';
662 }
663
664 /* if splidge sees this I'm going to die */
665 strlcat(buf, trojanscan_chans[i].channel->content, sizeof(buf));
666 strlcat(buf, " ", sizeof(buf));
667 }
668 if(buf[0])
669 trojanscan_reply(np, "%s", buf);
670
671 trojanscan_reply(np, "Done.");
672 return CMD_OK;
673 }
674
675 int trojanscan_whois(void *sender, int cargc, char **cargv) {
676 char *tochange;
677 nick *np = (nick *)sender, *np2;
678 int templevel;
679
680 if (cargc < 1) {
681 trojanscan_reply(np, "Not enough parameters.");
682 return CMD_ERROR;
683 }
684
685 if (cargv[0][0] == '#') {
686 tochange = cargv[0] + 1;
687 } else {
688 int i;
689 np2 = getnickbynick(cargv[0]);
690 if (!np2) {
691 trojanscan_reply(np, "That nickname is not on the network.");
692 return CMD_ERROR;
693 }
694 for(i=0;i<TROJANSCAN_CLONE_TOTAL;i++) {
695 if(trojanscan_swarm[i].clone->nick && !ircd_strcmp(trojanscan_swarm[i].clone->nick, np2->nick)) {
696 trojanscan_reply(np, "Nickname : %s", np2->nick);
697 trojanscan_reply(np, "Swarm : yes");
698 return CMD_OK;
699 }
700 }
701 if (!IsAccount(np2)) {
702 trojanscan_reply(np, "User is not authed.");
703 return CMD_OK;
704 }
705 tochange = np2->authname;
706 }
707
708 templevel = trojanscan_user_level_by_authname(tochange);
709 if (templevel == -1) {
710 trojanscan_reply(np, "User does not exist.");
711 } else {
712 union trojanscan_userlevel flags;
713 flags.number = templevel;
714 trojanscan_reply(np, "Authname : %s", tochange);
715 trojanscan_reply(np, "Flags : +" TROJANSCAN_FLAG_MASK, TrojanscanFlagsInfo(flags));
716 }
717
718 return CMD_OK;
719 }
720
721 void trojanscan_privmsg_chan_or_nick(channel *cp, nick *np, char *message, ...) {
722 char buf[513];
723 va_list va;
724
725 if (!trojanscan_nick)
726 return;
727
728 va_start(va, message);
729 vsnprintf(buf, sizeof(buf) - 1, message, va);
730 va_end(va);
731
732 if (cp) {
733 sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
734 } else {
735 sendmessagetouser(trojanscan_nick, np, "%s", buf);
736 }
737
738 }
739
740 int trojanscan_mew(void *sender, int cargc, char **cargv) {
741 nick *np = (nick *)sender, *np2 = NULL;
742 channel *cp = NULL;
743
744 if (cargc < 2) {
745 trojanscan_reply(np, "Not enough paramaters.");
746 return CMD_ERROR;
747 }
748
749 if(cargv[0][0] == '#') {
750 if (!(cp = findchannel(cargv[0]))) {
751 trojanscan_reply(np, "Channel not found.");
752 return CMD_ERROR;
753 }
754 trojanscan_log(np, "mew", "%s %s", cp->index->name->content, cargv[1]);
755 } else {
756 if (!(np2 = getnickbynick(cargv[0]))) {
757 trojanscan_reply(np, "Nickname is not present on the network.");
758 return CMD_ERROR;
759 }
760 trojanscan_log(np, "mew", "%s %s", np2->nick, cargv[1]);
761 }
762
763 trojanscan_privmsg_chan_or_nick(cp, np2, "\001ACTION mews hopefully at %s\001", cargv[1]);
764
765 if (cp) {
766 trojanscan_reply(np, "Mewed at %s in %s.", cargv[1], cp->index->name->content);
767 } else {
768 trojanscan_reply(np, "Mewed at %s at %s.", cargv[1], np2->nick);
769 }
770
771 if(!IsOper(np))
772 trojanscan_mainchanmsg("n: mew: %s %s (%s/%s)", cargv[1], cp?cp->index->name->content:np2->nick, np->nick, np->authname);
773
774 return CMD_OK;
775 }
776
777 int trojanscan_cat(void *sender, int cargc, char **cargv) {
778 nick *np = (nick *)sender, *np2 = NULL;
779 channel *cp = NULL;
780 FILE *cat;
781 char buf[513], *p;
782
783 if (cargc < 1) {
784 trojanscan_reply(np, "Not enough paramaters.");
785 return CMD_ERROR;
786 }
787
788 if(cargv[0][0] == '#') {
789 if (!(cp = findchannel(cargv[0]))) {
790 trojanscan_reply(np, "Channel not found.");
791 return CMD_ERROR;
792 }
793 trojanscan_log(np, "cat", cp->index->name->content);
794 } else {
795 if (!(np2 = getnickbynick(cargv[0]))) {
796 trojanscan_reply(np, "Nickname is not present on the network.");
797 return CMD_ERROR;
798 }
799 trojanscan_log(np, "cat", np2->nick);
800 }
801
802 if ((!(cat = fopen(TROJANSCAN_CAT, "r")))) {
803 trojanscan_reply(np, "Unable to open cat!");
804 return CMD_ERROR;
805 }
806
807 while (fgets(buf, sizeof(buf) - 1, cat)) {
808 if ((p = strchr(buf, '\n'))) {
809 *p = '\0';
810 trojanscan_privmsg_chan_or_nick(cp, np2, "%s", buf);
811 } else if (feof(cat)) {
812 trojanscan_privmsg_chan_or_nick(cp, np2, "%s", buf);
813 }
814 }
815
816 fclose(cat);
817
818 if (cp) {
819 trojanscan_reply(np, "Spammed cat in %s.", cp->index->name->content);
820 } else {
821 trojanscan_reply(np, "Spammed cat at %s.", np2->nick);
822 }
823
824 return CMD_OK;
825 }
826
827 int trojanscan_reschedule(void *sender, int cargc, char **cargv) {
828 nick *np = (nick *)sender;
829 trojanscan_log(np, "reschedule", "");
830 trojanscan_fill_channels(NULL);
831
832 trojanscan_reply(np, "Rescheduled.");
833 return CMD_OK;
834 }
835
836 int trojanscan_listusers(void *sender, int cargc, char **cargv) {
837 nick *np = (nick *)sender;
838
839 trojanscan_log(np, "listusers", "");
840
841 trojanscan_reply(np, "User list:");
842
843 if (!(trojanscan_database_query("SELECT authname, authlevel FROM users ORDER BY authlevel DESC, authname"))) {
844 trojanscan_database_res *res;
845 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
846 if (trojanscan_database_num_rows(res)) {
847 trojanscan_database_row sqlrow;
848 union trojanscan_userlevel flags;
849 while((sqlrow = trojanscan_database_fetch_row(res))) {
850 flags.number = atoi(sqlrow[1]);
851 trojanscan_reply(np, "%s +" TROJANSCAN_FLAG_MASK, sqlrow[0], TrojanscanIsDeveloper(flags) ? "d" : "", TrojanscanIsTeamLeader(flags) ? "t" : "", TrojanscanIsStaff(flags) ? "s" : "", TrojanscanIsWebsite(flags) ? "w" : "", TrojanscanIsCat(flags) ? "c" : "");
852 }
853 }
854 trojanscan_database_free_result(res);
855 }
856 }
857
858 trojanscan_reply(np, "Done.");
859 return CMD_OK;
860 }
861
862 int trojanscan_help(void *sender, int cargc, char **cargv) {
863 nick *np = (nick *)sender;
864
865 if (cargc == 0) {
866 trojanscan_reply(np, "Not enough parameters.");
867 return CMD_ERROR;
868 }
869
870 if (!strcasecmp("help", cargv[0])) {
871 trojanscan_reply(np, "Syntax: help <command name>");
872 trojanscan_reply(np, "Gives help on commands.");
873 } else if (!strcasecmp("status", cargv[0])) {
874 trojanscan_reply(np, "Syntax: status");
875 trojanscan_reply(np, "Gives statistical information about the bot.");
876 } else if (!strcasecmp("join", cargv[0])) {
877 trojanscan_reply(np, "Syntax: join <#channel>");
878 trojanscan_reply(np, "Orders a clone to join supplied channel.");
879 } else if (!strcasecmp("showcommands", cargv[0])) {
880 trojanscan_reply(np, "Syntax: showcommands");
881 trojanscan_reply(np, "Pretty obvious.");
882 } else if (!strcasecmp("hello", cargv[0])) {
883 trojanscan_reply(np, "Syntax: hello ?nickname?");
884 trojanscan_reply(np, "Creates a new user.");
885 } else if (!strcasecmp("rehash", cargv[0])) {
886 trojanscan_reply(np, "Syntax: rehash");
887 trojanscan_reply(np, "Reloads bot database.");
888 } else if (!strcasecmp("changelev", cargv[0])) {
889 trojanscan_reply(np, "Syntax: changelev <nickname or #authname> <flags>");
890 trojanscan_reply(np, "Changes access flags of selected user to supplied input.");
891 trojanscan_reply(np, "+d -> developer");
892 trojanscan_reply(np, "+t -> team leader");
893 trojanscan_reply(np, "+s -> staff");
894 trojanscan_reply(np, "+w -> web management");
895 trojanscan_reply(np, "+c -> cat access");
896 } else if (!strcasecmp("deluser", cargv[0])) {
897 trojanscan_reply(np, "Syntax: deluser <nickname or #authname>");
898 trojanscan_reply(np, "Deletes selected user from my database.");
899 } else if (!strcasecmp("mew", cargv[0])) {
900 trojanscan_reply(np, "Syntax: mew <#channel or nickname> <nickname>");
901 trojanscan_reply(np, "Gracefully mews at target in selected channel or query.");
902 } else if (!strcasecmp("cat", cargv[0])) {
903 trojanscan_reply(np, "Syntax: cat <#channel or nickname>");
904 trojanscan_reply(np, "Shows the almightly cat.");
905 } else if (!strcasecmp("reschedule", cargv[0])) {
906 trojanscan_reply(np, "Syntax: reschedule");
907 trojanscan_reply(np, "Recalculates bots schedule.");
908 } else if (!strcasecmp("chanlist", cargv[0])) {
909 trojanscan_reply(np, "Syntax: chanlist");
910 trojanscan_reply(np, "Displays bots current channel list.");
911 } else if (!strcasecmp("whois", cargv[0])) {
912 trojanscan_reply(np, "Syntax: whois <nickname or #authname>");
913 trojanscan_reply(np, "Displays information on given user.");
914 } else if (!strcasecmp("whois", cargv[0])) {
915 trojanscan_reply(np, "Syntax: listusers <flags>");
916 trojanscan_reply(np, "Displays users with listusersing flags.");
917 } else {
918 trojanscan_reply(np, "Command not found.");
919 return CMD_ERROR;
920 }
921
922 return CMD_OK;
923 }
924
925 int trojanscan_hello(void *sender, int cargc, char **cargv) {
926 nick *np = (nick *)sender, *toadd;
927 char eaccount[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
928 int level = 0;
929
930 if (cargc > 0) {
931 toadd = getnickbynick(cargv[0]);
932 if (!toadd) {
933 trojanscan_reply(np, "That nickname is not on the network.");
934 return CMD_ERROR;
935 }
936 if (!IsAccount(toadd)) {
937 trojanscan_reply(np, "That user is not authed with the network.");
938 return CMD_ERROR;
939 }
940 } else {
941 if (!IsAccount(np)) {
942 trojanscan_reply(np, "You are not authed with the network, auth before creating your user.");
943 return CMD_ERROR;
944 }
945 toadd = np;
946 }
947
948 if (trojanscan_user_level_by_authname(toadd->authname)!=-1) {
949 trojanscan_reply(np, "Authname (%s) is already on file.", toadd->authname);
950 return CMD_ERROR;
951 }
952
953 trojanscan_log(np, "hello", toadd->authname);
954
955 if (!(trojanscan_database_query("SELECT id FROM users LIMIT 1"))) {
956 trojanscan_database_res *res;
957 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
958 if (trojanscan_database_num_rows(res) == 0)
959 level = TROJANSCAN_ACL_DEVELOPER | TROJANSCAN_ACL_STAFF | TROJANSCAN_ACL_WEBSITE | TROJANSCAN_ACL_CAT;
960 trojanscan_database_free_result(res);
961 }
962 }
963
964 trojanscan_database_escape_string(eaccount, toadd->authname, strlen(toadd->authname));
965 trojanscan_database_query("INSERT INTO users (authname, authlevel) VALUES ('%s', %d)", eaccount, level);
966 trojanscan_reply(np, "Account added to database, account %s%s.", toadd->authname, level>0?" (first user so developer access)":"");
967
968 return CMD_OK;
969 }
970
971 int trojanscan_user_level_by_authname(char *authname) {
972 int result = -1, sl = strlen(authname);
973 char eaccount[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
974
975 trojanscan_database_escape_string(eaccount, authname, sl);
976 if (!(trojanscan_database_query("SELECT authlevel, authname FROM users WHERE authname = '%s'", eaccount))) {
977 trojanscan_database_res *res;
978 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
979 if (trojanscan_database_num_rows(res) > 0) {
980 trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
981 result = atoi(sqlrow[0]);
982 strlcpy(authname, sqlrow[1], sl + 1);
983 }
984 trojanscan_database_free_result(res);
985 }
986 }
987 return result;
988 }
989
990 int trojanscan_user_id_by_authname(char *authname) {
991 int result = 0;
992 char eaccount[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
993
994 trojanscan_database_escape_string(eaccount, authname, strlen(authname));
995 if (!(trojanscan_database_query("SELECT id FROM users WHERE authname = '%s'", eaccount))) {
996 trojanscan_database_res *res;
997 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
998 if (trojanscan_database_num_rows(res) > 0) {
999 trojanscan_database_row sqlrow = trojanscan_database_fetch_row(res);
1000 result = atoi(sqlrow[0]);
1001 }
1002 trojanscan_database_free_result(res);
1003 }
1004 }
1005 return result;
1006 }
1007
1008 struct trojanscan_clones *trojanscan_selectclone(char type) {
1009 struct trojanscan_clones *rc;
1010 int randomclone, hits = 0, minlimit, maxlimit;
1011
1012 if(type == TROJANSCAN_WATCH_CLONES) {
1013 minlimit = TROJANSCAN_CLONE_MAX;
1014 maxlimit = minlimit + TROJANSCAN_WATCHCLONE_MAX - 1;
1015 } else {
1016 minlimit = 0;
1017 maxlimit = TROJANSCAN_CLONE_MAX - 1;
1018 }
1019
1020 do {
1021 randomclone = trojanscan_minmaxrand(minlimit, maxlimit);
1022 if (hits++ > 200)
1023 return NULL;
1024 rc = &trojanscan_swarm[randomclone];
1025 if ((type == TROJANSCAN_NORMAL_CLONES) && (rc->sitting == 0) && (rc->remaining == 0))
1026 break;
1027
1028 } while (rc->remaining == 0);
1029
1030 if(type == TROJANSCAN_NORMAL_CLONES) {
1031 if ((rc->sitting == 0) && (rc->remaining == 0)) {
1032 if ((!rc->remaining) && (!rc->sitting)) {
1033 if (rc->clone) {
1034 deregisterlocaluser(rc->clone, NULL);
1035 rc->clone = NULL;
1036 }
1037 trojanscan_generateclone((void *)((long)rc->index));
1038 }
1039 }
1040 }
1041
1042 return rc;
1043
1044 }
1045
1046 struct trojanscan_realchannels *trojanscan_allocaterc(char *chan) {
1047 struct trojanscan_realchannels *rc;
1048 struct trojanscan_clones *clonep;
1049 channel *cp;
1050 int attempts_left = 10;
1051
1052 if (!chan) {
1053 trojanscan_errorcode = 1; /* sorry splidge ;( */
1054 return NULL;
1055 }
1056
1057 if(chan[0] != '#') {
1058 trojanscan_errorcode = 2;
1059 return NULL;
1060 }
1061
1062 if (strlen(chan) > 1) {
1063 if(strrchr(chan, ',')) {
1064 trojanscan_errorcode = 3;
1065 return NULL;
1066 }
1067
1068 if(strrchr(chan, ' ')) {
1069 trojanscan_errorcode = 4;
1070 return NULL;
1071 }
1072 }
1073
1074 cp = findchannel(chan);
1075 if (!cp) {
1076 trojanscan_errorcode = 5;
1077 return NULL;
1078 }
1079
1080 do {
1081 clonep = trojanscan_selectclone(TROJANSCAN_NORMAL_CLONES);
1082 if (!clonep) {
1083 trojanscan_errorcode = 6;
1084 return NULL;
1085 }
1086 if(!nickbanned(clonep->clone, cp, 0))
1087 break;
1088 } while (--attempts_left > 0);
1089
1090 if (!attempts_left) {
1091 trojanscan_errorcode = 7;
1092 return NULL;
1093 }
1094
1095 rc = (struct trojanscan_realchannels *)tmalloc(sizeof(struct trojanscan_realchannels));
1096
1097 rc->next = NULL;
1098 rc->clone = clonep;
1099 rc->chan = cp;
1100 rc->donotpart = 0;
1101 rc->kickedout = 0;
1102 return rc;
1103 }
1104
1105 void trojanscan_join(struct trojanscan_realchannels *rc) {
1106 struct trojanscan_realchannels *rp = trojanscan_realchanlist;
1107
1108 if (rc->clone && rc->clone->clone) {
1109 if (!localjoinchannel(rc->clone->clone, rc->chan)) {
1110 rc->clone->remaining--;
1111 rc->clone->sitting++;
1112 if (trojanscan_minmaxrand(1, TROJANSCAN_NICKCHANGE_ODDS)%TROJANSCAN_NICKCHANGE_ODDS == 0)
1113 trojanscan_donickchange((void *)rc->clone);
1114
1115 rc->schedule = scheduleoneshot(time(NULL)+trojanscan_part_time, &trojanscan_dopart, (void *)rc);
1116
1117 if (rp) {
1118 for(;rp->next;rp=rp->next);
1119 rp->next = rc;
1120 } else {
1121 trojanscan_realchanlist = rc;
1122 }
1123 }
1124 }
1125
1126 }
1127
1128 int trojanscan_userjoin(void *sender, int cargc, char **cargv) {
1129 nick *np = (nick *)sender;
1130 struct trojanscan_realchannels *rc;
1131
1132 if (cargc < 1) {
1133 trojanscan_reply(np, "Not enough paramaters");
1134 return CMD_ERROR;
1135 }
1136
1137 if (!trojanscan_swarm_created) {
1138 trojanscan_reply(np, "My swarm is currently empty.");
1139 return CMD_OK;
1140 }
1141
1142 if((rc = trojanscan_allocaterc(cargv[0]))) {
1143 trojanscan_log(np, "join", cargv[0]);
1144 trojanscan_join(rc);
1145 trojanscan_reply(np, "Clone has joined channel.");
1146 if(!IsOper(np))
1147 trojanscan_mainchanmsg("n: join: %s (%s/%s)", cargv[0], np->nick, np->authname);
1148 } else {
1149 if (trojanscan_errorcode == 5) {
1150 trojanscan_reply(np, "Not joining empty channel, check you entered the correct channel name.");
1151 } else {
1152 trojanscan_reply(np, "Clone could not join channel (error code %d)!", trojanscan_errorcode);
1153 }
1154 }
1155 return CMD_OK;
1156 }
1157
1158 int trojanscan_rehash(void *sender, int cargc, char **cargv) {
1159 nick *np = (void *)sender;
1160 trojanscan_refresh_settings();
1161 trojanscan_read_database(0);
1162 trojanscan_log(np, "rehash", "");
1163 trojanscan_reply(np, "Done.");
1164 return CMD_OK;
1165 }
1166
1167 int trojanscan_changelev(void *sender, int cargc, char **cargv) {
1168 nick *np = (nick *)sender, *np2;
1169 int templevel;
1170 char eaccount[TROJANSCAN_QUERY_TEMP_BUF_SIZE], *tochange, *p, mode = 1, error = 0, clast = 0, specialcase;
1171 union trojanscan_userlevel flags1, flags2;
1172
1173 if (cargc < 2) {
1174 trojanscan_reply(np, "Not enough parameters.");
1175 return CMD_ERROR;
1176 }
1177
1178 templevel = trojanscan_user_level_by_authname(np->authname);
1179
1180 if (templevel == -1) {
1181 trojanscan_reply(np, "You do not have an account.");
1182 return CMD_ERROR;
1183 }
1184
1185 flags1.number = templevel;
1186
1187 if (cargv[0][0] == '#') {
1188 tochange = cargv[0] + 1;
1189 } else {
1190 np2 = getnickbynick(cargv[0]);
1191 if (!np2) {
1192 trojanscan_reply(np, "That nickname is not on the network.");
1193 return CMD_ERROR;
1194 }
1195 if (!IsAccount(np2)) {
1196 trojanscan_reply(np, "That user is not authed with the network.");
1197 return CMD_ERROR;
1198 }
1199 tochange = np2->authname;
1200 }
1201
1202 templevel = trojanscan_user_level_by_authname(tochange);
1203
1204 if (templevel == -1) {
1205 trojanscan_reply(np, "User does not exist.");
1206 return CMD_ERROR;
1207 }
1208
1209 flags2.number = templevel;
1210
1211 if (!ircd_strcmp(np->authname, tochange)) {
1212 specialcase = 1;
1213 } else {
1214 specialcase = 0;
1215 }
1216
1217 for (p=cargv[1];*p;p++) {
1218 switch (*p) {
1219 case '+':
1220 case '-':
1221 mode = (*p == '+');
1222 break;
1223 case 'd':
1224 if (!TrojanscanIsDeveloper(flags1))
1225 clast = 1;
1226 flags2.values.developer = mode;
1227 break;
1228 case 't':
1229 if (!TrojanscanIsDeveloper(flags1))
1230 clast = 1;
1231 flags2.values.teamleader = mode;
1232 break;
1233 case 's':
1234 if (!TrojanscanIsLeastTeamLeader(flags1))
1235 clast = 1;
1236 flags2.values.staff = mode;
1237 break;
1238 case 'w':
1239 if (!TrojanscanIsDeveloper(flags1))
1240 clast = 1;
1241 flags2.values.website = mode;
1242 break;
1243 case 'c':
1244 if (!TrojanscanIsDeveloper(flags1))
1245 clast = 1;
1246 flags2.values.cat = mode;
1247 break;
1248 default:
1249 error = 1;
1250 goto last;
1251 break;
1252 }
1253 if (clast == 1) {
1254 if (specialcase && !mode) { /* allow user to remove their own flags */
1255 clast = 0;
1256 } else {
1257 goto last;
1258 }
1259 }
1260 }
1261
1262 last:
1263 if (*p) {
1264 if (error) {
1265 trojanscan_reply(np, "Unknown mode: %c%c.", mode?'+':'-', *p);
1266 } else {
1267 trojanscan_reply(np, "You have insufficient privilidges to add/remove one or more flags specified.");
1268 }
1269 return CMD_ERROR;
1270 }
1271
1272 trojanscan_log(np, "changelev", "%s %s", tochange, cargv[1]);
1273 trojanscan_database_escape_string(eaccount, tochange, strlen(tochange));
1274 trojanscan_database_query("UPDATE users SET authlevel = %d WHERE authname = '%s'", flags2.number, eaccount);
1275
1276 trojanscan_reply(np, "Flags changed.");
1277
1278 return CMD_OK;
1279 }
1280
1281 int trojanscan_deluser(void *sender, int cargc, char **cargv) {
1282 nick *np = (nick *)sender, *to;
1283 int templevel;
1284 char eaccount[TROJANSCAN_QUERY_TEMP_BUF_SIZE], *account;
1285 union trojanscan_userlevel flags1, flags2;
1286
1287 if (cargc < 1) {
1288 trojanscan_reply(np, "Not enough parameters.");
1289 return CMD_ERROR;
1290 }
1291
1292 if (cargv[0][0] == '#') {
1293 account = cargv[0] + 1;
1294 } else {
1295 to = getnickbynick(cargv[0]);
1296 if (!to) {
1297 trojanscan_reply(np, "That nickname is not on the network.");
1298 return CMD_ERROR;
1299 }
1300 if (!IsAccount(to)) {
1301 trojanscan_reply(np, "That user is not authed with the network.");
1302 return CMD_ERROR;
1303 }
1304 account = to->authname;
1305 }
1306
1307 flags1.number = trojanscan_user_level_by_authname(np->authname);
1308 templevel = trojanscan_user_level_by_authname(account);
1309
1310 if (templevel == -1) {
1311 trojanscan_reply(np, "Auth %s does not exist.", account);
1312 return CMD_ERROR;
1313 }
1314
1315 flags2.number = templevel;
1316
1317 if (!TrojanscanIsDeveloper(flags1) && TrojanscanIsLeastTeamLeader(flags2)) {
1318 trojanscan_reply(np, "Your cannot delete %s as his/her flags equal or surpass your own.", account);
1319 return CMD_ERROR;
1320 }
1321
1322 trojanscan_log(np, "deluser", account);
1323 trojanscan_database_escape_string(eaccount, account, strlen(account));
1324 trojanscan_database_query("DELETE FROM users WHERE authname = '%s'", eaccount);
1325 trojanscan_reply(np, "User deleted.");
1326
1327 return CMD_OK;
1328 }
1329
1330 int trojanscan_add_ll(struct trojanscan_prechannels **head, struct trojanscan_prechannels *newitem) {
1331 struct trojanscan_prechannels *position, *lastitem = NULL, *location = NULL;
1332 if (!*head) {
1333 *head = newitem;
1334 newitem->next = NULL;
1335 if (newitem->exempt) {
1336 return 0;
1337 } else {
1338 return 1;
1339 }
1340 }
1341 /* if its exempt, we don't give a monkeys where it is... */
1342 if (newitem->exempt) {
1343 newitem->next = *head;
1344 *head = newitem;
1345 return 0;
1346 }
1347
1348 for(position=*head;position;lastitem=position,position=position->next) {
1349 if (!ircd_strcmp(position->name->content, newitem->name->content)) {
1350 tfree(newitem);
1351 return 0;
1352 }
1353 if (!location && (position->size < newitem->size)) {
1354 if (!lastitem) {
1355 location = *head;
1356 } else {
1357 location = lastitem;
1358 }
1359 }
1360 }
1361 if (!location) {
1362 newitem->next = NULL;
1363 lastitem->next = newitem;
1364 } else {
1365 newitem->next = location->next;
1366 location->next = newitem;
1367 }
1368 if(newitem->exempt) {
1369 return 0;
1370 } else {
1371 return 1;
1372 }
1373 }
1374
1375 void trojanscan_watch_clone_update(struct trojanscan_prechannels *hp, int count) {
1376 int i, j, marked;
1377 struct trojanscan_prechannels *lp;
1378 struct trojanscan_templist *markedlist = NULL;
1379
1380 if(count > 0) {
1381 markedlist = (struct trojanscan_templist *)tmalloc(count * sizeof(struct trojanscan_templist));
1382 if (!markedlist)
1383 return;
1384 memset(markedlist, 0, sizeof(struct trojanscan_templist) * count);
1385 }
1386
1387 for(i=0;i<trojanscan_activechans;i++) {
1388 marked = 0;
1389 if(markedlist) {
1390 for(lp=hp,j=0;j<count&&lp;j++,lp=lp->next) {
1391 if(!markedlist[j].active && !lp->exempt && !ircd_strcmp(lp->name->content, trojanscan_chans[i].channel->content)) { /* we're already on the channel */
1392 if(trojanscan_chans[i].watch_clone) {
1393 markedlist[j].active = 1;
1394 markedlist[j].watch_clone = trojanscan_chans[i].watch_clone;
1395 lp->watch_clone = trojanscan_chans[i].watch_clone;
1396 }
1397 marked = 1;
1398 break;
1399 }
1400 }
1401 }
1402 if(!marked && trojanscan_chans[i].watch_clone) {
1403 channel *cp = findchannel(trojanscan_chans[i].channel->content);
1404 if(cp)
1405 localpartchannel(trojanscan_chans[i].watch_clone->clone, cp, NULL);
1406 }
1407 }
1408
1409 if(!markedlist)
1410 return;
1411
1412 for(j=0,lp=hp;j<count&&lp;j++,lp=lp->next) {
1413 if((!markedlist[j].active || !markedlist[j].watch_clone) && !lp->exempt) {
1414 channel *cp = findchannel(lp->name->content);
1415 if(cp) {
1416 int attempts = 10;
1417 do {
1418 lp->watch_clone = trojanscan_selectclone(TROJANSCAN_WATCH_CLONES);
1419 if(!lp->watch_clone)
1420 break;
1421 if(!nickbanned(lp->watch_clone->clone, cp, 0)) {
1422 if(localjoinchannel(lp->watch_clone->clone, cp))
1423 lp->watch_clone = NULL;
1424 break;
1425 }
1426 } while(--attempts > 0);
1427 if(!attempts)
1428 lp->watch_clone = NULL;
1429
1430 }
1431 }
1432 }
1433
1434 tfree(markedlist);
1435 }
1436
1437 void trojanscan_fill_channels(void *arg) {
1438 struct trojanscan_prechannels *head = NULL, *lp, *last = NULL;
1439 int i, count, tempctime = 0;
1440
1441 chanindex *chn;
1442
1443 for (count=i=0;i<trojanscan_database.total_channels;i++) {
1444 lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
1445 lp->name = trojanscan_database.channels[i].name;
1446 lp->size = 65535;
1447 lp->exempt = trojanscan_database.channels[i].exempt;
1448 lp->watch_clone = NULL;
1449 if (trojanscan_add_ll(&head, lp))
1450 count++;
1451 }
1452
1453 for (i=0;i<CHANNELHASHSIZE;i++) {
1454 for(chn=chantable[i];chn;chn=chn->next) {
1455 if (chn->channel && !IsKey(chn->channel) && !IsInviteOnly(chn->channel) && !IsRegOnly(chn->channel) && (chn->channel->users->totalusers >= trojanscan_minchansize)) {
1456 lp = (trojanscan_prechannels *)tmalloc(sizeof(trojanscan_prechannels));
1457 lp->name = chn->name;
1458 lp->size = chn->channel->users->totalusers;
1459 lp->exempt = 0;
1460 lp->watch_clone = NULL;
1461 if (trojanscan_add_ll(&head, lp))
1462 count++;
1463 }
1464 }
1465 }
1466
1467 count = TROJANSCAN_MMIN(count, trojanscan_maxchans);
1468
1469 trojanscan_watch_clone_update(head, count);
1470
1471 trojanscan_free_channels();
1472 trojanscan_chans = (struct trojanscan_inchannel *)tmalloc(count * sizeof(struct trojanscan_inchannel));
1473 memset(trojanscan_chans, 0, count * sizeof(struct trojanscan_inchannel));
1474 trojanscan_activechans = count;
1475 i = 0;
1476
1477 for(lp=head;lp;last=lp,lp=lp->next) {
1478 if (!(lp->exempt) && (i < count)) {
1479 trojanscan_chans[i].channel = getsstring(lp->name->content, lp->name->length);
1480 trojanscan_chans[i++].watch_clone = lp->watch_clone;
1481 }
1482 if (last)
1483 tfree(last);
1484 }
1485
1486 if (last)
1487 tfree(last);
1488
1489 if (trojanscan_activechans > 0) {
1490 tempctime = trojanscan_cycletime / trojanscan_activechans;
1491 } else {
1492 tempctime = 60;
1493 trojanscan_mainchanmsg("d: just escaped a divide by zero error (no activechans!), rescheduling in 60 seconds");
1494 }
1495
1496 if(trojanscan_schedule)
1497 deleteschedule(trojanscan_schedule, &trojanscan_dojoin, NULL);
1498
1499 trojanscan_channumber = 0;
1500
1501 trojanscan_schedule = schedulerecurring(time(NULL) + tempctime, trojanscan_activechans + 1, tempctime, trojanscan_dojoin, NULL);
1502
1503 }
1504
1505 void trojanscan_dojoin(void *arg) {
1506 struct trojanscan_realchannels *rc;
1507 if (trojanscan_channumber >= trojanscan_activechans) {
1508 trojanscan_schedule = NULL;
1509 trojanscan_fill_channels(NULL);
1510 } else {
1511 if ((rc = trojanscan_allocaterc(trojanscan_chans[trojanscan_channumber++].channel->content)))
1512 trojanscan_join(rc);
1513 }
1514 }
1515
1516
1517 void trojanscan_dopart(void *arg) {
1518 struct trojanscan_realchannels *rc = (struct trojanscan_realchannels *)arg, *rp, *past = NULL;
1519
1520 if (rc->kickedout) { /* there's a join scheduled, wait for it (reschedule) */
1521 rc->schedule = scheduleoneshot(time(NULL)+5, &trojanscan_dopart, (void *)rc);
1522 return;
1523 }
1524
1525 if (rc->clone->clone && (!(rc->donotpart)))
1526 localpartchannel(rc->clone->clone, rc->chan, NULL);
1527
1528 rc->clone->sitting--;
1529
1530 for(rp=trojanscan_realchanlist;rp;rp=rp->next) {
1531 if (rp == rc) {
1532 if (!past) {
1533 trojanscan_realchanlist = rp->next;
1534 } else {
1535 past->next = rp->next;
1536 }
1537 tfree(rp);
1538 break;
1539 }
1540 past = rp;
1541 }
1542
1543 }
1544
1545 void trojanscan_donickchange(void *arg) { /* just incase I choose to make this schedule at some point */
1546 struct trojanscan_clones *clone = (trojanscan_clones *)arg;
1547
1548 if (clone && clone->clone)
1549 patrol_nickchange(clone->clone);
1550 }
1551
1552 int trojanscan_keysort(const void *v1, const void *v2) {
1553 return ((*(trojanscan_prechannels **)v2)->size - (*(trojanscan_prechannels **)v1)->size);
1554 }
1555
1556 int trojanscan_showcommands(void *sender, int cargc, char **cargv) {
1557 nick *np = (nick *)sender;
1558 Command *cmdlist[100];
1559 int i, n;
1560 char level = 0;
1561
1562 n = getcommandlist(trojanscan_cmds, cmdlist, 100);
1563
1564 trojanscan_reply(np, "The following commands are registered at present:");
1565
1566 for(i=0;i<n;i++) {
1567 if (cmdlist[i]->level & TROJANSCAN_ACL_STAFF) {
1568 level = 's';
1569 } else if (cmdlist[i]->level & TROJANSCAN_ACL_DEVELOPER) {
1570 level = 'd';
1571 } else if (cmdlist[i]->level & TROJANSCAN_ACL_TEAMLEADER) {
1572 level = 't';
1573 } else if (cmdlist[i]->level & TROJANSCAN_ACL_CAT) {
1574 level = 'c';
1575 } else if (cmdlist[i]->level & TROJANSCAN_ACL_WEBSITE) {
1576 level = 'w';
1577 } else if (cmdlist[i]->level & TROJANSCAN_ACL_UNAUTHED) {
1578 level = 0;
1579 }
1580 if (level) {
1581 trojanscan_reply(np, "%s (+%c)", cmdlist[i]->command->content, level);
1582 } else {
1583 trojanscan_reply(np, "%s", cmdlist[i]->command->content);
1584 }
1585 }
1586 trojanscan_reply(np, "End of list.");
1587 return CMD_OK;
1588 }
1589
1590 void trojanscan_handlemessages(nick *target, int messagetype, void **args) {
1591 Command *cmd;
1592 char *cargv[50];
1593 int cargc, templevel;
1594 nick *sender;
1595 union trojanscan_userlevel level;
1596
1597 switch(messagetype) {
1598 case LU_PRIVMSG:
1599 case LU_SECUREMSG:
1600 /* If it's a message, first arg is nick and second is message */
1601 sender = (nick *)args[0];
1602
1603 if(strncmp(TROJANSCAN_VERSION_DETECT, args[1], sizeof(TROJANSCAN_VERSION_DETECT)-1)==0) {
1604 char p = ((char *)args[1])[sizeof(TROJANSCAN_VERSION_DETECT)-1];
1605 if((p == ' ') || (p == '\0') || (p == 1)) {
1606 trojanscan_reply(sender, "\001VERSION Trojanscan (or Tigger) Newserv module version %s by Chris Porter (slug), Newserv by David Mansell (splidge). Compiled " __DATE__ " " __TIME__ ".\001", TROJANSCAN_VERSION);
1607 return;
1608 }
1609 }
1610
1611 /* Split the line into params */
1612 cargc = splitline((char *)args[1], cargv, 50, 0);
1613 if(cargc == 0 || !cargv[0])
1614 return;
1615
1616 cmd=findcommandintree(trojanscan_cmds, cargv[0], 1);
1617 if (!cmd) {
1618 trojanscan_reply(sender, "Unknown command.");
1619 return;
1620 }
1621
1622 if ((cmd->level & TROJANSCAN_ACL_OPER) && !IsOper(sender)) {
1623 trojanscan_reply(sender, "You need to be opered to use this command.");
1624 return;
1625 }
1626
1627 /* bit grim code... */
1628
1629 if (!(cmd->level & TROJANSCAN_ACL_UNAUTHED)) {
1630 if (!IsAccount(sender)) {
1631 trojanscan_reply(sender, "You must be authed with the network to access this command!");
1632 return;
1633 }
1634 templevel = trojanscan_user_level_by_authname(sender->authname);
1635
1636 if (templevel == -1) {
1637 trojanscan_reply(sender, "You do not have an account.");
1638 return;
1639 }
1640
1641 level.number = templevel;
1642
1643 if ((cmd->level & TROJANSCAN_ACL_DEVELOPER) && !TrojanscanIsDeveloper(level)) {
1644 trojanscan_reply(sender, "Access denied.");
1645 return;
1646 }
1647 if ((cmd->level & TROJANSCAN_ACL_TEAMLEADER) && !TrojanscanIsLeastTeamLeader(level)) {
1648 trojanscan_reply(sender, "Access denied.");
1649 return;
1650 }
1651 if ((cmd->level & TROJANSCAN_ACL_STAFF) && !TrojanscanIsLeastStaff(level)) {
1652 trojanscan_reply(sender, "Access denied.");
1653 return;
1654 }
1655 if ((cmd->level & TROJANSCAN_ACL_CAT) && !TrojanscanIsCat(level)) {
1656 trojanscan_reply(sender, "Access denied.");
1657 return;
1658 }
1659 if ((cmd->level & TROJANSCAN_ACL_WEBSITE) && !TrojanscanIsLeastWebsite(level)) {
1660 trojanscan_reply(sender, "Access denied.");
1661 return;
1662 }
1663 }
1664
1665 /* Check the maxargs */
1666 if (cmd->maxparams<(cargc-1)) {
1667 /* We need to do some rejoining */
1668 rejoinline(cargv[cmd->maxparams], cargc-(cmd->maxparams));
1669 cargc = (cmd->maxparams) + 1;
1670 }
1671
1672 (cmd->handler)((void *)sender, cargc - 1, &(cargv[1]));
1673 break;
1674
1675 case LU_KILLED:
1676 /* someone killed me? Bastards */
1677 trojanscan_connect_nick_schedule = scheduleoneshot(time(NULL) + 1, &trojanscan_connect_nick, NULL);
1678 trojanscan_nick = NULL;
1679 break;
1680
1681 default:
1682 break;
1683 }
1684 }
1685
1686 static char trojanscan_getmtfromhooktype(int input) {
1687 switch(input) {
1688 case HOOK_CHANNEL_PART: return 'P';
1689 default: return '?';
1690 }
1691 }
1692
1693 char trojanscan_getmtfrommessagetype(int input) {
1694 switch(input) {
1695 case LU_PRIVMSG: return 'm';
1696 case LU_PRIVNOTICE: return 'n';
1697 case LU_SECUREMSG: return 's';
1698 case LU_CHANMSG: return 'M';
1699 case LU_CHANNOTICE: return 'N';
1700 default: return '?';
1701 }
1702 }
1703
1704 static void trojanscan_process(nick *sender, channel *cp, char mt, char *pretext) {
1705 char text[513];
1706 unsigned int len;
1707 unsigned int i;
1708 struct trojanscan_worms *worm;
1709 int vector[30], detected = 0;
1710
1711 trojanscan_strip_codes(text, sizeof(text) - 1, pretext);
1712
1713 len = strlen(text);
1714
1715 for(i=0;i<trojanscan_database.total_phrases;i++) {
1716 if (
1717 (
1718 (worm = trojanscan_database.phrases[i].worm)
1719 ) &&
1720 (
1721 (
1722 (
1723 (mt == 'm') || (mt == 's') || (mt == 'n')
1724 ) &&
1725 (
1726 (trojanscan_database.phrases[i].worm->hitpriv)
1727 )
1728 ) ||
1729 (
1730 (
1731 (mt == 'M') || (mt == 'N') || (mt == 'P')
1732 ) &&
1733 (
1734 (trojanscan_database.phrases[i].worm->hitchans)
1735 )
1736 )
1737 ) &&
1738 (trojanscan_database.phrases[i].phrase)
1739 ) {
1740 int pre = pcre_exec(trojanscan_database.phrases[i].phrase, trojanscan_database.phrases[i].hint, text, len, 0, 0, vector, 30);
1741 if(pre >= 0) {
1742 char matchbuf[513];
1743 matchbuf[0] = 0;
1744 matchbuf[512] = 0; /* hmm */
1745
1746 if(pre > 1)
1747 if(pcre_copy_substring(text, vector, pre, 1, matchbuf, sizeof(matchbuf) - 1) <= 0)
1748 matchbuf[0] = 0;
1749
1750 trojanscan_phrasematch(cp, sender, &trojanscan_database.phrases[i], mt, matchbuf);
1751
1752 detected = 1;
1753 break;
1754 }
1755 }
1756 }
1757 if (!detected && (mt != 'N') && (mt != 'M')) {
1758 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];
1759 trojanscan_database_escape_string(etext, text, len);
1760 trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
1761 trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
1762 trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
1763 trojanscan_database_query("INSERT INTO unknownlog (data, user) VALUES ('%s','%s!%s@%s')", etext, enick, eident, ehost);
1764 }
1765 }
1766
1767 void trojanscan_clonehandlemessages(nick *target, int messagetype, void **args) {
1768 char *pretext = NULL;
1769 nick *sender;
1770 struct trojanscan_realchannels *rp;
1771 struct trojanscan_rejoinlist *rj;
1772 char mt = trojanscan_getmtfrommessagetype(messagetype);
1773 char *channel_name;
1774 channel *cp = NULL;
1775 int i;
1776
1777 switch(messagetype) {
1778 case LU_PRIVMSG:
1779 case LU_SECUREMSG:
1780 case LU_PRIVNOTICE:
1781
1782 pretext = (char *)args[1];
1783
1784 case LU_CHANMSG:
1785 case LU_CHANNOTICE:
1786 sender = (nick *)args[0];
1787
1788 if (strlen(sender->nick) < 2)
1789 break;
1790
1791 if (!pretext) {
1792 pretext = (char *)args[2];
1793 cp = args[1];
1794 }
1795
1796 if(strncmp(TROJANSCAN_VERSION_DETECT, pretext, sizeof(TROJANSCAN_VERSION_DETECT)-1)==0) {
1797 char p = pretext[sizeof(TROJANSCAN_VERSION_DETECT)-1];
1798 if((p == ' ') || (p == '\0') || (p == 1)) {
1799 int staff = 0;
1800 if (IsOper(sender)) {
1801 staff = 1;
1802 } else {
1803 if (IsAccount(sender)) {
1804 int templevel = trojanscan_user_level_by_authname(sender->authname);
1805 if (templevel != -1) {
1806 union trojanscan_userlevel level;
1807 level.number = templevel;
1808 if (TrojanscanIsLeastStaff(level))
1809 staff = 1;
1810 }
1811 }
1812 }
1813 if (staff) {
1814 if(trojanscan_nick) {
1815 sendnoticetouser(target, sender, "\001VERSION T clone, check T for confirmation.\001");
1816 sendnoticetouser(trojanscan_nick, sender, "\001VERSION %s is part of my swarm.\001", target->nick);
1817 } else {
1818 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");
1819 }
1820 } else {
1821 sendnoticetouser(target, sender, "\001VERSION %s\001", versionreply);
1822 }
1823
1824 return;
1825 }
1826 }
1827
1828 trojanscan_process(sender, cp, mt, pretext);
1829 break;
1830 case LU_KILLED:
1831 /* someone killed me? Bastards */
1832
1833 /* PPA: we do NOT rejoin channels at this moment in time, it is possible to do this though */
1834 for (i=0;i<TROJANSCAN_CLONE_TOTAL;i++) {
1835 if (trojanscan_swarm[i].clone == target) {
1836
1837 scheduleoneshot(time(NULL)+1, &trojanscan_generateclone, (void *)((long)i));
1838 if(i >= TROJANSCAN_CLONE_MAX) {
1839 int j;
1840 for(j=0;j<trojanscan_activechans;j++)
1841 if(trojanscan_chans[j].watch_clone == &trojanscan_swarm[i])
1842 trojanscan_chans[j].watch_clone = NULL;
1843 } else {
1844 for(rp=trojanscan_realchanlist;rp;rp=rp->next)
1845 if (rp->clone == &(trojanscan_swarm[i]))
1846 rp->donotpart = 1;
1847 }
1848 trojanscan_swarm[i].clone = NULL;
1849 trojanscan_swarm[i].remaining = 0; /* bah */
1850 break;
1851 }
1852 }
1853 break;
1854
1855 case LU_KICKED:
1856 channel_name = ((channel *)args[1])->index->name->content;
1857 for (i=0;i<trojanscan_activechans;i++) {
1858 if (!trojanscan_chans[i].watch_clone)
1859 continue;
1860 if ((trojanscan_chans[i].watch_clone->clone == target) && (!strcmp(trojanscan_chans[i].channel->content, channel_name)))
1861 break;
1862 }
1863 if(i != trojanscan_activechans) {
1864 int j;
1865 for(j=0;j<TROJANSCAN_CLONE_TOTAL;j++) {
1866 if(&trojanscan_swarm[j] == trojanscan_chans[i].watch_clone) {
1867 trojanscan_chans[i].watch_clone = NULL;
1868 break;
1869 }
1870 }
1871 } else {
1872 /*
1873 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)");
1874 */
1875 rj = (struct trojanscan_rejoinlist *)tmalloc(sizeof(struct trojanscan_rejoinlist));
1876 if (rj) {
1877 rj->rp = NULL;
1878 for(rp=trojanscan_realchanlist;rp;rp=rp->next)
1879 if ((rp->clone->clone == target) && (rp->chan == args[1])) {
1880 rp->kickedout++;
1881 rj->rp = rp;
1882 break;
1883 }
1884 if(!rj->rp) {
1885 tfree(rj);
1886 return;
1887 }
1888
1889 rj->channel = getsstring(((channel *)args[1])->index->name->content, ((channel *)args[1])->index->name->length);
1890 if(!rj->channel) {
1891 trojanscan_mainchanmsg("d: unable to allocate memory for channel: %s upon rejoin", ((channel *)args[1])->index->name->content);
1892 tfree(rj);
1893 return;
1894 }
1895
1896 rj->clone = rp->clone;
1897 rj->next = trojanscan_schedulerejoins;
1898 trojanscan_schedulerejoins = rj;
1899
1900 rj->schedule = scheduleoneshot(time(NULL)+1, &trojanscan_rejoin_channel, (void *)rj);
1901 }
1902 }
1903 break;
1904 default:
1905 break;
1906 }
1907 }
1908
1909 static void trojanscan_part_watch(int hook, void *arg) {
1910 void **arglist = (void **)arg;
1911 channel *cp = (channel *)arglist[0];
1912 nick *np = arglist[1];
1913 char *reason = arglist[2];
1914
1915 if(!cp || !np || !reason || (*reason == '\0'))
1916 return;
1917
1918 trojanscan_process(np, cp, trojanscan_getmtfromhooktype(hook), reason);
1919 }
1920
1921 void trojanscan_phrasematch(channel *chp, nick *sender, trojanscan_phrases *phrase, char messagetype, char *matchbuf) {
1922 char glinemask[HOSTLEN + USERLEN + NICKLEN + 4], enick[TROJANSCAN_QUERY_TEMP_BUF_SIZE], eident[TROJANSCAN_QUERY_TEMP_BUF_SIZE], ehost[TROJANSCAN_QUERY_TEMP_BUF_SIZE];
1923 unsigned int frequency;
1924 int glining = 0, usercount;
1925 struct trojanscan_worms *worm = phrase->worm;
1926 char reason[200];
1927
1928 trojanscan_database.detections++;
1929
1930 usercount = 0;
1931 if (worm->monitor) {
1932 usercount = -1;
1933 } else if(worm->glinehost || worm->glineuser) {
1934 glining = 1;
1935
1936 usercount = glinebynick(sender, 0, NULL, GLINE_SIMULATE, "trojanscan");
1937 }
1938
1939 if (!usercount) {
1940 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);
1941 return;
1942 }
1943
1944 if (glining && (usercount > trojanscan_maxusers)) {
1945 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);
1946 return;
1947 }
1948
1949 if (glining && !worm->datalen) {
1950 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);
1951 return;
1952 }
1953
1954 trojanscan_database_escape_string(enick, sender->nick, strlen(sender->nick));
1955 trojanscan_database_escape_string(eident, sender->ident, strlen(sender->ident));
1956 trojanscan_database_escape_string(ehost, sender->host->name->content, sender->host->name->length);
1957
1958 frequency = 1;
1959
1960 if (!(trojanscan_database_query("SELECT COUNT(*) FROM hits WHERE glined = %d AND host = '%s'", glining, ehost))) {
1961 trojanscan_database_res *res;
1962 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
1963 trojanscan_database_row sqlrow;
1964 if ((trojanscan_database_num_rows(res) > 0) && (sqlrow = trojanscan_database_fetch_row(res)))
1965 frequency = atoi(sqlrow[0]) + 1;
1966 trojanscan_database_free_result(res);
1967 }
1968 }
1969
1970 if (!glining) {
1971 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:"");
1972 #ifdef TROJANSCAN_PEONCHANNEL
1973 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:"");
1974 #endif
1975 } else {
1976 int glinetime = TROJANSCAN_FIRST_OFFENSE * frequency * (worm->epidemic?TROJANSCAN_EPIDEMIC_MULTIPLIER:1);
1977 if(glinetime > 7 * 24)
1978 glinetime = 7 * 24; /* can't set glines over 7 days with normal non U:lined glines */
1979
1980 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);
1981 trojanscan_database.glines++;
1982
1983 snprintf(reason, sizeof(reason), "You (%s!%s@%s) are infected with a trojan (%s/%d), see %s%d for details - banned for %d hours", sender->nick, sender->ident, sender->host->name->content, worm->name->content, phrase->id, TROJANSCAN_URL_PREFIX, worm->id, glinetime);
1984 glinebynick(sender, glinetime * 3600, reason, 0, "trojanscan");
1985
1986 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:"");
1987 }
1988 }
1989
1990 void trojanscan_rejoin_channel(void *arg) {
1991 struct trojanscan_rejoinlist *rj2, *lrj, *rj = (struct trojanscan_rejoinlist *)arg;
1992
1993 channel *cp = findchannel(rj->channel->content);
1994 freesstring(rj->channel);
1995
1996 if (rj->rp) {
1997 rj->rp->kickedout--;
1998 if (!cp) {
1999 rj->rp->donotpart = 1; /* we were the last user on the channel, so we need to be VERY careful freeing it */
2000 } else {
2001 if(!rj->rp->donotpart && !rj->rp->kickedout) { /* check we're allowed to join channels (not killed), and we're the last one to join */
2002 if (nickbanned(rj->clone->clone, cp, 0)) {
2003 rj->rp->donotpart = 1;
2004 } else {
2005 localjoinchannel(rj->clone->clone, cp);
2006 }
2007 }
2008 }
2009 }
2010
2011 rj2 = trojanscan_schedulerejoins;
2012 lrj = NULL;
2013
2014 if (rj2 == rj) {
2015 trojanscan_schedulerejoins = rj->next;
2016 tfree(rj);
2017 } else {
2018 for(rj2=trojanscan_schedulerejoins;rj2;lrj=rj2,rj2=rj2->next) {
2019 if (rj2 == rj) {
2020 lrj->next = rj2->next;
2021 tfree(rj);
2022 break;
2023 }
2024 }
2025 }
2026
2027 }
2028
2029 void trojanscan_reply(nick *target, char *message, ... ) {
2030 char buf[513];
2031 va_list va;
2032
2033 if (!trojanscan_nick)
2034 return;
2035
2036 va_start(va, message);
2037 vsnprintf(buf, sizeof(buf) - 1, message, va);
2038 va_end(va);
2039
2040 sendnoticetouser(trojanscan_nick, target, "%s", buf);
2041 }
2042
2043
2044 void trojanscan_mainchanmsg(char *message, ...) {
2045 char buf[513];
2046 va_list va;
2047 channel *cp;
2048
2049 if (!trojanscan_nick)
2050 return;
2051 if (!(cp = findchannel(TROJANSCAN_CHANNEL)))
2052 return;
2053
2054 va_start(va, message);
2055 vsnprintf(buf, sizeof(buf) - 1, message, va);
2056 va_end(va);
2057
2058 sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
2059 }
2060
2061 #ifdef TROJANSCAN_PEONCHANNEL
2062 void trojanscan_peonchanmsg(char *message, ...) {
2063 char buf[513];
2064 va_list va;
2065 channel *cp;
2066
2067 if (!trojanscan_nick)
2068 return;
2069 if (!(cp = findchannel(TROJANSCAN_PEONCHANNEL)))
2070 return;
2071
2072 va_start(va, message);
2073 vsnprintf(buf, sizeof(buf) - 1, message, va);
2074 va_end(va);
2075
2076 sendmessagetochannel(trojanscan_nick, cp, "%s", buf);
2077 }
2078 #endif
2079
2080 int trojanscan_minmaxrand(float min, float max) {
2081 return (int)((max-min+1)*rand()/(RAND_MAX+min))+min;
2082 }
2083
2084 nick *trojanscan_selectuser(void) {
2085 int target = trojanscan_minmaxrand(0, 500), loops = 150, j;
2086 nick *np;
2087 do {
2088 for (j=trojanscan_minmaxrand(0, NICKHASHSIZE-1);j<NICKHASHSIZE;j++)
2089 for(np=nicktable[j];np;np=np->next)
2090 if (!--target)
2091 return np;
2092 } while(--loops > 0);
2093 return NULL;
2094 }
2095
2096 static void db_ping(void *arg) {
2097 if (!(trojanscan_database_query("SELECT 1"))) {
2098 trojanscan_database_res *res;
2099 if ((res = trojanscan_database_store_result(&trojanscan_sql))) {
2100 trojanscan_database_free_result(res);
2101 }
2102 }
2103
2104 db_ping_schedule = scheduleoneshot(time(NULL) + 60, &db_ping, NULL);
2105 }
2106
2107 void trojanscan_database_close(void) {
2108 if(db_ping_schedule)
2109 deleteschedule(db_ping_schedule, db_ping, NULL);
2110
2111 mysql_close(&trojanscan_sql);
2112 }
2113
2114 int trojanscan_database_connect(char *dbhost, char *dbuser, char *dbpass, char *db, unsigned int port) {
2115 mysql_init(&trojanscan_sql);
2116 if (!mysql_real_connect(&trojanscan_sql, dbhost, dbuser, dbpass, db, port, NULL, 0))
2117 return -1;
2118
2119
2120 db_ping_schedule = scheduleoneshot(time(NULL) + 60, &db_ping, NULL);
2121
2122 return 0;
2123 }
2124
2125 void trojanscan_database_escape_string(char *dest, char *source, size_t length) {
2126 mysql_escape_string(dest, source, length);
2127 }
2128
2129 int trojanscan_database_query(char *format, ...) {
2130 char trojanscan_sqlquery[TROJANSCAN_QUERY_BUF_SIZE];
2131 va_list va;
2132
2133 va_start(va, format);
2134 vsnprintf(trojanscan_sqlquery, sizeof(trojanscan_sqlquery) - 1, format, va);
2135 va_end(va);
2136 return mysql_query(&trojanscan_sql, trojanscan_sqlquery);
2137 }
2138
2139 int trojanscan_database_num_rows(trojanscan_database_res *res) {
2140 return mysql_num_rows(res);
2141 }
2142
2143 trojanscan_database_res *trojanscan_database_store_result() {
2144 return mysql_store_result(&trojanscan_sql);
2145 }
2146
2147 trojanscan_database_row trojanscan_database_fetch_row(trojanscan_database_res *res) {
2148 return mysql_fetch_row(res);
2149 }
2150
2151 void trojanscan_database_free_result(trojanscan_database_res *res) {
2152 mysql_free_result(res);
2153 }
2154
2155 int trojanscan_isip(char *host) {
2156 char *p = host, components = 0, length = 0;
2157
2158 for(;*p;p++) {
2159 if(*p == '.') {
2160 if(((!length) || (length = 0)) || (++components > 3))
2161 return 0;
2162 } else {
2163 if ((++length > 3) || !isdigit(*p))
2164 return 0;
2165 }
2166 }
2167 return components == 3;
2168 }
2169