Restore stats_spy hook that was removed in commit 401f2454671ca233e35b0e6e4f3fa4c43cd...
[seven-1.x.git] / src / s_newconf.c
bloba65dfaacadc14ed4d6cc75787345a85d2088c0fa
1 /*
2 * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
3 * s_newconf.c - code for dealing with conf stuff
5 * Copyright (C) 2004 Lee Hardy <lee@leeh.co.uk>
6 * Copyright (C) 2004-2005 ircd-ratbox development team
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
12 * 1.Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * 2.Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3.The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include "stdinc.h"
34 #include "ircd_defs.h"
35 #include "common.h"
36 #include "s_conf.h"
37 #include "s_newconf.h"
38 #include "tools.h"
39 #include "client.h"
40 #include "memory.h"
41 #include "s_serv.h"
42 #include "send.h"
43 #include "hostmask.h"
44 #include "newconf.h"
45 #include "hash.h"
46 #include "balloc.h"
47 #include "event.h"
48 #include "sprintf_irc.h"
50 dlink_list shared_conf_list;
51 dlink_list cluster_conf_list;
52 dlink_list oper_conf_list;
53 dlink_list hubleaf_conf_list;
54 dlink_list server_conf_list;
55 dlink_list xline_conf_list;
56 dlink_list resv_conf_list; /* nicks only! */
57 dlink_list nd_list; /* nick delay */
58 dlink_list tgchange_list;
60 patricia_tree_t *tgchange_tree;
62 static BlockHeap *nd_heap = NULL;
64 static void expire_temp_rxlines(void *unused);
65 static void expire_nd_entries(void *unused);
67 void
68 init_s_newconf(void)
70 tgchange_tree = New_Patricia(PATRICIA_BITS);
71 nd_heap = BlockHeapCreate(sizeof(struct nd_entry), ND_HEAP_SIZE);
72 eventAddIsh("expire_nd_entries", expire_nd_entries, NULL, 30);
73 eventAddIsh("expire_temp_rxlines", expire_temp_rxlines, NULL, 60);
76 void
77 clear_s_newconf(void)
79 struct server_conf *server_p;
80 dlink_node *ptr;
81 dlink_node *next_ptr;
83 DLINK_FOREACH_SAFE(ptr, next_ptr, shared_conf_list.head)
85 /* ptr here is ptr->data->node */
86 dlinkDelete(ptr, &shared_conf_list);
87 free_remote_conf(ptr->data);
90 DLINK_FOREACH_SAFE(ptr, next_ptr, cluster_conf_list.head)
92 dlinkDelete(ptr, &cluster_conf_list);
93 free_remote_conf(ptr->data);
96 DLINK_FOREACH_SAFE(ptr, next_ptr, hubleaf_conf_list.head)
98 dlinkDelete(ptr, &hubleaf_conf_list);
99 free_remote_conf(ptr->data);
102 DLINK_FOREACH_SAFE(ptr, next_ptr, oper_conf_list.head)
104 free_oper_conf(ptr->data);
105 dlinkDestroy(ptr, &oper_conf_list);
108 DLINK_FOREACH_SAFE(ptr, next_ptr, server_conf_list.head)
110 server_p = ptr->data;
112 if(!server_p->servers)
114 dlinkDelete(ptr, &server_conf_list);
115 free_server_conf(ptr->data);
117 else
118 server_p->flags |= SERVER_ILLEGAL;
122 void
123 clear_s_newconf_bans(void)
125 struct ConfItem *aconf;
126 dlink_node *ptr, *next_ptr;
128 DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
130 aconf = ptr->data;
132 if(aconf->hold)
133 continue;
135 free_conf(aconf);
136 dlinkDestroy(ptr, &xline_conf_list);
139 DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
141 aconf = ptr->data;
143 /* temporary resv */
144 if(aconf->hold)
145 continue;
147 free_conf(aconf);
148 dlinkDestroy(ptr, &resv_conf_list);
151 clear_resv_hash();
154 struct remote_conf *
155 make_remote_conf(void)
157 struct remote_conf *remote_p = MyMalloc(sizeof(struct remote_conf));
158 return remote_p;
161 void
162 free_remote_conf(struct remote_conf *remote_p)
164 s_assert(remote_p != NULL);
165 if(remote_p == NULL)
166 return;
168 MyFree(remote_p->username);
169 MyFree(remote_p->host);
170 MyFree(remote_p->server);
171 MyFree(remote_p);
175 find_shared_conf(const char *username, const char *host,
176 const char *server, int flags)
178 struct remote_conf *shared_p;
179 dlink_node *ptr;
181 DLINK_FOREACH(ptr, shared_conf_list.head)
183 shared_p = ptr->data;
185 if(match(shared_p->username, username) &&
186 match(shared_p->host, host) &&
187 match(shared_p->server, server))
189 if(shared_p->flags & flags)
190 return YES;
191 else
192 return NO;
196 return NO;
199 void
200 propagate_generic(struct Client *source_p, const char *command,
201 const char *target, int cap, const char *format, ...)
203 char buffer[BUFSIZE];
204 va_list args;
206 va_start(args, format);
207 ircvsnprintf(buffer, sizeof(buffer), format, args);
208 va_end(args);
210 sendto_match_servs(source_p, target, cap, NOCAPS,
211 "%s %s %s",
212 command, target, buffer);
213 sendto_match_servs(source_p, target, CAP_ENCAP, cap,
214 "ENCAP %s %s %s",
215 target, command, buffer);
218 void
219 cluster_generic(struct Client *source_p, const char *command,
220 int cltype, int cap, const char *format, ...)
222 char buffer[BUFSIZE];
223 struct remote_conf *shared_p;
224 va_list args;
225 dlink_node *ptr;
227 va_start(args, format);
228 ircvsnprintf(buffer, sizeof(buffer), format, args);
229 va_end(args);
231 DLINK_FOREACH(ptr, cluster_conf_list.head)
233 shared_p = ptr->data;
235 if(!(shared_p->flags & cltype))
236 continue;
238 sendto_match_servs(source_p, shared_p->server, cap, NOCAPS,
239 "%s %s %s",
240 command, shared_p->server, buffer);
241 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, cap,
242 "ENCAP %s %s %s",
243 shared_p->server, command, buffer);
247 struct oper_conf *
248 make_oper_conf(void)
250 struct oper_conf *oper_p = MyMalloc(sizeof(struct oper_conf));
251 return oper_p;
254 void
255 free_oper_conf(struct oper_conf *oper_p)
257 s_assert(oper_p != NULL);
258 if(oper_p == NULL)
259 return;
261 MyFree(oper_p->username);
262 MyFree(oper_p->host);
263 MyFree(oper_p->name);
265 if(oper_p->passwd)
267 memset(oper_p->passwd, 0, strlen(oper_p->passwd));
268 MyFree(oper_p->passwd);
271 #ifdef HAVE_LIBCRYPTO
272 MyFree(oper_p->rsa_pubkey_file);
274 if(oper_p->rsa_pubkey)
275 RSA_free(oper_p->rsa_pubkey);
276 #endif
278 MyFree(oper_p);
281 struct oper_conf *
282 find_oper_conf(const char *username, const char *host, const char *locip, const char *name)
284 struct oper_conf *oper_p;
285 struct irc_sockaddr_storage ip, cip;
286 char addr[HOSTLEN+1];
287 int bits, cbits;
288 dlink_node *ptr;
290 parse_netmask(locip, (struct sockaddr *)&cip, &cbits);
292 DLINK_FOREACH(ptr, oper_conf_list.head)
294 oper_p = ptr->data;
296 /* name/username doesnt match.. */
297 if(irccmp(oper_p->name, name) || !match(oper_p->username, username))
298 continue;
300 strlcpy(addr, oper_p->host, sizeof(addr));
302 if(parse_netmask(addr, (struct sockaddr *)&ip, &bits) != HM_HOST)
304 if(ip.ss_family == cip.ss_family &&
305 comp_with_mask_sock((struct sockaddr *)&ip, (struct sockaddr *)&cip, bits))
306 return oper_p;
309 /* we have to compare against the host as well, because its
310 * valid to set a spoof to an IP, which if we only compare
311 * in ip form to sockhost will not necessarily match --anfl
313 if(match(oper_p->host, host))
314 return oper_p;
317 return NULL;
320 struct oper_flags oper_flagtable[] =
322 { OPER_ADMIN, 'A', 'a' },
323 { OPER_REMOTEBAN, 'B', 'b' },
324 { OPER_KILL, 'C', 'c' },
325 { OPER_DIE, 'D', 'd' },
326 { OPER_EXPERIMENTAL, 'E', 'e' },
327 { OPER_STAFFER, 'F', 'f' },
328 { OPER_GRANT, 'G', 'g' },
329 { OPER_REHASH, 'H', 'h' },
330 { OPER_KLINE, 'K', 'k' },
331 { OPER_OPERWALL, 'L', 'l' },
332 { OPER_CMODES, 'M', 'm' },
333 { OPER_MASSNOTICE, 'N', 'n' },
334 { OPER_OVERRIDE, 'O', 'o' },
335 { OPER_RESV, 'Q', 'q' },
336 { OPER_ROUTING, 'R', 'r' },
337 { OPER_AUSPEX, 'S', 's' },
338 { OPER_HELPER, 'T', 't' },
339 { OPER_UNKLINE, 'U', 'u' },
340 { OPER_WALLOPS, 'W', 'w' },
341 { OPER_XLINE, 'X', 'x' },
342 { 0, '\0', '\0' }
345 const char *
346 get_oper_privs(int flags)
348 static char buf[20];
349 char *p;
350 int i;
352 p = buf;
354 for(i = 0; oper_flagtable[i].flag; i++)
356 if(flags & oper_flagtable[i].flag)
357 *p++ = oper_flagtable[i].has;
358 else
359 *p++ = oper_flagtable[i].hasnt;
362 *p = '\0';
364 return buf;
367 struct server_conf *
368 make_server_conf(void)
370 struct server_conf *server_p = MyMalloc(sizeof(struct server_conf));
371 server_p->aftype = AF_INET;
372 return server_p;
375 void
376 free_server_conf(struct server_conf *server_p)
378 s_assert(server_p != NULL);
379 if(server_p == NULL)
380 return;
382 if(!EmptyString(server_p->passwd))
384 memset(server_p->passwd, 0, strlen(server_p->passwd));
385 MyFree(server_p->passwd);
388 if(!EmptyString(server_p->spasswd))
390 memset(server_p->spasswd, 0, strlen(server_p->spasswd));
391 MyFree(server_p->spasswd);
394 MyFree(server_p->name);
395 MyFree(server_p->host);
396 MyFree(server_p->class_name);
397 MyFree(server_p);
400 void
401 add_server_conf(struct server_conf *server_p)
403 if(EmptyString(server_p->class_name))
405 DupString(server_p->class_name, "default");
406 server_p->class = default_class;
407 return;
410 server_p->class = find_class(server_p->class_name);
412 if(server_p->class == default_class)
414 conf_report_error("Warning connect::class invalid for %s",
415 server_p->name);
417 MyFree(server_p->class_name);
418 DupString(server_p->class_name, "default");
421 if(strchr(server_p->host, '*') || strchr(server_p->host, '?'))
422 return;
425 struct server_conf *
426 find_server_conf(const char *name)
428 struct server_conf *server_p;
429 dlink_node *ptr;
431 DLINK_FOREACH(ptr, server_conf_list.head)
433 server_p = ptr->data;
435 if(ServerConfIllegal(server_p))
436 continue;
438 if(match(name, server_p->name))
439 return server_p;
442 return NULL;
445 void
446 attach_server_conf(struct Client *client_p, struct server_conf *server_p)
448 /* already have an attached conf */
449 if(client_p->localClient->att_sconf)
451 /* short circuit this special case :) */
452 if(client_p->localClient->att_sconf == server_p)
453 return;
455 detach_server_conf(client_p);
458 CurrUsers(server_p->class)++;
460 client_p->localClient->att_sconf = server_p;
461 server_p->servers++;
464 void
465 detach_server_conf(struct Client *client_p)
467 struct server_conf *server_p = client_p->localClient->att_sconf;
469 if(server_p == NULL)
470 return;
472 client_p->localClient->att_sconf = NULL;
473 server_p->servers--;
474 CurrUsers(server_p->class)--;
476 if(ServerConfIllegal(server_p) && !server_p->servers)
478 /* the class this one is using may need destroying too */
479 if(MaxUsers(server_p->class) < 0 && CurrUsers(server_p->class) <= 0)
480 free_class(server_p->class);
482 dlinkDelete(&server_p->node, &server_conf_list);
483 free_server_conf(server_p);
487 void
488 set_server_conf_autoconn(struct Client *source_p, char *name, int newval)
490 struct server_conf *server_p;
492 if((server_p = find_server_conf(name)) != NULL)
494 if(newval)
495 server_p->flags |= SERVER_AUTOCONN;
496 else
497 server_p->flags &= ~SERVER_AUTOCONN;
499 sendto_realops_snomask(SNO_GENERAL, L_ALL,
500 "%s has changed AUTOCONN for %s to %i",
501 get_oper_name(source_p), name, newval);
503 else
504 sendto_one(source_p, ":%s NOTICE %s :Can't find %s",
505 me.name, source_p->name, name);
508 struct ConfItem *
509 find_xline(const char *gecos, int counter)
511 struct ConfItem *aconf;
512 dlink_node *ptr;
514 DLINK_FOREACH(ptr, xline_conf_list.head)
516 aconf = ptr->data;
518 if(match_esc(aconf->name, gecos))
520 if(counter)
521 aconf->port++;
522 return aconf;
526 return NULL;
529 struct ConfItem *
530 find_nick_resv(const char *name)
532 struct ConfItem *aconf;
533 dlink_node *ptr;
535 DLINK_FOREACH(ptr, resv_conf_list.head)
537 aconf = ptr->data;
539 if(match_esc(aconf->name, name))
541 aconf->port++;
542 return aconf;
546 return NULL;
549 /* clean_resv_nick()
551 * inputs - nick
552 * outputs - 1 if nick is vaild resv, 0 otherwise
553 * side effects -
556 clean_resv_nick(const char *nick)
558 char tmpch;
559 int as = 0;
560 int q = 0;
561 int ch = 0;
563 if(*nick == '-' || IsDigit(*nick))
564 return 0;
566 while ((tmpch = *nick++))
568 if(tmpch == '?' || tmpch == '@' || tmpch == '#')
569 q++;
570 else if(tmpch == '*')
571 as++;
572 else if(IsNickChar(tmpch))
573 ch++;
574 else
575 return 0;
578 if(!ch && as)
579 return 0;
581 return 1;
584 /* valid_wild_card_simple()
586 * inputs - "thing" to test
587 * outputs - 1 if enough wildcards, else 0
588 * side effects -
591 valid_wild_card_simple(const char *data)
593 const char *p;
594 char tmpch;
595 int nonwild = 0;
597 /* check the string for minimum number of nonwildcard chars */
598 p = data;
600 while((tmpch = *p++))
602 /* found an escape, p points to the char after it, so skip
603 * that and move on.
605 if(tmpch == '\\')
607 p++;
609 else if(!IsMWildChar(tmpch))
611 /* if we have enough nonwildchars, return */
612 if(++nonwild >= ConfigFileEntry.min_nonwildcard_simple)
613 return 1;
617 return 0;
620 time_t
621 valid_temp_time(const char *p)
623 time_t result = 0;
625 while(*p)
627 if(IsDigit(*p))
629 result *= 10;
630 result += ((*p) & 0xF);
631 p++;
633 else
634 return -1;
637 if(result > (60 * 24 * 7 * 52))
638 result = (60 * 24 * 7 * 52);
640 return(result * 60);
643 static void
644 expire_temp_rxlines(void *unused)
646 struct ConfItem *aconf;
647 dlink_node *ptr;
648 dlink_node *next_ptr;
649 int i;
651 HASH_WALK_SAFE(i, R_MAX, ptr, next_ptr, resvTable)
653 aconf = ptr->data;
655 if(aconf->hold && aconf->hold <= CurrentTime)
657 if(ConfigFileEntry.tkline_expire_notices)
658 sendto_realops_snomask(SNO_GENERAL, L_ALL,
659 "Temporary RESV for [%s] expired",
660 aconf->name);
662 free_conf(aconf);
663 dlinkDestroy(ptr, &resvTable[i]);
666 HASH_WALK_END
668 DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
670 aconf = ptr->data;
672 if(aconf->hold && aconf->hold <= CurrentTime)
674 if(ConfigFileEntry.tkline_expire_notices)
675 sendto_realops_snomask(SNO_GENERAL, L_ALL,
676 "Temporary RESV for [%s] expired",
677 aconf->name);
678 free_conf(aconf);
679 dlinkDestroy(ptr, &resv_conf_list);
683 DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
685 aconf = ptr->data;
687 if(aconf->hold && aconf->hold <= CurrentTime)
689 if(ConfigFileEntry.tkline_expire_notices)
690 sendto_realops_snomask(SNO_GENERAL, L_ALL,
691 "Temporary X-line for [%s] expired",
692 aconf->name);
693 free_conf(aconf);
694 dlinkDestroy(ptr, &xline_conf_list);
699 unsigned long
700 get_nd_count(void)
702 return(dlink_list_length(&nd_list));
706 void
707 add_nd_entry(const char *name)
709 struct nd_entry *nd;
711 if(hash_find_nd(name) != NULL)
712 return;
714 nd = BlockHeapAlloc(nd_heap);
716 strlcpy(nd->name, name, sizeof(nd->name));
717 nd->expire = CurrentTime + ConfigFileEntry.nick_delay;
719 /* this list is ordered */
720 dlinkAddTail(nd, &nd->lnode, &nd_list);
721 add_to_nd_hash(name, nd);
724 void
725 free_nd_entry(struct nd_entry *nd)
727 dlinkDelete(&nd->lnode, &nd_list);
728 dlinkDelete(&nd->hnode, &ndTable[nd->hashv]);
729 BlockHeapFree(nd_heap, nd);
732 void
733 expire_nd_entries(void *unused)
735 struct nd_entry *nd;
736 dlink_node *ptr;
737 dlink_node *next_ptr;
739 DLINK_FOREACH_SAFE(ptr, next_ptr, nd_list.head)
741 nd = ptr->data;
743 /* this list is ordered - we can stop when we hit the first
744 * entry that doesnt expire..
746 if(nd->expire > CurrentTime)
747 return;
749 free_nd_entry(nd);
753 void
754 add_tgchange(const char *host)
756 tgchange *target;
757 patricia_node_t *pnode;
759 if(find_tgchange(host))
760 return;
762 target = MyMalloc(sizeof(tgchange));
763 pnode = make_and_lookup(tgchange_tree, host);
765 pnode->data = target;
766 target->pnode = pnode;
768 DupString(target->ip, host);
769 target->expiry = CurrentTime + (60*60*12);
771 dlinkAdd(target, &target->node, &tgchange_list);
774 tgchange *
775 find_tgchange(const char *host)
777 patricia_node_t *pnode;
779 if((pnode = match_exact_string(tgchange_tree, host)))
780 return pnode->data;
782 return NULL;