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