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