]> jfr.im git - irc/SurrealServices/srsv.git/blame - branches/0.4.3/modules/securitybot.pm
further work on TOR loading
[irc/SurrealServices/srsv.git] / branches / 0.4.3 / modules / securitybot.pm
CommitLineData
7b261bb8 1#!/usr/bin/perl
2#
3# Copyright saturn@surrealchat.net
4# multiple feature-adds and code changes tabris@tabris.net
5#
6# Licensed under the GNU Public License
7# http://www.gnu.org/licenses/gpl.txt
8#
9
10package securitybot;
11
12use strict;
13no strict "refs";
14use Time::HiRes qw(gettimeofday);
15
16use SrSv::Process::Init;
17use SrSv::IRCd::Event 'addhandler';
18use SrSv::IRCd::State 'initial_synced';
19use SrSv::Timer qw(add_timer);
20use SrSv::Time;
21use SrSv::Agent;
22use SrSv::HostMask qw( parse_hostmask );
7b261bb8 23use SrSv::Conf2Consts qw(main sql);
24use SrSv::SimpleHash qw(readHash writeHash);
25
26use SrSv::Log;
27
28use SrSv::User qw( get_user_nick );
29use SrSv::User::Notice;
30use SrSv::Help qw( sendhelp );
31
32use SrSv::MySQL '$dbh';
33use SrSv::MySQL::Glob;
34
b0a0754f 35use SrSv::Shared qw(%conf $torip %unwhois);
7b261bb8 36
b6cdbd26 37use SrSv::Process::InParent qw(list_conf loadconf saveconf update_tor_list);
7b261bb8 38
39use SrSv::TOR;
40
7b261bb8 41#this stuff needs to be put into files
42our $sbnick = "SecurityBot";
43our $ident = 'Security';
44our $gecos = 'Security Monitor (you are being monitored)';
45our $umodes = '+BHSdopqz';
46our $vhost = 'services.SC.bot';
47
48our (
49 $add_spamfilter, $del_spamfilter, $add_tklban, $del_tklban,
50 $del_expired_tklban, $get_expired_tklban,
51
52 $get_tklban, $get_spamfilter,
53 $get_all_tklban, $get_all_spamfilter,
54
55 $check_opm,
56);
57
58loadconf(0);
59our $enabletor = $conf{'EnableTor'};
60register();
61
62addhandler('SEOS', undef, undef, "securitybot::start_timers");
63addhandler('TKL', undef, undef, "securitybot::handle_tkl");
64
65addhandler('PRIVMSG', undef, $sbnick, "securitybot::msghandle");
66addhandler('NOTICE', undef, $sbnick, "securitybot::noticehandle");
67addhandler('SENDSNO', undef, undef, "securitybot::snotice");
68addhandler('GLOBOPS', undef, undef, "securitybot::globops");
69addhandler('SMO', undef, undef, "securitybot::snotice");
70
71if($conf{'EnableTor'} or $conf{'CTCPonConnect'} or $conf{'EnableOPM'}) {
72 addhandler('NICKCONN', undef, undef, 'securitybot::nickconn');
73 addhandler('USERIP', undef, undef, 'securitybot::userip');
74}
75
76proc_init {
77 $add_tklban = $dbh->prepare_cached("REPLACE INTO tklban
78 SET type=?, ident=?, host=?, setter=?, expire=?, time=?, reason=?");
79 $del_tklban = $dbh->prepare_cached("DELETE FROM tklban WHERE type=? AND ident=? AND host=?");
80 $add_spamfilter = $dbh->prepare_cached("REPLACE INTO spamfilter
81 SET target=?, action=?, setter=?, expire=?, time=?, bantime=?, reason=?, mask=?");
82 $del_spamfilter = $dbh->prepare_cached("DELETE FROM spamfilter WHERE target=? AND action=? AND mask=?");
83
84 $del_expired_tklban = $dbh->prepare_cached("DELETE FROM tklban WHERE expire <= UNIX_TIMESTAMP() AND expire!=0");
85 $get_expired_tklban = $dbh->prepare_cached("SELECT type, ident, host, setter, expire, time, reason
86 FROM tklban WHERE expire <= UNIX_TIMESTAMP() AND expire!=0");
87
88 $get_tklban = $dbh->prepare_cached("SELECT setter, expire, time, reason FROM tklban WHERE
89 type=? AND ident=? AND host=?");
90 $get_spamfilter = $dbh->prepare_cached("SELECT time, reason FROM spamfilter WHERE target=? AND action=? AND mask=?");
91
92 $get_all_tklban = $dbh->prepare_cached("SELECT type, ident, host, setter, expire, time, reason
93 FROM tklban ORDER BY type, time, host");
94 $get_all_spamfilter = $dbh->prepare_cached("SELECT target, action, setter, expire, time, bantime, reason, mask, managed
95 FROM spamfilter ORDER BY time, mask");
96
97 $check_opm = $dbh->prepare_cached("SELECT 1 FROM opm WHERE ipaddr=?");
98};
99
100sub init {
40bf2790 101 return if main::COMPILE_ONLY();
7b261bb8 102 my $tmpdbh = DBI->connect(
103 "DBI:mysql:".sql_conf_mysql_db,
104 sql_conf_mysql_user,
105 sql_conf_mysql_pass,
106 {
107 AutoCommit => 1,
108 RaiseError => 1
109 }
110 );
111 $tmpdbh->do("TRUNCATE TABLE tklban");
112 $tmpdbh->do("TRUNCATE TABLE spamfilter");
113 $tmpdbh->disconnect();
114}
115
116=cut
117my %snomasks = (
118 e => 'Eyes Notice',
119 v => 'VHost Notice',
120 # They're prefixed already.
121 #S => 'Spamfilter',
122 o => 'Oper-up Notice',
123);
124=cut
125
126sub snotice($$$) {
127 my ($server, $type, $msg) = @_;
128# $type = $snomasks{$type};
129# diagmsg( ($type ? "[$type] " : '').$msg);
130 diagmsg( $msg);
131}
132
133sub globops($$) {
134 my ($src, $msg) = @_;
135 diagmsg("Global -- from $src: $msg");
136}
137
138sub register {
d2344bba 139 agent_connect($sbnick, $ident, undef, $umodes, $gecos);
7b261bb8 140 ircd::sqline($sbnick, 'Reserved for Services');
141
142 agent_join($sbnick, main_conf_diag);
143 ircd::setmode($sbnick, main_conf_diag, '+o', $sbnick);
144}
145
146sub start_timers {
147 add_timer('', 5, __PACKAGE__, 'securitybot::start_timers2');
148 expire_tkl_timed();
149}
150
151sub start_timers2 {
39dbe351 152 update_tor_list_timed(3540) if $enabletor;
7b261bb8 153 #securitybot::ss2tkl::update_ss_timed(3300) if $conf{'EnableSS'};
154};
155
156sub nickconn {
157 my ($rnick, $time, $ident, $host, $vhost, $server, $modes, $gecos, $ip, $svsstamp) = @_[0,2..4,8,5,7,9,10,6];
158
159 goto OUT if ($svsstamp or $unwhois{lc $rnick});
160
161 if((initial_synced and $enabletor) or $conf{'EnableOPM'} or $conf{'BanCountry'} ) {
162 if ($ip) {
163 check_blacklists($rnick, $ip) or return;
164 }
165 else {
166 ircd::userip($rnick) unless module::is_loaded('services');
167 }
168 }
169
170 if($conf{'CTCPonConnect'}) {
171 my @ctcplist = split(/ /, $conf{'CTCPonConnect'});
172 foreach my $ctcp_msg (@ctcplist) {
173 if(uc($ctcp_msg) eq 'PING') {
174 my ($sec, $usec) = gettimeofday();
175 ircd::ctcp($sbnick, $rnick, 'PING', $sec, $usec);
176 } else {
177 ircd::ctcp($sbnick, $rnick, uc($ctcp_msg));
178 }
179 }
180 }
181 OUT:
182 $unwhois{lc $rnick} = 1 unless ($svsstamp or $ip);
183}
184
185sub userip {
186 my($src, $rnick, $ip) = @_;
187
188 return unless($unwhois{lc $rnick});
189 return unless($ip =~ /^\d{1,3}(\.\d{1,3}){3}$/);
190
191 check_blacklists($rnick, $ip) or return;
192
193 delete $unwhois{lc $rnick};
194}
195
196sub check_opm($) {
197 my ($ip) = @_;
198 $check_opm->execute($ip);
199 my ($ret) = $check_opm->fetchrow_array();
200 $check_opm->finish();
201 return $ret;
202}
203
204sub check_country($) {
205 my ($ip) = @_;
206 my $ccode;
207 if(module::is_loaded('geoip')) {
208 $ccode = geoip::get_ip_location($ip);
209 } elsif(module::is_loaded('country')) {
210 $ccode = country::get_ip_country_aton($ip);
211 }
212 foreach my $country (split(/[, ]+/, $conf{'BanCountry'})) {
213 if (lc $ccode eq lc $country) {
214 return country::get_country_long($country);
215 }
216 }
217 return undef;
218}
219
220sub mk_banreason($$) {
221 my ($reason, $ip) = @_;
222 $reason =~ s/\$/$ip/g;
223 return $reason;
224}
225
226sub check_blacklists($$) {
227 my ($rnick, $ip) = @_;
228
b0a0754f 229 if(initial_synced and $enabletor && $torip->{$ip}) {
7b261bb8 230 if (lc $enabletor eq lc 'vhost') {
231 ircd::chghost($sbnick, $rnick, misc::gen_uuid(1, 20).'.session.tor');
232 } else {
233 ircd::zline($sbnick, $ip, $conf{'ProxyZlineTime'}, $conf{'TorZlineReason'});
234 }
235 return 0;
236 }
237
238 if($conf{'EnableOPM'} && check_opm($ip)) {
239 ircd::zline($sbnick, $ip, $conf{'ProxyZlineTime'}, mk_banreason($conf{'OPMZlineReason'}, $ip));
240 return 0;
241 }
242
8f076623 243sub hasGeoCountry() {
244 return module::is_loaded('country') || module::is_loaded('geoip');
245}
246
247 if($conf{'BanCountry'} && hasGeoCountry() && (my $country = check_country($ip))) {
7b261bb8 248 ircd::zline($sbnick, $ip, $conf{'ProxyZlineTime'}, mk_banreason($conf{'CountryZlineReason'}, $country));
249 return 0;
250 }
251
252 return 1;
253}
254
255sub update_tor_list_timed($) {
256 my $time = shift;
257 $time = 3600 unless $time;
258
259 add_timer('', $time, __PACKAGE__, 'securitybot::update_tor_list_timed');
260
39dbe351 261 update_tor_list() if $enabletor;
7b261bb8 262}
263
264sub update_tor_list() {
6f1e56e4 265 return unless (defined($conf{'TorServer'}) && length($conf{'TorServer'}));
7b261bb8 266 diagmsg( " -- Loading Tor server list.");
267
268 # path may be a local one if you run a tor-client.
269 # most configs are /var/lib/tor/cached-directory
270 my %newtorip;
b0a0754f 271 my @entries;
272 local $SIG{__DIE__} = undef;
273 eval {
274 @entries = getTorRouters($conf{'TorServer'});
275 };
276 if($@) {
277 ircd::debug("SecurityBot failed to load TOR data", $@);
278 return;
279 }
280 foreach my $torIP (@entries) {
7b261bb8 281 $newtorip{$torIP} = 1;
282 }
283
284 my $torcount = scalar(keys(%newtorip));
285
286 if($torcount > 0) {
b0a0754f 287 $torip = \%newtorip;
7b261bb8 288 diagmsg( " -- Finished loading Tor server list - $torcount servers found.");
289 } else {
290 diagmsg( " -- Failed to load Tor server list, CHECK YOUR TorServer SETTING.");
291 }
292}
293
294sub msghandle {
295 my ($rnick, $dst, $msg) = @_;
296 print join("\n", @_);
297 my $user = { NICK => $rnick, AGENT => $sbnick };
298 unless (adminserv::is_ircop($user)) {
299 notice($user, 'Permission Denied');
300 return;
301 }
302
303 if($msg =~ /^help/i) {
304 my (undef, @args) = split(/ /, $msg); #discards first token 'help'
305 sendhelp($user, 'securitybot', @args);
306 }
307
308 elsif($msg =~ /^notice (\S*) (.*)/i) {
309 ircd::notice($sbnick, $1, $2);
310 }
311
312 elsif($msg =~ /^msg (\S*) (.*)/i) {
313 ircd::privmsg($sbnick, $1, $2);
314 }
315
316 elsif($msg =~ /^raw (.*)/i) {
317 if(!adminserv::is_svsop($user, adminserv::S_ROOT() )) {
318 notice($user, 'You do not have sufficient rank for this command');
319 return;
320 }
321 ircd::ircsend($1);
322 }
323
324 elsif($msg =~ /^kill (\S*) (.*)/i) {
325 ircd::irckill($sbnick, $1, $2);
326 }
327
328 elsif($msg =~ /^conf/i) {
329 notice($user, "Configuration:", list_conf);
330 }
331
332 elsif($msg =~ /^set (\S+) (.*)/i) {
333 if(!adminserv::is_svsop($user, adminserv::S_ROOT() )) {
334 notice($user, 'You do not have sufficient rank for this command');
335 return;
336 }
337
338 my @p = ($1, $2);
339 chomp $p[1];
340
341 if(update_conf($p[0], $p[1])) {
342 notice($user, "Configuration: ".$p[0]." = ".$p[1]);
343 } else {
344 notice($user, "That value is read-only.");
345 }
346 }
347
348 elsif($msg =~ /^save/i) {
349 notice($user, "Saving configuration.");
350
351 saveconf();
352 }
353
354 elsif($msg =~ /^rehash/i) {
355 notice($user, "Loading configuration.");
356
357 loadconf(1);
358 }
359
360 elsif($msg =~ /^tssync/i) {
361 ircd::tssync();
362 }
363
364 elsif($msg =~ /^svsnick (\S+) (\S+)/i) {
365 if(!adminserv::is_svsop($user, adminserv::S_ROOT() )) {
366 notice($user, 'You do not have sufficient rank for this command');
367 return;
368 }
369 ircd::svsnick($sbnick, $1, $2);
370 }
371
372 elsif($msg =~ /^tor-update/i) {
373 notice($user, "Updating Tor server list.");
374 update_tor_list();
375 }
376=cut
377 elsif($msg =~ /^ss-update/i) {
378 notice($user, "Updating SS definitions.");
379 securitybot::ss2tkl::update_ss();
380 }
381=cut
382 elsif($msg =~ /^tkl/i) {
383 sb_tkl($user, $msg);
384 }
385}
386
387sub list_conf() {
388 my @k = keys(%conf);
389 my @v = values(%conf);
390 my @reply;
391
392 for(my $i=0; $i<@k; $i++) {
393 push @reply, $k[$i]." = ".$v[$i];
394 }
395 return @reply;
396}
397
398sub noticehandle {
399 my ($rnick, $dst, $msg) = @_;
400
401 if($msg =~ /^\x01(\S+)\s?(.*?)\x01?$/) {
402 diagmsg( "Got $1 reply from $rnick: $2");
403 }
404}
405
406sub sb_tkl($$) {
407# This function is a hack to fit better our normal services coding style.
408# Better fix is to rewrite msghandle in another cleanup patch.
409 my ($user, $msg) = @_;
410 # We discard first token 'tkl'
411 my $cmd;
412 (undef, $cmd, $msg) = split(/ /, $msg, 3);
413 if(lc($cmd) eq 'list') {
414 if($msg) {
415 sb_tkl_glob($user, $msg);
416 }
417 else {
418 sb_tkl_list($user);
419 }
420 }
421 elsif(lc($cmd) eq 'del') {
422 unless($msg) {
423 notice($user, "You have to specify at least one parameter");
424 }
425 sb_tkl_glob_delete($user, $msg);
426 }
427}
428
429sub sb_tkl_list($) {
430 my ($user) = @_;
431 my @reply;
432 $get_all_tklban->execute();
433 while(my ($type, $ident, $host, $setter, $expire, $time, $reason) = $get_all_tklban->fetchrow_array()) {
434 if($type eq 'Q') {
435 #push @reply, "$type $host $setter";
436 next;
437 }
438 else {
439 push @reply, "$type $ident\@$host $setter";
440 }
441 $time = gmtime2($time); $expire = time_rel($expire - time()) if $expire;
442 push @reply, " set: $time; ".($expire ? "expires in: $expire" : "Will not expire");
443 push @reply, " reason: $reason";
444 }
445 $get_all_tklban->finish();
446 push @reply, "No results" unless @reply;
447
448 notice($user, @reply);
449}
450
451sub sb_tkl_glob($$) {
452 my ($user, $cmdline) = @_;
453
454 my $sql_expr = "SELECT type, ident, host, setter, expire, time, reason FROM tklban ";
455
456 my ($filters, $parms) = split(/ /, $cmdline, 2);
457 my @filters = split(//, $filters);
458 unless($filters[0] eq '+' or $filters[0] eq '-') {
459 notice($user, "Invalid Syntax: First parameter must be a set of filters preceded by a + or -");
460 return;
461 }
462 my @args = misc::parse_quoted($parms);
463
464 my ($success, $expr) = make_tkl_query(\@filters, \@args);
465 unless ($success) {
466 notice($user, "Error: $expr");
467 return;
468 }
469 $sql_expr .= $expr;
470
471 my @reply;
472 my $get_glob_tklban = $dbh->prepare($sql_expr);
473 $get_glob_tklban->execute();
474 while(my ($type, $ident, $host, $setter, $expire, $time, $reason) = $get_glob_tklban->fetchrow_array()) {
475 if($type eq 'Q') {
476 #push @reply, "$type $host $setter";
477 next;
478 }
479 else {
480 push @reply, "$type $ident\@$host $setter";
481 }
482 $time = gmtime2($time); $expire = time_rel($expire - time()) if $expire;
483 push @reply, " set: $time; ".($expire ? "expires in: $expire" : "Will not expire");
484 push @reply, " reason: $reason";
485 }
486 $get_glob_tklban->finish();
487
488 push @reply, "No results" unless @reply;
489 notice($user, @reply);
490}
491
492sub sb_tkl_glob_delete($$) {
493 my ($user, $cmdline) = @_;
494
495 my $sql_expr = "SELECT type, ident, host FROM tklban ";
496
497 my ($filters, $parms) = split(/ /, $cmdline, 2);
498 my @filters = split(//, $filters);
499 unless($filters[0] eq '+' or $filters[0] eq '-') {
500 notice($user, "Invalid Syntax: First parameter must be a set of filters preceded by a + or -");
501 return;
502 }
503 my @args = misc::parse_quoted($parms);
504
505 my ($success, $expr) = make_tkl_query(\@filters, \@args);
506 unless ($success) {
507 notice($user, "Error: $expr");
508 return;
509 }
510
511 $sql_expr .= $expr;
512
513 my $src = get_user_nick($user);
514 my $get_glob_tklban = $dbh->prepare($sql_expr);
515 $get_glob_tklban->execute();
516 while(my ($type, $ident, $host) = $get_glob_tklban->fetchrow_array()) {
517 if($type eq 'G') {
518 ircd::unkline($src, $ident, $host);
519 }
520 elsif($type eq 'Z') {
521 ircd::unzline($src, $host);
522 }
523 }
524 $get_glob_tklban->finish();
525
526}
527
528sub make_tkl_query($$) {
529 my ($parm1, $parm2) = @_;
530 my @filters = @$parm1; my @args = @$parm2;
531
532 my ($sign, $sql_expr, $sortby, $where, $and);
533 while(my $filter = shift @filters) {
534 my $condition;
535 if ($filter eq '+') {
536 $sign = +1;
537 next;
538 }
539 elsif($filter eq '-') {
540 $sign = 0;
541 next;
542 }
543
544 my $parm = shift @args;
545 unless (defined($parm)) {
546 return (0, "Not enough arguments for filters.");
547 }
548 if($filter eq 'm') {
549 my ($mident, $mhost) = parse_hostmask($parm);
550 $mident = glob2sql($dbh->quote($mident)) if $mident;
551 $mhost = glob2sql($dbh->quote($mhost)) if $mhost;
552
553 $condition = ($mident ? ($sign ? '' : '!').
554 "(ident LIKE $mident) " : '').
555 ($mhost ? ($sign ? '' : '!').
556 "(host LIKE $mhost) " : '');
557 }
558 elsif($filter eq 'r') {
559 my $reason = $dbh->quote($parm);
560 $reason = glob2sql($reason);
561 $condition = ($sign ? '' : '!')."(reason LIKE $reason) ";
562
563 }
564 elsif($filter eq 's') {
565 my $setter = $dbh->quote($parm);
566 $setter = glob2sql($setter);
567 $condition = ($sign ? '' : '!')."(setter LIKE $setter) ";
568
569 }
570 if($filter eq 'M') {
571 my ($mident, $mhost) = parse_hostmask($parm);
572 $mident = $dbh->quote($mident) if $mident;
573 $mhost = $dbh->quote($mhost) if $mhost;
574 $condition = ($mident ? ($sign ? '' : '!').
575 "(ident REGEXP $mident) " : '').
576 ($mhost ? ($sign ? '' : '!').
577 "(host REGEXP $mhost) " : '');
578 }
579 elsif($filter eq 'R') {
580 my $reason = $dbh->quote($parm);
581 $condition = ($sign ? '' : '!')."(reason REGEXP $reason) ";
582
583 }
584 elsif($filter eq 'S') {
585 my $setter = $dbh->quote($parm);
586 $condition = ($sign ? '' : '!')."(setter REGEXP $setter) ";
587
588 }
589 elsif(lc $filter eq 'o') {
590 $parm = lc $parm;
591 next unless ($parm =~ /(type|ident|host|setter|expire|reason|time)/);
592 if ($sortby) {
593 $sortby .= ', ';
594 } else {
595 $sortby = 'ORDER BY ';
596 }
597 $sortby .= $parm.($sign ? ' ASC' : ' DESC');
598 next;
599 }
600 if (!$where) {
601 $sql_expr .= 'WHERE ';
602 $where = 1;
603 }
604 if ($and) {
605 $sql_expr .= 'AND ';
606 } else {
607 $and = 1;
608 }
609 $sql_expr .= $condition if $condition;
610 }
611 if (scalar(@args)) {
612 return (0, "Too many arguments for filters.");
613 }
614 return (1, $sql_expr.((defined $sortby and $sortby ne '') ? $sortby : 'ORDER BY type, time, host'));
615}
616
617sub get_tkl_type_name($) {
618 my %tkltype = (
619 G => 'G:line',
620 Z => 'GZ:line',
621 s => 'Shun',
622 Q => 'Q:line',
623 );
624 return $tkltype{$_[0]};
625};
626
627sub get_filter_action_name($) {
628 my %filteraction = (
629 Z => 'GZ:line',
630 S => 'tempshun',
631 s => 'shun',
632 g => 'G:line',
633 z => 'Z:line',
634 k => 'K:line',
635 K => 'Kill',
636 b => 'Block',
637 d => 'DCC Block',
638 v => 'Virus Chan',
639 w => 'Warn',
640 #t => 'Test', # Should never show up, and not implemented in 3.2.4 yet.
641 );
642 return $filteraction{$_[0]};
643};
644
645sub handle_tkl($$@) {
646 my ($type, $sign, @parms) = @_;
647 return unless defined ($dbh);
648 if ($type eq 'G' or $type eq 'Z' or $type eq 's' or $type eq 'Q') {
649 if ($sign == +1) {
650 my ($ident, $host, $setter, $expire, $time, $reason) = @parms;
651 $add_tklban->execute($type, $ident, $host, $setter, $expire, $time, $reason);
652 $add_tklban->finish();
653 diagmsg( get_tkl_type_name($type)." added for $ident\@$host ".
654 "from ($setter on ".gmtime2($time).
655 ($expire ? ' to expire at '.gmtime2($expire) : ' does not expire').": $reason)")
656 if initial_synced() and $type ne 'Q';
657 }
658 elsif($sign == -1) {
659 my ($ident, $host, $setter) = @parms;
660
661 if ($type ne 'Q' and initial_synced()) {
662 $get_tklban->execute($type, $ident, $host);
663 my (undef, $expire, $time, $reason) = $get_tklban->fetchrow_array;
664 $get_tklban->finish();
665
666 diagmsg( "$setter removed ".get_tkl_type_name($type)." $ident\@$host ".
667 "set at ".gmtime2($time)." - reason: $reason");
668 }
669
670 $del_tklban->execute($type, $ident, $host);
671 $del_tklban->finish();
672 }
673 }
674 elsif($type eq 'F') {
675 if($sign == +1) {
676 my ($target, $action, $setter, $expire, $time, $bantime, $reason, $mask) = @parms;
677 $add_spamfilter->execute($target, $action, $setter, $expire, $time, $bantime, $reason, $mask);
678 $add_spamfilter->finish();
679 diagmsg( "Spamfilter added: '$mask' [target: $target] [action: ".
680 get_filter_action_name($action)."] [reason: $reason] on ".gmtime2($time)."from ($setter)")
681 if initial_synced();
682 }
683 elsif($sign == -1) {
684 # TKL - F u Z tabris!northman@tabris.netadmin.SCnet.ops 0 0 :do_not!use@mask
685 my ($target, $action, $setter, $mask) = @parms;
686 if(initial_synced()) {
687 $get_spamfilter->execute($target, $action, $mask);
688 my ($time, $reason) = $get_spamfilter->fetchrow_array;
689 $get_spamfilter->finish();
690 $reason =~ tr/_/ /;
691 diagmsg( "$setter removed Spamfilter (action: ".get_filter_action_name($action).
692 ", targets: $target) (reason: $reason) '$mask' set at: ".gmtime2($time));
693 }
694 $del_spamfilter->execute($target, $action, $mask);
695 $del_spamfilter->finish();
696 }
697 }
698}
699
700sub saveconf() {
701 writeHash(\%conf, "config/securitybot/sb.conf");
702}
703
704sub loadconf($) {
705 my ($update) = @_;
706
707 %conf = readHash("config/securitybot/sb.conf");
708}
709
710sub update_conf($$) {
711 my ($k, $v) = @_;
712
713 return 0 if($k eq 'EnableTor');
714
715 $conf{$k} = $v;
716 return 1;
717}
718
719sub expire_tkl() {
720 $get_expired_tklban->execute();
721 while (my ($type, $ident, $host, $setter, $expire, $time, $reason) = $get_expired_tklban->fetchrow_array()) {
722 if ($type eq 'G' or $type eq 'Z' or $type eq 's') {
723 diagmsg( "Expiring ".get_tkl_type_name($type)." $ident\@$host ".
724 "set by $setter at ".gmtime2($time)." - reason: $reason");
725 #$del_tklban->execute($type, $ident, $host);
726 #$del_tklban->finish();
727 }
728 }
729 $get_expired_tklban->finish();
730
731 $del_expired_tklban->execute();
732 $del_expired_tklban->finish();
733}
734
735sub expire_tkl_timed {
736 my ($time) = @_;
737 $time = 10 unless $time;
738
739 add_timer('10', $time, __PACKAGE__, "securitybot::expire_tkl_timed");
740
741 expire_tkl();
742}
743
744sub diagmsg(@) {
745 ircd::privmsg($sbnick, main_conf_diag, @_);
746 write_log('diag', '<'.main_conf_local.'>', @_);
747}
748
749sub end { }
750sub unload { saveconf(); }
751
7521;