]> jfr.im git - solanum.git/blob - ircd/s_newconf.c
ircd: integrate ircd side of wsockd support
[solanum.git] / ircd / s_newconf.c
1 /*
2 * ircd-ratbox: an advanced Internet Relay Chat Daemon(ircd).
3 * s_newconf.c - code for dealing with conf stuff
4 *
5 * Copyright (C) 2004 Lee Hardy <lee@leeh.co.uk>
6 * Copyright (C) 2004-2005 ircd-ratbox development team
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
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.
19 *
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.
31 */
32
33 #include "stdinc.h"
34 #include "ircd_defs.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "client.h"
38 #include "s_serv.h"
39 #include "send.h"
40 #include "hostmask.h"
41 #include "newconf.h"
42 #include "hash.h"
43 #include "rb_dictionary.h"
44 #include "rb_radixtree.h"
45 #include "s_assert.h"
46 #include "logger.h"
47 #include "dns.h"
48
49 rb_dlink_list shared_conf_list;
50 rb_dlink_list cluster_conf_list;
51 rb_dlink_list oper_conf_list;
52 rb_dlink_list hubleaf_conf_list;
53 rb_dlink_list server_conf_list;
54 rb_dlink_list xline_conf_list;
55 rb_dlink_list resv_conf_list; /* nicks only! */
56 rb_dlink_list nd_list; /* nick delay */
57 rb_dlink_list tgchange_list;
58
59 rb_patricia_tree_t *tgchange_tree;
60
61 static rb_bh *nd_heap = NULL;
62
63 static void expire_temp_rxlines(void *unused);
64 static void expire_nd_entries(void *unused);
65
66 struct ev_entry *expire_nd_entries_ev = NULL;
67 struct ev_entry *expire_temp_rxlines_ev = NULL;
68
69 void
70 init_s_newconf(void)
71 {
72 tgchange_tree = rb_new_patricia(PATRICIA_BITS);
73 nd_heap = rb_bh_create(sizeof(struct nd_entry), ND_HEAP_SIZE, "nd_heap");
74 expire_nd_entries_ev = rb_event_addish("expire_nd_entries", expire_nd_entries, NULL, 30);
75 expire_temp_rxlines_ev = rb_event_addish("expire_temp_rxlines", expire_temp_rxlines, NULL, 60);
76 }
77
78 void
79 clear_s_newconf(void)
80 {
81 struct server_conf *server_p;
82 rb_dlink_node *ptr;
83 rb_dlink_node *next_ptr;
84
85 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, shared_conf_list.head)
86 {
87 /* ptr here is ptr->data->node */
88 rb_dlinkDelete(ptr, &shared_conf_list);
89 free_remote_conf(ptr->data);
90 }
91
92 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, cluster_conf_list.head)
93 {
94 rb_dlinkDelete(ptr, &cluster_conf_list);
95 free_remote_conf(ptr->data);
96 }
97
98 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, hubleaf_conf_list.head)
99 {
100 rb_dlinkDelete(ptr, &hubleaf_conf_list);
101 free_remote_conf(ptr->data);
102 }
103
104 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, oper_conf_list.head)
105 {
106 free_oper_conf(ptr->data);
107 rb_dlinkDestroy(ptr, &oper_conf_list);
108 }
109
110 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, server_conf_list.head)
111 {
112 server_p = ptr->data;
113
114 if(!server_p->servers)
115 {
116 rb_dlinkDelete(ptr, &server_conf_list);
117 free_server_conf(ptr->data);
118 }
119 else
120 server_p->flags |= SERVER_ILLEGAL;
121 }
122 }
123
124 void
125 clear_s_newconf_bans(void)
126 {
127 struct ConfItem *aconf;
128 rb_dlink_node *ptr, *next_ptr;
129
130 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
131 {
132 aconf = ptr->data;
133
134 if(aconf->hold)
135 continue;
136
137 free_conf(aconf);
138 rb_dlinkDestroy(ptr, &xline_conf_list);
139 }
140
141 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
142 {
143 aconf = ptr->data;
144
145 /* temporary resv */
146 if(aconf->hold)
147 continue;
148
149 free_conf(aconf);
150 rb_dlinkDestroy(ptr, &resv_conf_list);
151 }
152
153 clear_resv_hash();
154 }
155
156 struct remote_conf *
157 make_remote_conf(void)
158 {
159 struct remote_conf *remote_p = rb_malloc(sizeof(struct remote_conf));
160 return remote_p;
161 }
162
163 void
164 free_remote_conf(struct remote_conf *remote_p)
165 {
166 s_assert(remote_p != NULL);
167 if(remote_p == NULL)
168 return;
169
170 rb_free(remote_p->username);
171 rb_free(remote_p->host);
172 rb_free(remote_p->server);
173 rb_free(remote_p);
174 }
175
176 bool
177 find_shared_conf(const char *username, const char *host,
178 const char *server, int flags)
179 {
180 struct remote_conf *shared_p;
181 rb_dlink_node *ptr;
182
183 RB_DLINK_FOREACH(ptr, shared_conf_list.head)
184 {
185 shared_p = ptr->data;
186
187 if(match(shared_p->username, username) &&
188 match(shared_p->host, host) &&
189 match(shared_p->server, server))
190 {
191 if(shared_p->flags & flags)
192 return true;
193 else
194 return false;
195 }
196 }
197
198 return false;
199 }
200
201 void
202 propagate_generic(struct Client *source_p, const char *command,
203 const char *target, int cap, const char *format, ...)
204 {
205 char buffer[BUFSIZE];
206 va_list args;
207
208 va_start(args, format);
209 vsnprintf(buffer, sizeof(buffer), format, args);
210 va_end(args);
211
212 sendto_match_servs(source_p, target, cap, NOCAPS,
213 "%s %s %s",
214 command, target, buffer);
215 sendto_match_servs(source_p, target, CAP_ENCAP, cap,
216 "ENCAP %s %s %s",
217 target, command, buffer);
218 }
219
220 void
221 cluster_generic(struct Client *source_p, const char *command,
222 int cltype, int cap, const char *format, ...)
223 {
224 char buffer[BUFSIZE];
225 struct remote_conf *shared_p;
226 va_list args;
227 rb_dlink_node *ptr;
228
229 va_start(args, format);
230 vsnprintf(buffer, sizeof(buffer), format, args);
231 va_end(args);
232
233 RB_DLINK_FOREACH(ptr, cluster_conf_list.head)
234 {
235 shared_p = ptr->data;
236
237 if(!(shared_p->flags & cltype))
238 continue;
239
240 sendto_match_servs(source_p, shared_p->server, cap, NOCAPS,
241 "%s %s %s",
242 command, shared_p->server, buffer);
243 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, cap,
244 "ENCAP %s %s %s",
245 shared_p->server, command, buffer);
246 }
247 }
248
249 struct oper_conf *
250 make_oper_conf(void)
251 {
252 struct oper_conf *oper_p = rb_malloc(sizeof(struct oper_conf));
253 return oper_p;
254 }
255
256 void
257 free_oper_conf(struct oper_conf *oper_p)
258 {
259 s_assert(oper_p != NULL);
260 if(oper_p == NULL)
261 return;
262
263 rb_free(oper_p->username);
264 rb_free(oper_p->host);
265 rb_free(oper_p->name);
266 rb_free(oper_p->certfp);
267
268 if(oper_p->passwd)
269 {
270 memset(oper_p->passwd, 0, strlen(oper_p->passwd));
271 rb_free(oper_p->passwd);
272 }
273
274 #ifdef HAVE_LIBCRYPTO
275 rb_free(oper_p->rsa_pubkey_file);
276
277 if(oper_p->rsa_pubkey)
278 RSA_free(oper_p->rsa_pubkey);
279 #endif
280
281 rb_free(oper_p);
282 }
283
284 struct oper_conf *
285 find_oper_conf(const char *username, const char *host, const char *locip, const char *name)
286 {
287 struct oper_conf *oper_p;
288 struct rb_sockaddr_storage ip, cip;
289 char addr[HOSTLEN+1];
290 int bits, cbits;
291 rb_dlink_node *ptr;
292
293 parse_netmask(locip, &cip, &cbits);
294
295 RB_DLINK_FOREACH(ptr, oper_conf_list.head)
296 {
297 oper_p = ptr->data;
298
299 /* name/username doesnt match.. */
300 if(irccmp(oper_p->name, name) || !match(oper_p->username, username))
301 continue;
302
303 rb_strlcpy(addr, oper_p->host, sizeof(addr));
304
305 if(parse_netmask(addr, &ip, &bits) != HM_HOST)
306 {
307 if(GET_SS_FAMILY(&ip) == GET_SS_FAMILY(&cip) &&
308 comp_with_mask_sock((struct sockaddr *)&ip, (struct sockaddr *)&cip, bits))
309 return oper_p;
310 }
311
312 /* we have to compare against the host as well, because its
313 * valid to set a spoof to an IP, which if we only compare
314 * in ip form to sockhost will not necessarily match --anfl
315 */
316 if(match(oper_p->host, host))
317 return oper_p;
318 }
319
320 return NULL;
321 }
322
323 struct server_conf *
324 make_server_conf(void)
325 {
326 struct server_conf *server_p = rb_malloc(sizeof(struct server_conf));
327 server_p->aftype = AF_INET;
328 return server_p;
329 }
330
331 void
332 free_server_conf(struct server_conf *server_p)
333 {
334 s_assert(server_p != NULL);
335 if(server_p == NULL)
336 return;
337
338 if(!EmptyString(server_p->passwd))
339 {
340 memset(server_p->passwd, 0, strlen(server_p->passwd));
341 rb_free(server_p->passwd);
342 }
343
344 if(!EmptyString(server_p->spasswd))
345 {
346 memset(server_p->spasswd, 0, strlen(server_p->spasswd));
347 rb_free(server_p->spasswd);
348 }
349
350 rb_free(server_p->name);
351 rb_free(server_p->host);
352 rb_free(server_p->class_name);
353 rb_free(server_p);
354 }
355
356 /*
357 * conf_dns_callback
358 * inputs - pointer to struct ConfItem
359 * - pointer to adns reply
360 * output - none
361 * side effects - called when resolver query finishes
362 * if the query resulted in a successful search, hp will contain
363 * a non-null pointer, otherwise hp will be null.
364 * if successful save hp in the conf item it was called with
365 */
366 static void
367 conf_dns_callback(const char *result, int status, int aftype, void *data)
368 {
369 struct server_conf *server_p = data;
370
371 if(status == 1)
372 rb_inet_pton_sock(result, (struct sockaddr *)&server_p->my_ipnum);
373
374 server_p->dns_query = 0;
375 }
376
377 void
378 add_server_conf(struct server_conf *server_p)
379 {
380 if(EmptyString(server_p->class_name))
381 {
382 server_p->class_name = rb_strdup("default");
383 server_p->class = default_class;
384 return;
385 }
386
387 server_p->class = find_class(server_p->class_name);
388
389 if(server_p->class == default_class)
390 {
391 conf_report_error("Warning connect::class invalid for %s",
392 server_p->name);
393
394 rb_free(server_p->class_name);
395 server_p->class_name = rb_strdup("default");
396 }
397
398 if(strpbrk(server_p->host, "*?"))
399 return;
400
401 server_p->dns_query =
402 lookup_hostname(server_p->host, GET_SS_FAMILY(&server_p->my_ipnum), conf_dns_callback, server_p);
403 }
404
405 struct server_conf *
406 find_server_conf(const char *name)
407 {
408 struct server_conf *server_p;
409 rb_dlink_node *ptr;
410
411 RB_DLINK_FOREACH(ptr, server_conf_list.head)
412 {
413 server_p = ptr->data;
414
415 if(ServerConfIllegal(server_p))
416 continue;
417
418 if(match(name, server_p->name))
419 return server_p;
420 }
421
422 return NULL;
423 }
424
425 void
426 attach_server_conf(struct Client *client_p, struct server_conf *server_p)
427 {
428 /* already have an attached conf */
429 if(client_p->localClient->att_sconf)
430 {
431 /* short circuit this special case :) */
432 if(client_p->localClient->att_sconf == server_p)
433 return;
434
435 detach_server_conf(client_p);
436 }
437
438 CurrUsers(server_p->class)++;
439
440 client_p->localClient->att_sconf = server_p;
441 server_p->servers++;
442 }
443
444 void
445 detach_server_conf(struct Client *client_p)
446 {
447 struct server_conf *server_p = client_p->localClient->att_sconf;
448
449 if(server_p == NULL)
450 return;
451
452 client_p->localClient->att_sconf = NULL;
453 server_p->servers--;
454 CurrUsers(server_p->class)--;
455
456 if(ServerConfIllegal(server_p) && !server_p->servers)
457 {
458 /* the class this one is using may need destroying too */
459 if(MaxUsers(server_p->class) < 0 && CurrUsers(server_p->class) <= 0)
460 free_class(server_p->class);
461
462 rb_dlinkDelete(&server_p->node, &server_conf_list);
463 free_server_conf(server_p);
464 }
465 }
466
467 void
468 set_server_conf_autoconn(struct Client *source_p, const char *name, int newval)
469 {
470 struct server_conf *server_p;
471
472 if((server_p = find_server_conf(name)) != NULL)
473 {
474 if(newval)
475 server_p->flags |= SERVER_AUTOCONN;
476 else
477 server_p->flags &= ~SERVER_AUTOCONN;
478
479 sendto_realops_snomask(SNO_GENERAL, L_ALL,
480 "%s has changed AUTOCONN for %s to %i",
481 get_oper_name(source_p), name, newval);
482 }
483 else
484 sendto_one_notice(source_p, ":Can't find %s", name);
485 }
486
487 void
488 disable_server_conf_autoconn(const char *name)
489 {
490 struct server_conf *server_p;
491
492 server_p = find_server_conf(name);
493 if(server_p != NULL && server_p->flags & SERVER_AUTOCONN)
494 {
495 server_p->flags &= ~SERVER_AUTOCONN;
496
497 sendto_realops_snomask(SNO_GENERAL, L_ALL,
498 "Disabling AUTOCONN for %s because of error",
499 name);
500 ilog(L_SERVER, "Disabling AUTOCONN for %s because of error",
501 name);
502 }
503 }
504
505 struct ConfItem *
506 find_xline(const char *gecos, int counter)
507 {
508 struct ConfItem *aconf;
509 rb_dlink_node *ptr;
510
511 RB_DLINK_FOREACH(ptr, xline_conf_list.head)
512 {
513 aconf = ptr->data;
514
515 if(match_esc(aconf->host, gecos))
516 {
517 if(counter)
518 aconf->port++;
519 return aconf;
520 }
521 }
522
523 return NULL;
524 }
525
526 struct ConfItem *
527 find_xline_mask(const char *gecos)
528 {
529 struct ConfItem *aconf;
530 rb_dlink_node *ptr;
531
532 RB_DLINK_FOREACH(ptr, xline_conf_list.head)
533 {
534 aconf = ptr->data;
535
536 if(!irccmp(aconf->host, gecos))
537 return aconf;
538 }
539
540 return NULL;
541 }
542
543 struct ConfItem *
544 find_nick_resv(const char *name)
545 {
546 struct ConfItem *aconf;
547 rb_dlink_node *ptr;
548
549 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
550 {
551 aconf = ptr->data;
552
553 if(match_esc(aconf->host, name))
554 {
555 aconf->port++;
556 return aconf;
557 }
558 }
559
560 return NULL;
561 }
562
563 struct ConfItem *
564 find_nick_resv_mask(const char *name)
565 {
566 struct ConfItem *aconf;
567 rb_dlink_node *ptr;
568
569 RB_DLINK_FOREACH(ptr, resv_conf_list.head)
570 {
571 aconf = ptr->data;
572
573 if(!irccmp(aconf->host, name))
574 return aconf;
575 }
576
577 return NULL;
578 }
579
580 /* clean_resv_nick()
581 *
582 * inputs - nick
583 * outputs - 1 if nick is vaild resv, 0 otherwise
584 * side effects -
585 */
586 int
587 clean_resv_nick(const char *nick)
588 {
589 char tmpch;
590 int as = 0;
591 int q = 0;
592 int ch = 0;
593
594 if(*nick == '-' || IsDigit(*nick))
595 return 0;
596
597 while ((tmpch = *nick++))
598 {
599 if(tmpch == '?' || tmpch == '@' || tmpch == '#')
600 q++;
601 else if(tmpch == '*')
602 as++;
603 else if(IsNickChar(tmpch))
604 ch++;
605 else
606 return 0;
607 }
608
609 if(!ch && as)
610 return 0;
611
612 return 1;
613 }
614
615 /* valid_wild_card_simple()
616 *
617 * inputs - "thing" to test
618 * outputs - 1 if enough wildcards, else 0
619 * side effects -
620 */
621 int
622 valid_wild_card_simple(const char *data)
623 {
624 const char *p;
625 char tmpch;
626 int nonwild = 0;
627 int wild = 0;
628
629 /* check the string for minimum number of nonwildcard chars */
630 p = data;
631
632 while((tmpch = *p++))
633 {
634 /* found an escape, p points to the char after it, so skip
635 * that and move on.
636 */
637 if(tmpch == '\\' && *p)
638 {
639 p++;
640 if(++nonwild >= ConfigFileEntry.min_nonwildcard_simple)
641 return 1;
642 }
643 else if(!IsMWildChar(tmpch))
644 {
645 /* if we have enough nonwildchars, return */
646 if(++nonwild >= ConfigFileEntry.min_nonwildcard_simple)
647 return 1;
648 }
649 else
650 wild++;
651 }
652
653 /* strings without wilds are also ok */
654 return wild == 0;
655 }
656
657 time_t
658 valid_temp_time(const char *p)
659 {
660 time_t result = 0;
661
662 while(*p)
663 {
664 if(IsDigit(*p))
665 {
666 result *= 10;
667 result += ((*p) & 0xF);
668 p++;
669 }
670 else
671 return -1;
672 }
673
674 if(result > (60 * 24 * 7 * 52))
675 result = (60 * 24 * 7 * 52);
676
677 return(result * 60);
678 }
679
680 /* Propagated bans are expired elsewhere. */
681 static void
682 expire_temp_rxlines(void *unused)
683 {
684 struct ConfItem *aconf;
685 rb_dlink_node *ptr;
686 rb_dlink_node *next_ptr;
687 rb_radixtree_iteration_state state;
688
689 RB_RADIXTREE_FOREACH(aconf, &state, resv_tree)
690 {
691 if(aconf->lifetime != 0)
692 continue;
693 if(aconf->hold && aconf->hold <= rb_current_time())
694 {
695 if(ConfigFileEntry.tkline_expire_notices)
696 sendto_realops_snomask(SNO_GENERAL, L_ALL,
697 "Temporary RESV for [%s] expired",
698 aconf->host);
699
700 rb_radixtree_delete(resv_tree, aconf->host);
701 free_conf(aconf);
702 }
703 }
704
705 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, resv_conf_list.head)
706 {
707 aconf = ptr->data;
708
709 if(aconf->lifetime != 0)
710 continue;
711 if(aconf->hold && aconf->hold <= rb_current_time())
712 {
713 if(ConfigFileEntry.tkline_expire_notices)
714 sendto_realops_snomask(SNO_GENERAL, L_ALL,
715 "Temporary RESV for [%s] expired",
716 aconf->host);
717 free_conf(aconf);
718 rb_dlinkDestroy(ptr, &resv_conf_list);
719 }
720 }
721
722 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, xline_conf_list.head)
723 {
724 aconf = ptr->data;
725
726 if(aconf->lifetime != 0)
727 continue;
728 if(aconf->hold && aconf->hold <= rb_current_time())
729 {
730 if(ConfigFileEntry.tkline_expire_notices)
731 sendto_realops_snomask(SNO_GENERAL, L_ALL,
732 "Temporary X-line for [%s] expired",
733 aconf->host);
734 free_conf(aconf);
735 rb_dlinkDestroy(ptr, &xline_conf_list);
736 }
737 }
738 }
739
740 unsigned long
741 get_nd_count(void)
742 {
743 return(rb_dlink_list_length(&nd_list));
744 }
745
746 void
747 add_nd_entry(const char *name)
748 {
749 struct nd_entry *nd;
750
751 if(rb_dictionary_find(nd_dict, name) != NULL)
752 return;
753
754 nd = rb_bh_alloc(nd_heap);
755
756 rb_strlcpy(nd->name, name, sizeof(nd->name));
757 nd->expire = rb_current_time() + ConfigFileEntry.nick_delay;
758
759 /* this list is ordered */
760 rb_dlinkAddTail(nd, &nd->lnode, &nd_list);
761
762 rb_dictionary_add(nd_dict, nd->name, nd);
763 }
764
765 void
766 free_nd_entry(struct nd_entry *nd)
767 {
768 rb_dictionary_delete(nd_dict, nd->name);
769
770 rb_dlinkDelete(&nd->lnode, &nd_list);
771 rb_bh_free(nd_heap, nd);
772 }
773
774 void
775 expire_nd_entries(void *unused)
776 {
777 struct nd_entry *nd;
778 rb_dlink_node *ptr;
779 rb_dlink_node *next_ptr;
780
781 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, nd_list.head)
782 {
783 nd = ptr->data;
784
785 /* this list is ordered - we can stop when we hit the first
786 * entry that doesnt expire..
787 */
788 if(nd->expire > rb_current_time())
789 return;
790
791 free_nd_entry(nd);
792 }
793 }
794
795 void
796 add_tgchange(const char *host)
797 {
798 tgchange *target;
799 rb_patricia_node_t *pnode;
800
801 if(find_tgchange(host))
802 return;
803
804 target = rb_malloc(sizeof(tgchange));
805 pnode = make_and_lookup(tgchange_tree, host);
806
807 pnode->data = target;
808 target->pnode = pnode;
809
810 target->ip = rb_strdup(host);
811 target->expiry = rb_current_time() + (60*60*12);
812
813 rb_dlinkAdd(target, &target->node, &tgchange_list);
814 }
815
816 tgchange *
817 find_tgchange(const char *host)
818 {
819 rb_patricia_node_t *pnode;
820
821 if((pnode = rb_match_exact_string(tgchange_tree, host)))
822 return pnode->data;
823
824 return NULL;
825 }