]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/xline.cpp
Making sure this is compatible with GCC3.4/4.x
[user/henk/code/inspircd.git] / src / xline.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  Inspire is copyright (C) 2002-2004 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 #include "inspircd.h"
18 #include "inspircd_io.h"
19 #include "inspircd_util.h"
20 #include "inspircd_config.h"
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <sys/errno.h>
24 #include <sys/ioctl.h>
25 #include <sys/utsname.h>
26 #include <cstdio>
27 #include <time.h>
28 #include <string>
29 #ifdef GCC3
30 #include <ext/hash_map>
31 #else
32 #include <hash_map>
33 #endif
34 #include <map>
35 #include <sstream>
36 #include <vector>
37 #include <errno.h>
38 #include <deque>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <sched.h>
42 #include "connection.h"
43 #include "users.h"
44 #include "servers.h"
45 #include "ctables.h"
46 #include "globals.h"
47 #include "modules.h"
48 #include "dynamic.h"
49 #include "wildcard.h"
50 #include "message.h"
51 #include "commands.h"
52 #include "xline.h"
53 #include "inspstring.h"
54 #include "helperfuncs.h"
55 #include "hashcomp.h"
56
57 using namespace std;
58
59 extern int MODCOUNT;
60 extern std::vector<Module*> modules;
61 extern std::vector<ircd_module*> factory;
62
63 extern int LogLevel;
64 extern char ServerName[MAXBUF];
65 extern char Network[MAXBUF];
66 extern char ServerDesc[MAXBUF];
67 extern char AdminName[MAXBUF];
68 extern char AdminEmail[MAXBUF];
69 extern char AdminNick[MAXBUF];
70 extern char diepass[MAXBUF];
71 extern char restartpass[MAXBUF];
72 extern char motd[MAXBUF];
73 extern char rules[MAXBUF];
74 extern char list[MAXBUF];
75 extern char PrefixQuit[MAXBUF];
76 extern char DieValue[MAXBUF];
77
78 extern int debugging;
79 extern int WHOWAS_STALE;
80 extern int WHOWAS_MAX;
81 extern int DieDelay;
82 extern time_t startup_time;
83 extern int NetBufferSize;
84 extern time_t nb_start;
85
86 extern std::vector<int> fd_reap;
87 extern std::vector<std::string> module_names;
88
89 extern int boundPortCount;
90 extern int portCount;
91 extern int SERVERportCount;
92 extern int ports[MAXSOCKS];
93 extern int defaultRoute;
94
95 extern std::vector<long> auth_cookies;
96 extern std::stringstream config_f;
97
98 extern serverrec* me[32];
99
100 extern FILE *log_file;
101
102 typedef nspace::hash_map<std::string, userrec*, nspace::hash<string>, StrHashComp> user_hash;
103 typedef nspace::hash_map<std::string, chanrec*, nspace::hash<string>, StrHashComp> chan_hash;
104 typedef nspace::hash_map<in_addr,string*, nspace::hash<in_addr>, InAddr_HashComp> address_cache;
105 typedef nspace::hash_map<std::string, WhoWasUser*, nspace::hash<string>, StrHashComp> whowas_hash;
106 typedef std::deque<command_t> command_table;
107
108
109 extern user_hash clientlist;
110 extern chan_hash chanlist;
111 extern whowas_hash whowas;
112 extern command_table cmdlist;
113 extern file_cache MOTD;
114 extern file_cache RULES;
115 extern address_cache IP;
116
117 extern time_t TIME;
118
119 std::vector<KLine> klines;
120 std::vector<GLine> glines;
121 std::vector<ZLine> zlines;
122 std::vector<QLine> qlines;
123 std::vector<ELine> elines;
124
125 // Reads the default bans from the config file.
126 // only a very small number of bans are defined
127 // this way these days, such as qlines against 
128 // services nicks, etc.
129
130 void read_xline_defaults()
131 {
132         char ipmask[MAXBUF];
133         char nick[MAXBUF];
134         char host[MAXBUF];
135         char reason[MAXBUF];
136
137         for (int i = 0; i < ConfValueEnum("badip",&config_f); i++)
138         {
139                 ConfValue("badip","ipmask",i,ipmask,&config_f);
140                 ConfValue("badip","reason",i,reason,&config_f);
141                 add_zline(0,"<Config>",reason,ipmask);
142                 log(DEBUG,"Read Z line (badip tag): ipmask=%s reason=%s",ipmask,reason);
143         }
144         
145         for (int i = 0; i < ConfValueEnum("badnick",&config_f); i++)
146         {
147                 ConfValue("badnick","nick",i,nick,&config_f);
148                 ConfValue("badnick","reason",i,reason,&config_f);
149                 add_qline(0,"<Config>",reason,nick);
150                 log(DEBUG,"Read Q line (badnick tag): nick=%s reason=%s",nick,reason);
151         }
152         
153         for (int i = 0; i < ConfValueEnum("badhost",&config_f); i++)
154         {
155                 ConfValue("badhost","host",i,host,&config_f);
156                 ConfValue("badhost","reason",i,reason,&config_f);
157                 add_kline(0,"<Config>",reason,host);
158                 log(DEBUG,"Read K line (badhost tag): host=%s reason=%s",host,reason);
159         }
160         for (int i = 0; i < ConfValueEnum("exception",&config_f); i++)
161         {
162                 ConfValue("exception","host",i,host,&config_f);
163                 ConfValue("exception","reason",i,reason,&config_f);
164                 add_eline(0,"<Config>",reason,host);
165                 log(DEBUG,"Read E line (exception tag): host=%s reason=%s",host,reason);
166         }
167 }
168
169 // adds a g:line
170
171 void add_gline(long duration, const char* source,const char* reason,const char* hostmask)
172 {
173         del_gline(hostmask);
174         GLine item;
175         item.duration = duration;
176         strlcpy(item.hostmask,hostmask,199);
177         strlcpy(item.reason,reason,MAXBUF);
178         strlcpy(item.source,source,255);
179         item.n_matches = 0;
180         item.set_time = TIME;
181         glines.push_back(item);
182 }
183
184 // adds an e:line (exception to bans)
185
186 void add_eline(long duration, const char* source, const char* reason, const char* hostmask)
187 {
188         del_eline(hostmask);
189         ELine item;
190         item.duration = duration;
191         strlcpy(item.hostmask,hostmask,199);
192         strlcpy(item.reason,reason,MAXBUF);
193         strlcpy(item.source,source,255);
194         item.n_matches = 0;
195         item.set_time = TIME;
196         elines.push_back(item);
197 }
198
199 // adds a q:line
200
201 void add_qline(long duration, const char* source, const char* reason, const char* nickname)
202 {
203         del_qline(nickname);
204         QLine item;
205         item.duration = duration;
206         strlcpy(item.nick,nickname,63);
207         strlcpy(item.reason,reason,MAXBUF);
208         strlcpy(item.source,source,255);
209         item.n_matches = 0;
210         item.is_global = false;
211         item.set_time = TIME;
212         qlines.push_back(item);
213 }
214
215 // adds a z:line
216
217 void add_zline(long duration, const char* source, const char* reason, const char* ipaddr)
218 {
219         del_zline(ipaddr);
220         ZLine item;
221         item.duration = duration;
222         if (strchr(ipaddr,'@'))
223         {
224                 while (*ipaddr != '@')
225                         ipaddr++;
226                 ipaddr++;
227         }
228         strlcpy(item.ipaddr,ipaddr,39);
229         strlcpy(item.reason,reason,MAXBUF);
230         strlcpy(item.source,source,255);
231         item.n_matches = 0;
232         item.is_global = false;
233         item.set_time = TIME;
234         zlines.push_back(item);
235 }
236
237 // adds a k:line
238
239 void add_kline(long duration, const char* source, const char* reason, const char* hostmask)
240 {
241         del_kline(hostmask);
242         KLine item;
243         item.duration = duration;
244         strlcpy(item.hostmask,hostmask,200);
245         strlcpy(item.reason,reason,MAXBUF);
246         strlcpy(item.source,source,255);
247         item.n_matches = 0;
248         item.set_time = TIME;
249         klines.push_back(item);
250 }
251
252 // deletes a g:line, returns true if the line existed and was removed
253
254 bool del_gline(const char* hostmask)
255 {
256         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
257         {
258                 if (!strcasecmp(hostmask,i->hostmask))
259                 {
260                         glines.erase(i);
261                         return true;
262                 }
263         }
264         return false;
265 }
266
267 // deletes a e:line, returns true if the line existed and was removed
268
269 bool del_eline(const char* hostmask)
270 {
271         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
272         {
273                 if (!strcasecmp(hostmask,i->hostmask))
274                 {
275                         elines.erase(i);
276                         return true;
277                 }
278         }
279         return false;
280 }
281
282 // deletes a q:line, returns true if the line existed and was removed
283
284 bool del_qline(const char* nickname)
285 {
286         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
287         {
288                 if (!strcasecmp(nickname,i->nick))
289                 {
290                         qlines.erase(i);
291                         return true;
292                 }
293         }
294         return false;
295 }
296
297 bool qline_make_global(const char* nickname)
298 {
299         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
300         {
301                 if (!strcasecmp(nickname,i->nick))
302                 {
303                         i->is_global = true;
304                         return true;
305                 }
306         }
307         return false;
308 }
309
310 bool zline_make_global(const char* ipaddr)
311 {
312         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
313         {
314                 if (!strcasecmp(ipaddr,i->ipaddr))
315                 {
316                         i->is_global = true;
317                         return true;
318                 }
319         }
320         return false;
321 }
322
323 void sync_xlines(serverrec* serv, char* tcp_host)
324 {
325         char data[MAXBUF];
326         
327         // for zlines and qlines, we should first check if theyre global...
328         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
329         {
330                 if (i->is_global)
331                 {
332                         snprintf(data,MAXBUF,"%s } %s %s %lu %lu :%s",CreateSum().c_str(),i->ipaddr,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
333                         serv->SendPacket(data,tcp_host);
334                 }
335         }
336         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
337         {
338                 if (i->is_global)
339                 {
340                         snprintf(data,MAXBUF,"%s { %s %s %lu %lu :%s",CreateSum().c_str(),i->nick,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
341                         serv->SendPacket(data,tcp_host);
342                 }
343         }
344         // glines are always global, so no need to check
345         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
346         {
347                 snprintf(data,MAXBUF,"%s # %s %s %lu %lu :%s",CreateSum().c_str(),i->hostmask,i->source,(unsigned long)i->set_time,(unsigned long)i->duration,i->reason);
348                 serv->SendPacket(data,tcp_host);
349         }
350 }
351
352
353 // deletes a z:line, returns true if the line existed and was removed
354
355 bool del_zline(const char* ipaddr)
356 {
357         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
358         {
359                 if (!strcasecmp(ipaddr,i->ipaddr))
360                 {
361                         zlines.erase(i);
362                         return true;
363                 }
364         }
365         return false;
366 }
367
368 // deletes a k:line, returns true if the line existed and was removed
369
370 bool del_kline(const char* hostmask)
371 {
372         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
373         {
374                 if (!strcasecmp(hostmask,i->hostmask))
375                 {
376                         klines.erase(i);
377                         return true;
378                 }
379         }
380         return false;
381 }
382
383 // returns a pointer to the reason if a nickname matches a qline, NULL if it didnt match
384
385 char* matches_qline(const char* nick)
386 {
387         if (qlines.empty())
388                 return NULL;
389         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
390         {
391                 if (match(nick,i->nick))
392                 {
393                         return i->reason;
394                 }
395         }
396         return NULL;
397 }
398
399 // returns a pointer to the reason if a host matches a gline, NULL if it didnt match
400
401 char* matches_gline(const char* host)
402 {
403         if (glines.empty())
404                 return NULL;
405         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
406         {
407                 if (match(host,i->hostmask))
408                 {
409                         return i->reason;
410                 }
411         }
412         return NULL;
413 }
414
415 char* matches_exception(const char* host)
416 {
417         if (elines.empty())
418                 return NULL;
419         char host2[MAXBUF];
420         snprintf(host2,MAXBUF,"*@%s",host);
421         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
422         {
423                 if ((match(host,i->hostmask)) || (match(host2,i->hostmask)))
424                 {
425                         return i->reason;
426                 }
427         }
428         return NULL;
429 }
430
431
432 void gline_set_creation_time(char* host, time_t create_time)
433 {
434         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
435         {
436                 if (!strcasecmp(host,i->hostmask))
437                 {
438                         i->set_time = create_time;
439                         return;
440                 }
441         }
442         return ;        
443 }
444
445 void qline_set_creation_time(char* nick, time_t create_time)
446 {
447         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
448         {
449                 if (!strcasecmp(nick,i->nick))
450                 {
451                         i->set_time = create_time;
452                         return;
453                 }
454         }
455         return ;        
456 }
457
458 void zline_set_creation_time(char* ip, time_t create_time)
459 {
460         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
461         {
462                 if (!strcasecmp(ip,i->ipaddr))
463                 {
464                         i->set_time = create_time;
465                         return;
466                 }
467         }
468         return ;        
469 }
470
471 // returns a pointer to the reason if an ip address matches a zline, NULL if it didnt match
472
473 char* matches_zline(const char* ipaddr)
474 {
475         if (zlines.empty())
476                 return NULL;
477         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
478         {
479                 if (match(ipaddr,i->ipaddr))
480                 {
481                         return i->reason;
482                 }
483         }
484         return NULL;
485 }
486
487 // returns a pointer to the reason if a host matches a kline, NULL if it didnt match
488
489 char* matches_kline(const char* host)
490 {
491         if (klines.empty())
492                 return NULL;
493         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
494         {
495                 if (match(host,i->hostmask))
496                 {
497                         return i->reason;
498                 }
499         }
500         return NULL;
501 }
502
503 // removes lines that have expired
504
505 void expire_lines()
506 {
507         bool go_again = true;
508         time_t current = TIME;
509         
510         // because we mess up an iterator when we remove from the vector, we must bail from
511         // the loop early if we delete an item, therefore this outer while loop is required.
512         while (go_again)
513         {
514                 go_again = false;
515
516                 for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
517                 {
518                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
519                         {
520                                 WriteOpers("Expiring timed K-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
521                                 klines.erase(i);
522                                 go_again = true;
523                                 break;
524                         }
525                 }
526
527                 for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
528                 {
529                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
530                         {
531                                 WriteOpers("Expiring timed E-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
532                                 elines.erase(i);
533                                 go_again = true;
534                                 break;
535                         }
536                 }
537
538                 for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
539                 {
540                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
541                         {
542                                 WriteOpers("Expiring timed G-Line %s (set by %s %d seconds ago)",i->hostmask,i->source,i->duration);
543                                 glines.erase(i);
544                                 go_again = true;
545                                 break;
546                         }
547                 }
548
549                 for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
550                 {
551                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
552                         {
553                                 WriteOpers("Expiring timed Z-Line %s (set by %s %d seconds ago)",i->ipaddr,i->source,i->duration);
554                                 zlines.erase(i);
555                                 go_again = true;
556                                 break;
557                         }
558                 }
559
560                 for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
561                 {
562                         if ((current > (i->duration + i->set_time)) && (i->duration > 0))
563                         {
564                                 WriteOpers("Expiring timed Q-Line %s (set by %s %d seconds ago)",i->nick,i->source,i->duration);
565                                 qlines.erase(i);
566                                 go_again = true;
567                                 break;
568                         }
569                 }
570         }
571 }
572
573 // applies lines, removing clients and changing nicks etc as applicable
574
575 void apply_lines()
576 {
577         bool go_again = true;
578         char reason[MAXBUF];
579         char host[MAXBUF];
580         
581         if ((!glines.size()) && (!klines.size()) && (!zlines.size()) && (!qlines.size()))
582                 return;
583         
584         while (go_again)
585         {
586                 go_again = false;
587                 for (user_hash::const_iterator u = clientlist.begin(); u != clientlist.end(); u++)
588                 {
589                         if (!strcasecmp(u->second->server,ServerName))
590                         {
591                                 snprintf(host,MAXBUF,"%s@%s",u->second->ident,u->second->host);
592                                 if (elines.size())
593                                 {
594                                         // ignore people matching exempts
595                                         if (matches_exception(host))
596                                                 continue;
597                                 }
598                                 if (glines.size())
599                                 {
600                                         char* check = matches_gline(host);
601                                         if (check)
602                                         {
603                                                 WriteOpers("*** User %s matches G-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
604                                                 snprintf(reason,MAXBUF,"G-Lined: %s",check);
605                                                 kill_link(u->second,reason);
606                                                 go_again = true;
607                                                 break;
608                                         }
609                                 }
610                                 if (klines.size())
611                                 {
612                                         char* check = matches_kline(host);
613                                         if (check)
614                                         {
615                                                 WriteOpers("*** User %s matches K-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",check);
616                                                 snprintf(reason,MAXBUF,"K-Lined: %s",check);
617                                                 kill_link(u->second,reason);
618                                                 go_again = true;
619                                                 break;
620                                         }
621                                 }
622                                 if (qlines.size())
623                                 {
624                                         char* check = matches_qline(u->second->nick);
625                                         if (check)
626                                         {
627                                                 snprintf(reason,MAXBUF,"Matched Q-Lined nick: %s",check);
628                                                 WriteOpers("*** Q-Lined nickname %s from %s: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
629                                                 kill_link(u->second,reason);
630                                                 go_again = true;
631                                                 break;
632                                         }
633                                 }
634                                 if (zlines.size())
635                                 {
636                                         char* check = matches_zline(u->second->ip);
637                                         if (check)
638                                         {
639                                                 snprintf(reason,MAXBUF,"Z-Lined: %s",check);
640                                                 WriteOpers("*** User %s matches Z-Line: %s",u->second->registered == 7 ? u->second->nick:"<unknown>",u->second->host,check);
641                                                 kill_link(u->second,reason);
642                                                 go_again = true;
643                                                 break;
644                                         }
645                                 }
646                         }
647                 }
648         }
649 }
650
651 void stats_k(userrec* user)
652 {
653         for (std::vector<KLine>::iterator i = klines.begin(); i != klines.end(); i++)
654         {
655                 WriteServ(user->fd,"216 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
656         }
657 }
658
659 void stats_g(userrec* user)
660 {
661         for (std::vector<GLine>::iterator i = glines.begin(); i != glines.end(); i++)
662         {
663                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
664         }
665 }
666
667 void stats_q(userrec* user)
668 {
669         for (std::vector<QLine>::iterator i = qlines.begin(); i != qlines.end(); i++)
670         {
671                 WriteServ(user->fd,"217 %s :%s %d %d %s %s",user->nick,i->nick,i->set_time,i->duration,i->source,i->reason);
672         }
673 }
674
675 void stats_z(userrec* user)
676 {
677         for (std::vector<ZLine>::iterator i = zlines.begin(); i != zlines.end(); i++)
678         {
679                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->ipaddr,i->set_time,i->duration,i->source,i->reason);
680         }
681 }
682
683 void stats_e(userrec* user)
684 {
685         for (std::vector<ELine>::iterator i = elines.begin(); i != elines.end(); i++)
686         {
687                 WriteServ(user->fd,"223 %s :%s %d %d %s %s",user->nick,i->hostmask,i->set_time,i->duration,i->source,i->reason);
688         }
689 }