ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1411
Committed: Sat May 12 20:46:53 2012 UTC (13 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 93483 byte(s)
Log Message:
- src/conf.c: fixed compile error with openssl disabled

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * conf.c: Configuration file functions.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "list.h"
27 #include "ircd_defs.h"
28 #include "balloc.h"
29 #include "conf.h"
30 #include "s_serv.h"
31 #include "resv.h"
32 #include "channel.h"
33 #include "client.h"
34 #include "event.h"
35 #include "hook.h"
36 #include "irc_string.h"
37 #include "s_bsd.h"
38 #include "ircd.h"
39 #include "listener.h"
40 #include "hostmask.h"
41 #include "modules.h"
42 #include "numeric.h"
43 #include "fdlist.h"
44 #include "log.h"
45 #include "send.h"
46 #include "s_gline.h"
47 #include "memory.h"
48 #include "irc_res.h"
49 #include "userhost.h"
50 #include "s_user.h"
51 #include "channel_mode.h"
52 #include "parse.h"
53 #include "s_misc.h"
54
55 struct Callback *client_check_cb = NULL;
56 struct config_server_hide ConfigServerHide;
57
58 /* general conf items link list root, other than k lines etc. */
59 dlink_list service_items = { NULL, NULL, 0 };
60 dlink_list server_items = { NULL, NULL, 0 };
61 dlink_list cluster_items = { NULL, NULL, 0 };
62 dlink_list oconf_items = { NULL, NULL, 0 };
63 dlink_list uconf_items = { NULL, NULL, 0 };
64 dlink_list xconf_items = { NULL, NULL, 0 };
65 dlink_list rxconf_items = { NULL, NULL, 0 };
66 dlink_list rkconf_items = { NULL, NULL, 0 };
67 dlink_list nresv_items = { NULL, NULL, 0 };
68 dlink_list class_items = { NULL, NULL, 0 };
69 dlink_list gdeny_items = { NULL, NULL, 0 };
70
71 dlink_list temporary_xlines = { NULL, NULL, 0 };
72 dlink_list temporary_resv = { NULL, NULL, 0 };
73
74 extern unsigned int lineno;
75 extern char linebuf[];
76 extern char conffilebuf[IRCD_BUFSIZE];
77 extern int yyparse(); /* defined in y.tab.c */
78
79 struct conf_parser_context conf_parser_ctx = { 0, 0, NULL };
80
81 /* internally defined functions */
82 static void read_conf(FILE *);
83 static void clear_out_old_conf(void);
84 static void flush_deleted_I_P(void);
85 static void expire_tklines(dlink_list *);
86 static void garbage_collect_ip_entries(void);
87 static int hash_ip(struct irc_ssaddr *);
88 static int verify_access(struct Client *, const char *);
89 static int attach_iline(struct Client *, struct ConfItem *);
90 static struct ip_entry *find_or_add_ip(struct irc_ssaddr *);
91 static void parse_conf_file(int, int);
92 static dlink_list *map_to_list(ConfType);
93 static struct AccessItem *find_regexp_kline(const char *[]);
94 static int find_user_host(struct Client *, char *, char *, char *, unsigned int);
95
96 /*
97 * bit_len
98 */
99 static int cidr_limit_reached(int, struct irc_ssaddr *, struct ClassItem *);
100 static void remove_from_cidr_check(struct irc_ssaddr *, struct ClassItem *);
101 static void destroy_cidr_class(struct ClassItem *);
102
103 static void flags_to_ascii(unsigned int, const unsigned int[], char *, int);
104
105 /* address of default class conf */
106 static struct ConfItem *class_default;
107
108 /* usually, with hash tables, you use a prime number...
109 * but in this case I am dealing with ip addresses,
110 * not ascii strings.
111 */
112 #define IP_HASH_SIZE 0x1000
113
114 struct ip_entry
115 {
116 struct irc_ssaddr ip;
117 int count;
118 time_t last_attempt;
119 struct ip_entry *next;
120 };
121
122 static struct ip_entry *ip_hash_table[IP_HASH_SIZE];
123 static BlockHeap *ip_entry_heap = NULL;
124 static int ip_entries_count = 0;
125
126
127 void *
128 map_to_conf(struct ConfItem *aconf)
129 {
130 void *conf;
131 conf = (void *)((uintptr_t)aconf +
132 (uintptr_t)sizeof(struct ConfItem));
133 return(conf);
134 }
135
136 struct ConfItem *
137 unmap_conf_item(void *aconf)
138 {
139 struct ConfItem *conf;
140
141 conf = (struct ConfItem *)((uintptr_t)aconf -
142 (uintptr_t)sizeof(struct ConfItem));
143 return(conf);
144 }
145
146 /* conf_dns_callback()
147 *
148 * inputs - pointer to struct AccessItem
149 * - pointer to DNSReply reply
150 * output - none
151 * side effects - called when resolver query finishes
152 * if the query resulted in a successful search, hp will contain
153 * a non-null pointer, otherwise hp will be null.
154 * if successful save hp in the conf item it was called with
155 */
156 static void
157 conf_dns_callback(void *vptr, const struct irc_ssaddr *addr, const char *name)
158 {
159 struct AccessItem *aconf = vptr;
160
161 aconf->dns_pending = 0;
162
163 if (addr != NULL)
164 memcpy(&aconf->addr, addr, sizeof(aconf->addr));
165 else
166 aconf->dns_failed = 1;
167 }
168
169 /* conf_dns_lookup()
170 *
171 * do a nameserver lookup of the conf host
172 * if the conf entry is currently doing a ns lookup do nothing, otherwise
173 * allocate a dns_query and start ns lookup.
174 */
175 static void
176 conf_dns_lookup(struct AccessItem *aconf)
177 {
178 if (!aconf->dns_pending)
179 {
180 aconf->dns_pending = 1;
181 gethost_byname(conf_dns_callback, aconf, aconf->host);
182 }
183 }
184
185 /* make_conf_item()
186 *
187 * inputs - type of item
188 * output - pointer to new conf entry
189 * side effects - none
190 */
191 struct ConfItem *
192 make_conf_item(ConfType type)
193 {
194 struct ConfItem *conf = NULL;
195 struct AccessItem *aconf = NULL;
196 struct ClassItem *aclass = NULL;
197 int status = 0;
198
199 switch (type)
200 {
201 case DLINE_TYPE:
202 case EXEMPTDLINE_TYPE:
203 case GLINE_TYPE:
204 case KLINE_TYPE:
205 case CLIENT_TYPE:
206 case OPER_TYPE:
207 case SERVER_TYPE:
208 conf = MyMalloc(sizeof(struct ConfItem) +
209 sizeof(struct AccessItem));
210 aconf = map_to_conf(conf);
211 aconf->aftype = AF_INET;
212
213 /* Yes, sigh. switch on type again */
214 switch (type)
215 {
216 case EXEMPTDLINE_TYPE:
217 status = CONF_EXEMPTDLINE;
218 break;
219
220 case DLINE_TYPE:
221 status = CONF_DLINE;
222 break;
223
224 case KLINE_TYPE:
225 status = CONF_KLINE;
226 break;
227
228 case GLINE_TYPE:
229 status = CONF_GLINE;
230 break;
231
232 case CLIENT_TYPE:
233 status = CONF_CLIENT;
234 break;
235
236 case OPER_TYPE:
237 status = CONF_OPERATOR;
238 dlinkAdd(conf, &conf->node, &oconf_items);
239 break;
240
241 case SERVER_TYPE:
242 status = CONF_SERVER;
243 dlinkAdd(conf, &conf->node, &server_items);
244 break;
245
246 default:
247 break;
248 }
249 aconf->status = status;
250 break;
251
252 case ULINE_TYPE:
253 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
254 sizeof(struct MatchItem));
255 dlinkAdd(conf, &conf->node, &uconf_items);
256 break;
257
258 case GDENY_TYPE:
259 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
260 sizeof(struct AccessItem));
261 dlinkAdd(conf, &conf->node, &gdeny_items);
262 break;
263
264 case XLINE_TYPE:
265 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
266 sizeof(struct MatchItem));
267 dlinkAdd(conf, &conf->node, &xconf_items);
268 break;
269 #ifdef HAVE_LIBPCRE
270 case RXLINE_TYPE:
271 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
272 sizeof(struct MatchItem));
273 dlinkAdd(conf, &conf->node, &rxconf_items);
274 break;
275
276 case RKLINE_TYPE:
277 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
278 sizeof(struct AccessItem));
279 aconf = map_to_conf(conf);
280 aconf->status = CONF_KLINE;
281 dlinkAdd(conf, &conf->node, &rkconf_items);
282 break;
283 #endif
284 case CLUSTER_TYPE:
285 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem));
286 dlinkAdd(conf, &conf->node, &cluster_items);
287 break;
288
289 case CRESV_TYPE:
290 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
291 sizeof(struct ResvChannel));
292 break;
293
294 case NRESV_TYPE:
295 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
296 sizeof(struct MatchItem));
297 dlinkAdd(conf, &conf->node, &nresv_items);
298 break;
299
300 case SERVICE_TYPE:
301 status = CONF_SERVICE;
302 conf = MyMalloc(sizeof(struct ConfItem));
303 dlinkAdd(conf, &conf->node, &service_items);
304 break;
305
306 case CLASS_TYPE:
307 conf = MyMalloc(sizeof(struct ConfItem) +
308 sizeof(struct ClassItem));
309 dlinkAdd(conf, &conf->node, &class_items);
310
311 aclass = map_to_conf(conf);
312 aclass->active = 1;
313 aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
314 aclass->ping_freq = DEFAULT_PINGFREQUENCY;
315 aclass->max_total = MAXIMUM_LINKS_DEFAULT;
316 aclass->max_sendq = DEFAULT_SENDQ;
317
318 break;
319
320 default:
321 conf = NULL;
322 break;
323 }
324
325 /* XXX Yes, this will core if default is hit. I want it to for now - db */
326 conf->type = type;
327
328 return conf;
329 }
330
331 void
332 delete_conf_item(struct ConfItem *conf)
333 {
334 dlink_node *m = NULL, *m_next = NULL;
335 struct MatchItem *match_item;
336 struct AccessItem *aconf;
337 ConfType type = conf->type;
338
339 MyFree(conf->name);
340 conf->name = NULL;
341
342 switch(type)
343 {
344 case DLINE_TYPE:
345 case EXEMPTDLINE_TYPE:
346 case GLINE_TYPE:
347 case KLINE_TYPE:
348 case CLIENT_TYPE:
349 case OPER_TYPE:
350 case SERVER_TYPE:
351 aconf = map_to_conf(conf);
352
353 if (aconf->dns_pending)
354 delete_resolver_queries(aconf);
355 if (aconf->passwd != NULL)
356 memset(aconf->passwd, 0, strlen(aconf->passwd));
357 if (aconf->spasswd != NULL)
358 memset(aconf->spasswd, 0, strlen(aconf->spasswd));
359 aconf->class_ptr = NULL;
360
361 MyFree(aconf->passwd);
362 MyFree(aconf->spasswd);
363 MyFree(aconf->reason);
364 MyFree(aconf->oper_reason);
365 MyFree(aconf->user);
366 MyFree(aconf->host);
367 #ifdef HAVE_LIBCRYPTO
368 MyFree(aconf->cipher_list);
369
370 if (aconf->rsa_public_key)
371 RSA_free(aconf->rsa_public_key);
372 MyFree(aconf->rsa_public_key_file);
373 #endif
374
375 /* Yes, sigh. switch on type again */
376 switch(type)
377 {
378 case EXEMPTDLINE_TYPE:
379 case DLINE_TYPE:
380 case GLINE_TYPE:
381 case KLINE_TYPE:
382 case CLIENT_TYPE:
383 MyFree(conf);
384 break;
385
386 case OPER_TYPE:
387 aconf = map_to_conf(conf);
388 if (!IsConfIllegal(aconf))
389 dlinkDelete(&conf->node, &oconf_items);
390 MyFree(conf);
391 break;
392
393 case SERVER_TYPE:
394 aconf = map_to_conf(conf);
395
396 DLINK_FOREACH_SAFE(m, m_next, aconf->hub_list.head)
397 {
398 MyFree(m->data);
399 free_dlink_node(m);
400 }
401
402 DLINK_FOREACH_SAFE(m, m_next, aconf->leaf_list.head)
403 {
404 MyFree(m->data);
405 free_dlink_node(m);
406 }
407
408 if (!IsConfIllegal(aconf))
409 dlinkDelete(&conf->node, &server_items);
410 MyFree(conf);
411 break;
412
413 default:
414 break;
415 }
416 break;
417
418 case ULINE_TYPE:
419 match_item = map_to_conf(conf);
420 MyFree(match_item->user);
421 MyFree(match_item->host);
422 MyFree(match_item->reason);
423 MyFree(match_item->oper_reason);
424 dlinkDelete(&conf->node, &uconf_items);
425 MyFree(conf);
426 break;
427
428 case XLINE_TYPE:
429 match_item = map_to_conf(conf);
430 MyFree(match_item->user);
431 MyFree(match_item->host);
432 MyFree(match_item->reason);
433 MyFree(match_item->oper_reason);
434 dlinkDelete(&conf->node, &xconf_items);
435 MyFree(conf);
436 break;
437 #ifdef HAVE_LIBPCRE
438 case RKLINE_TYPE:
439 aconf = map_to_conf(conf);
440 MyFree(aconf->regexuser);
441 MyFree(aconf->regexhost);
442 MyFree(aconf->user);
443 MyFree(aconf->host);
444 MyFree(aconf->reason);
445 MyFree(aconf->oper_reason);
446 dlinkDelete(&conf->node, &rkconf_items);
447 MyFree(conf);
448 break;
449
450 case RXLINE_TYPE:
451 MyFree(conf->regexpname);
452 match_item = map_to_conf(conf);
453 MyFree(match_item->user);
454 MyFree(match_item->host);
455 MyFree(match_item->reason);
456 MyFree(match_item->oper_reason);
457 dlinkDelete(&conf->node, &rxconf_items);
458 MyFree(conf);
459 break;
460 #endif
461 case NRESV_TYPE:
462 match_item = map_to_conf(conf);
463 MyFree(match_item->user);
464 MyFree(match_item->host);
465 MyFree(match_item->reason);
466 MyFree(match_item->oper_reason);
467 dlinkDelete(&conf->node, &nresv_items);
468
469 if (conf->flags & CONF_FLAGS_TEMPORARY)
470 if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
471 free_dlink_node(m);
472
473 MyFree(conf);
474 break;
475
476 case GDENY_TYPE:
477 aconf = map_to_conf(conf);
478 MyFree(aconf->user);
479 MyFree(aconf->host);
480 dlinkDelete(&conf->node, &gdeny_items);
481 MyFree(conf);
482 break;
483
484 case CLUSTER_TYPE:
485 dlinkDelete(&conf->node, &cluster_items);
486 MyFree(conf);
487 break;
488
489 case CRESV_TYPE:
490 if (conf->flags & CONF_FLAGS_TEMPORARY)
491 if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
492 free_dlink_node(m);
493
494 MyFree(conf);
495 break;
496
497 case CLASS_TYPE:
498 dlinkDelete(&conf->node, &class_items);
499 MyFree(conf);
500 break;
501
502 case SERVICE_TYPE:
503 dlinkDelete(&conf->node, &service_items);
504 MyFree(conf);
505 break;
506
507 default:
508 break;
509 }
510 }
511
512 /* free_access_item()
513 *
514 * inputs - pointer to conf to free
515 * output - none
516 * side effects - crucial password fields are zeroed, conf is freed
517 */
518 void
519 free_access_item(struct AccessItem *aconf)
520 {
521 struct ConfItem *conf;
522
523 if (aconf == NULL)
524 return;
525 conf = unmap_conf_item(aconf);
526 delete_conf_item(conf);
527 }
528
529 static const unsigned int shared_bit_table[] =
530 { 'K', 'k', 'U', 'X', 'x', 'Y', 'Q', 'q', 'R', 'L', 0};
531
532 /* report_confitem_types()
533 *
534 * inputs - pointer to client requesting confitem report
535 * - ConfType to report
536 * output - none
537 * side effects -
538 */
539 void
540 report_confitem_types(struct Client *source_p, ConfType type)
541 {
542 dlink_node *ptr = NULL, *dptr = NULL;
543 struct ConfItem *conf = NULL;
544 struct AccessItem *aconf = NULL;
545 struct MatchItem *matchitem = NULL;
546 struct ClassItem *classitem = NULL;
547 char buf[12];
548 char *p = NULL;
549
550 switch (type)
551 {
552 case GDENY_TYPE:
553 DLINK_FOREACH(ptr, gdeny_items.head)
554 {
555 conf = ptr->data;
556 aconf = map_to_conf(conf);
557
558 p = buf;
559
560 if (aconf->flags & GDENY_BLOCK)
561 *p++ = 'B';
562 else
563 *p++ = 'b';
564
565 if (aconf->flags & GDENY_REJECT)
566 *p++ = 'R';
567 else
568 *p++ = 'r';
569
570 *p = '\0';
571
572 sendto_one(source_p, ":%s %d %s V %s@%s %s %s",
573 me.name, RPL_STATSDEBUG, source_p->name,
574 aconf->user, aconf->host, conf->name, buf);
575 }
576 break;
577
578 case XLINE_TYPE:
579 DLINK_FOREACH(ptr, xconf_items.head)
580 {
581 conf = ptr->data;
582 matchitem = map_to_conf(conf);
583
584 sendto_one(source_p, form_str(RPL_STATSXLINE),
585 me.name, source_p->name,
586 matchitem->hold ? "x": "X", matchitem->count,
587 conf->name, matchitem->reason);
588 }
589 break;
590
591 #ifdef HAVE_LIBPCRE
592 case RXLINE_TYPE:
593 DLINK_FOREACH(ptr, rxconf_items.head)
594 {
595 conf = ptr->data;
596 matchitem = map_to_conf(conf);
597
598 sendto_one(source_p, form_str(RPL_STATSXLINE),
599 me.name, source_p->name,
600 "XR", matchitem->count,
601 conf->name, matchitem->reason);
602 }
603 break;
604
605 case RKLINE_TYPE:
606 DLINK_FOREACH(ptr, rkconf_items.head)
607 {
608 aconf = map_to_conf((conf = ptr->data));
609
610 sendto_one(source_p, form_str(RPL_STATSKLINE), me.name,
611 source_p->name, "KR", aconf->host, aconf->user,
612 aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
613 }
614 break;
615 #endif
616
617 case ULINE_TYPE:
618 DLINK_FOREACH(ptr, uconf_items.head)
619 {
620 conf = ptr->data;
621 matchitem = map_to_conf(conf);
622
623 p = buf;
624
625 /* some of these are redundant for the sake of
626 * consistency with cluster{} flags
627 */
628 *p++ = 'c';
629 flags_to_ascii(matchitem->action, shared_bit_table, p, 0);
630
631 sendto_one(source_p, form_str(RPL_STATSULINE),
632 me.name, source_p->name, conf->name,
633 matchitem->user?matchitem->user: "*",
634 matchitem->host?matchitem->host: "*", buf);
635 }
636
637 DLINK_FOREACH(ptr, cluster_items.head)
638 {
639 conf = ptr->data;
640
641 p = buf;
642
643 *p++ = 'C';
644 flags_to_ascii(conf->flags, shared_bit_table, p, 0);
645
646 sendto_one(source_p, form_str(RPL_STATSULINE),
647 me.name, source_p->name, conf->name,
648 "*", "*", buf);
649 }
650
651 break;
652
653 case OPER_TYPE:
654 DLINK_FOREACH(ptr, oconf_items.head)
655 {
656 conf = ptr->data;
657 aconf = map_to_conf(conf);
658
659 /* Don't allow non opers to see oper privs */
660 if (HasUMode(source_p, UMODE_OPER))
661 sendto_one(source_p, form_str(RPL_STATSOLINE),
662 me.name, source_p->name, 'O', aconf->user, aconf->host,
663 conf->name, oper_privs_as_string(aconf->port),
664 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
665 else
666 sendto_one(source_p, form_str(RPL_STATSOLINE),
667 me.name, source_p->name, 'O', aconf->user, aconf->host,
668 conf->name, "0",
669 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
670 }
671 break;
672
673 case CLASS_TYPE:
674 DLINK_FOREACH(ptr, class_items.head)
675 {
676 conf = ptr->data;
677 classitem = map_to_conf(conf);
678 sendto_one(source_p, form_str(RPL_STATSYLINE),
679 me.name, source_p->name, 'Y',
680 conf->name, classitem->ping_freq,
681 classitem->con_freq,
682 classitem->max_total, classitem->max_sendq,
683 classitem->curr_user_count,
684 classitem->active ? "active" : "disabled");
685 }
686 break;
687
688 case CONF_TYPE:
689 case CLIENT_TYPE:
690 break;
691
692 case SERVICE_TYPE:
693 DLINK_FOREACH(ptr, service_items.head)
694 {
695 conf = ptr->data;
696 sendto_one(source_p, form_str(RPL_STATSSERVICE),
697 me.name, source_p->name, 'S', "*", conf->name, 0, 0);
698 }
699 break;
700
701 case SERVER_TYPE:
702 DLINK_FOREACH(ptr, server_items.head)
703 {
704 p = buf;
705
706 conf = ptr->data;
707 aconf = map_to_conf(conf);
708
709 buf[0] = '\0';
710
711 if (IsConfAllowAutoConn(aconf))
712 *p++ = 'A';
713 if (IsConfSSL(aconf))
714 *p++ = 'S';
715 if (IsConfTopicBurst(aconf))
716 *p++ = 'T';
717 if (buf[0] == '\0')
718 *p++ = '*';
719
720 *p = '\0';
721
722 /*
723 * Allow admins to see actual ips unless hide_server_ips is enabled
724 */
725 if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
726 sendto_one(source_p, form_str(RPL_STATSCLINE),
727 me.name, source_p->name, 'C', aconf->host,
728 buf, conf->name, aconf->port,
729 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
730 else
731 sendto_one(source_p, form_str(RPL_STATSCLINE),
732 me.name, source_p->name, 'C',
733 "*@127.0.0.1", buf, conf->name, aconf->port,
734 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
735 }
736 break;
737
738 case HUB_TYPE:
739 DLINK_FOREACH(ptr, server_items.head)
740 {
741 conf = ptr->data;
742 aconf = map_to_conf(conf);
743
744 DLINK_FOREACH(dptr, aconf->hub_list.head)
745 sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
746 source_p->name, 'H', dptr->data, conf->name, 0, "*");
747 }
748 break;
749
750 case LEAF_TYPE:
751 DLINK_FOREACH(ptr, server_items.head)
752 {
753 conf = ptr->data;
754 aconf = map_to_conf(conf);
755
756 DLINK_FOREACH(dptr, aconf->leaf_list.head)
757 sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
758 source_p->name, 'L', dptr->data, conf->name, 0, "*");
759 }
760 break;
761
762 case GLINE_TYPE:
763 case KLINE_TYPE:
764 case DLINE_TYPE:
765 case EXEMPTDLINE_TYPE:
766 case CRESV_TYPE:
767 case NRESV_TYPE:
768 case CLUSTER_TYPE:
769 default:
770 break;
771 }
772 }
773
774 /* check_client()
775 *
776 * inputs - pointer to client
777 * output - 0 = Success
778 * NOT_AUTHORIZED (-1) = Access denied (no I line match)
779 * IRCD_SOCKET_ERROR (-2) = Bad socket.
780 * I_LINE_FULL (-3) = I-line is full
781 * TOO_MANY (-4) = Too many connections from hostname
782 * BANNED_CLIENT (-5) = K-lined
783 * side effects - Ordinary client access check.
784 * Look for conf lines which have the same
785 * status as the flags passed.
786 */
787 static void *
788 check_client(va_list args)
789 {
790 struct Client *source_p = va_arg(args, struct Client *);
791 const char *username = va_arg(args, const char *);
792 int i;
793
794 /* I'm already in big trouble if source_p->localClient is NULL -db */
795 if ((i = verify_access(source_p, username)))
796 ilog(LOG_TYPE_IRCD, "Access denied: %s[%s]",
797 source_p->name, source_p->sockhost);
798
799 switch (i)
800 {
801 case TOO_MANY:
802 sendto_realops_flags(UMODE_FULL, L_ALL,
803 "Too many on IP for %s (%s).",
804 get_client_name(source_p, SHOW_IP),
805 source_p->sockhost);
806 ilog(LOG_TYPE_IRCD, "Too many connections on IP from %s.",
807 get_client_name(source_p, SHOW_IP));
808 ++ServerStats.is_ref;
809 exit_client(source_p, &me, "No more connections allowed on that IP");
810 break;
811
812 case I_LINE_FULL:
813 sendto_realops_flags(UMODE_FULL, L_ALL,
814 "I-line is full for %s (%s).",
815 get_client_name(source_p, SHOW_IP),
816 source_p->sockhost);
817 ilog(LOG_TYPE_IRCD, "Too many connections from %s.",
818 get_client_name(source_p, SHOW_IP));
819 ++ServerStats.is_ref;
820 exit_client(source_p, &me,
821 "No more connections allowed in your connection class");
822 break;
823
824 case NOT_AUTHORIZED:
825 ++ServerStats.is_ref;
826 /* jdc - lists server name & port connections are on */
827 /* a purely cosmetical change */
828 sendto_realops_flags(UMODE_UNAUTH, L_ALL,
829 "Unauthorized client connection from %s [%s] on [%s/%u].",
830 get_client_name(source_p, SHOW_IP),
831 source_p->sockhost,
832 source_p->localClient->listener->name,
833 source_p->localClient->listener->port);
834 ilog(LOG_TYPE_IRCD,
835 "Unauthorized client connection from %s on [%s/%u].",
836 get_client_name(source_p, SHOW_IP),
837 source_p->localClient->listener->name,
838 source_p->localClient->listener->port);
839
840 /* XXX It is prolematical whether it is better to use the
841 * capture reject code here or rely on the connecting too fast code.
842 * - Dianora
843 */
844 if (REJECT_HOLD_TIME > 0)
845 {
846 sendto_one(source_p, ":%s NOTICE %s :You are not authorized to use this server",
847 me.name, source_p->name);
848 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
849 SetCaptured(source_p);
850 }
851 else
852 exit_client(source_p, &me, "You are not authorized to use this server");
853 break;
854
855 case BANNED_CLIENT:
856 /*
857 * Don't exit them immediately, play with them a bit.
858 * - Dianora
859 */
860 if (REJECT_HOLD_TIME > 0)
861 {
862 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
863 SetCaptured(source_p);
864 }
865 else
866 exit_client(source_p, &me, "Banned");
867 ++ServerStats.is_ref;
868 break;
869
870 case 0:
871 default:
872 break;
873 }
874
875 return (i < 0 ? NULL : source_p);
876 }
877
878 /* verify_access()
879 *
880 * inputs - pointer to client to verify
881 * - pointer to proposed username
882 * output - 0 if success -'ve if not
883 * side effect - find the first (best) I line to attach.
884 */
885 static int
886 verify_access(struct Client *client_p, const char *username)
887 {
888 struct AccessItem *aconf = NULL, *rkconf = NULL;
889 struct ConfItem *conf = NULL;
890 char non_ident[USERLEN + 1] = { '~', '\0' };
891 const char *uhi[3];
892
893 if (IsGotId(client_p))
894 {
895 aconf = find_address_conf(client_p->host, client_p->username,
896 &client_p->localClient->ip,
897 client_p->localClient->aftype,
898 client_p->localClient->passwd);
899 }
900 else
901 {
902 strlcpy(non_ident+1, username, sizeof(non_ident)-1);
903 aconf = find_address_conf(client_p->host,non_ident,
904 &client_p->localClient->ip,
905 client_p->localClient->aftype,
906 client_p->localClient->passwd);
907 }
908
909 uhi[0] = IsGotId(client_p) ? client_p->username : non_ident;
910 uhi[1] = client_p->host;
911 uhi[2] = client_p->sockhost;
912
913 rkconf = find_regexp_kline(uhi);
914
915 if (aconf != NULL)
916 {
917 if (IsConfClient(aconf) && !rkconf)
918 {
919 conf = unmap_conf_item(aconf);
920
921 if (IsConfRedir(aconf))
922 {
923 sendto_one(client_p, form_str(RPL_REDIR),
924 me.name, client_p->name,
925 conf->name ? conf->name : "",
926 aconf->port);
927 return(NOT_AUTHORIZED);
928 }
929
930 if (IsConfDoIdentd(aconf))
931 SetNeedId(client_p);
932
933 /* Thanks for spoof idea amm */
934 if (IsConfDoSpoofIp(aconf))
935 {
936 conf = unmap_conf_item(aconf);
937
938 if (!ConfigFileEntry.hide_spoof_ips && IsConfSpoofNotice(aconf))
939 sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s spoofing: %s as %s",
940 client_p->name, client_p->host, conf->name);
941 strlcpy(client_p->host, conf->name, sizeof(client_p->host));
942 SetIPSpoof(client_p);
943 }
944
945 return(attach_iline(client_p, conf));
946 }
947 else if (rkconf || IsConfKill(aconf) || (ConfigFileEntry.glines && IsConfGline(aconf)))
948 {
949 /* XXX */
950 aconf = rkconf ? rkconf : aconf;
951 if (IsConfGline(aconf))
952 sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name,
953 client_p->name);
954 if (ConfigFileEntry.kline_with_reason)
955 sendto_one(client_p, ":%s NOTICE %s :*** Banned %s",
956 me.name, client_p->name, aconf->reason);
957 return(BANNED_CLIENT);
958 }
959 }
960
961 return(NOT_AUTHORIZED);
962 }
963
964 /* attach_iline()
965 *
966 * inputs - client pointer
967 * - conf pointer
968 * output -
969 * side effects - do actual attach
970 */
971 static int
972 attach_iline(struct Client *client_p, struct ConfItem *conf)
973 {
974 struct AccessItem *aconf;
975 struct ClassItem *aclass;
976 struct ip_entry *ip_found;
977 int a_limit_reached = 0;
978 int local = 0, global = 0, ident = 0;
979
980 ip_found = find_or_add_ip(&client_p->localClient->ip);
981 ip_found->count++;
982 SetIpHash(client_p);
983
984 aconf = map_to_conf(conf);
985 if (aconf->class_ptr == NULL)
986 return NOT_AUTHORIZED; /* If class is missing, this is best */
987
988 aclass = map_to_conf(aconf->class_ptr);
989
990 count_user_host(client_p->username, client_p->host,
991 &global, &local, &ident);
992
993 /* XXX blah. go down checking the various silly limits
994 * setting a_limit_reached if any limit is reached.
995 * - Dianora
996 */
997 if (aclass->max_total != 0 && aclass->curr_user_count >= aclass->max_total)
998 a_limit_reached = 1;
999 else if (aclass->max_perip != 0 && ip_found->count > aclass->max_perip)
1000 a_limit_reached = 1;
1001 else if (aclass->max_local != 0 && local >= aclass->max_local)
1002 a_limit_reached = 1;
1003 else if (aclass->max_global != 0 && global >= aclass->max_global)
1004 a_limit_reached = 1;
1005 else if (aclass->max_ident != 0 && ident >= aclass->max_ident &&
1006 client_p->username[0] != '~')
1007 a_limit_reached = 1;
1008
1009 if (a_limit_reached)
1010 {
1011 if (!IsConfExemptLimits(aconf))
1012 return TOO_MANY; /* Already at maximum allowed */
1013
1014 sendto_one(client_p,
1015 ":%s NOTICE %s :*** Your connection class is full, "
1016 "but you have exceed_limit = yes;", me.name, client_p->name);
1017 }
1018
1019 return attach_conf(client_p, conf);
1020 }
1021
1022 /* init_ip_hash_table()
1023 *
1024 * inputs - NONE
1025 * output - NONE
1026 * side effects - allocate memory for ip_entry(s)
1027 * - clear the ip hash table
1028 */
1029 void
1030 init_ip_hash_table(void)
1031 {
1032 ip_entry_heap = BlockHeapCreate("ip", sizeof(struct ip_entry),
1033 2 * hard_fdlimit);
1034 memset(ip_hash_table, 0, sizeof(ip_hash_table));
1035 }
1036
1037 /* find_or_add_ip()
1038 *
1039 * inputs - pointer to struct irc_ssaddr
1040 * output - pointer to a struct ip_entry
1041 * side effects -
1042 *
1043 * If the ip # was not found, a new struct ip_entry is created, and the ip
1044 * count set to 0.
1045 */
1046 static struct ip_entry *
1047 find_or_add_ip(struct irc_ssaddr *ip_in)
1048 {
1049 struct ip_entry *ptr, *newptr;
1050 int hash_index = hash_ip(ip_in), res;
1051 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
1052 #ifdef IPV6
1053 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
1054 #endif
1055
1056 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
1057 {
1058 #ifdef IPV6
1059 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1060 continue;
1061 if (ip_in->ss.ss_family == AF_INET6)
1062 {
1063 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1064 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1065 }
1066 else
1067 #endif
1068 {
1069 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1070 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1071 }
1072 if (res == 0)
1073 {
1074 /* Found entry already in hash, return it. */
1075 return ptr;
1076 }
1077 }
1078
1079 if (ip_entries_count >= 2 * hard_fdlimit)
1080 garbage_collect_ip_entries();
1081
1082 newptr = BlockHeapAlloc(ip_entry_heap);
1083 ip_entries_count++;
1084 memcpy(&newptr->ip, ip_in, sizeof(struct irc_ssaddr));
1085
1086 newptr->next = ip_hash_table[hash_index];
1087 ip_hash_table[hash_index] = newptr;
1088
1089 return newptr;
1090 }
1091
1092 /* remove_one_ip()
1093 *
1094 * inputs - unsigned long IP address value
1095 * output - NONE
1096 * side effects - The ip address given, is looked up in ip hash table
1097 * and number of ip#'s for that ip decremented.
1098 * If ip # count reaches 0 and has expired,
1099 * the struct ip_entry is returned to the ip_entry_heap
1100 */
1101 void
1102 remove_one_ip(struct irc_ssaddr *ip_in)
1103 {
1104 struct ip_entry *ptr;
1105 struct ip_entry *last_ptr = NULL;
1106 int hash_index = hash_ip(ip_in), res;
1107 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
1108 #ifdef IPV6
1109 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
1110 #endif
1111
1112 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
1113 {
1114 #ifdef IPV6
1115 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1116 continue;
1117 if (ip_in->ss.ss_family == AF_INET6)
1118 {
1119 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1120 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1121 }
1122 else
1123 #endif
1124 {
1125 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1126 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1127 }
1128 if (res)
1129 continue;
1130 if (ptr->count > 0)
1131 ptr->count--;
1132 if (ptr->count == 0 &&
1133 (CurrentTime-ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1134 {
1135 if (last_ptr != NULL)
1136 last_ptr->next = ptr->next;
1137 else
1138 ip_hash_table[hash_index] = ptr->next;
1139
1140 BlockHeapFree(ip_entry_heap, ptr);
1141 ip_entries_count--;
1142 return;
1143 }
1144 last_ptr = ptr;
1145 }
1146 }
1147
1148 /* hash_ip()
1149 *
1150 * input - pointer to an irc_inaddr
1151 * output - integer value used as index into hash table
1152 * side effects - hopefully, none
1153 */
1154 static int
1155 hash_ip(struct irc_ssaddr *addr)
1156 {
1157 if (addr->ss.ss_family == AF_INET)
1158 {
1159 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
1160 int hash;
1161 uint32_t ip;
1162
1163 ip = ntohl(v4->sin_addr.s_addr);
1164 hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1);
1165 return hash;
1166 }
1167 #ifdef IPV6
1168 else
1169 {
1170 int hash;
1171 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
1172 uint32_t *ip = (uint32_t *)&v6->sin6_addr.s6_addr;
1173
1174 hash = ip[0] ^ ip[3];
1175 hash ^= hash >> 16;
1176 hash ^= hash >> 8;
1177 hash = hash & (IP_HASH_SIZE - 1);
1178 return hash;
1179 }
1180 #else
1181 return 0;
1182 #endif
1183 }
1184
1185 /* count_ip_hash()
1186 *
1187 * inputs - pointer to counter of number of ips hashed
1188 * - pointer to memory used for ip hash
1189 * output - returned via pointers input
1190 * side effects - NONE
1191 *
1192 * number of hashed ip #'s is counted up, plus the amount of memory
1193 * used in the hash.
1194 */
1195 void
1196 count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored)
1197 {
1198 struct ip_entry *ptr;
1199 int i;
1200
1201 *number_ips_stored = 0;
1202 *mem_ips_stored = 0;
1203
1204 for (i = 0; i < IP_HASH_SIZE; i++)
1205 {
1206 for (ptr = ip_hash_table[i]; ptr; ptr = ptr->next)
1207 {
1208 *number_ips_stored += 1;
1209 *mem_ips_stored += sizeof(struct ip_entry);
1210 }
1211 }
1212 }
1213
1214 /* garbage_collect_ip_entries()
1215 *
1216 * input - NONE
1217 * output - NONE
1218 * side effects - free up all ip entries with no connections
1219 */
1220 static void
1221 garbage_collect_ip_entries(void)
1222 {
1223 struct ip_entry *ptr;
1224 struct ip_entry *last_ptr;
1225 struct ip_entry *next_ptr;
1226 int i;
1227
1228 for (i = 0; i < IP_HASH_SIZE; i++)
1229 {
1230 last_ptr = NULL;
1231
1232 for (ptr = ip_hash_table[i]; ptr; ptr = next_ptr)
1233 {
1234 next_ptr = ptr->next;
1235
1236 if (ptr->count == 0 &&
1237 (CurrentTime - ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1238 {
1239 if (last_ptr != NULL)
1240 last_ptr->next = ptr->next;
1241 else
1242 ip_hash_table[i] = ptr->next;
1243 BlockHeapFree(ip_entry_heap, ptr);
1244 ip_entries_count--;
1245 }
1246 else
1247 last_ptr = ptr;
1248 }
1249 }
1250 }
1251
1252 /* detach_conf()
1253 *
1254 * inputs - pointer to client to detach
1255 * - type of conf to detach
1256 * output - 0 for success, -1 for failure
1257 * side effects - Disassociate configuration from the client.
1258 * Also removes a class from the list if marked for deleting.
1259 */
1260 int
1261 detach_conf(struct Client *client_p, ConfType type)
1262 {
1263 dlink_node *ptr, *next_ptr;
1264 struct ConfItem *conf;
1265 struct ClassItem *aclass;
1266 struct AccessItem *aconf;
1267 struct ConfItem *aclass_conf;
1268 struct MatchItem *match_item;
1269
1270 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->confs.head)
1271 {
1272 conf = ptr->data;
1273
1274 if (type == CONF_TYPE || conf->type == type)
1275 {
1276 dlinkDelete(ptr, &client_p->localClient->confs);
1277 free_dlink_node(ptr);
1278
1279 switch (conf->type)
1280 {
1281 case CLIENT_TYPE:
1282 case OPER_TYPE:
1283 case SERVER_TYPE:
1284 aconf = map_to_conf(conf);
1285
1286 assert(aconf->clients > 0);
1287
1288 if ((aclass_conf = aconf->class_ptr) != NULL)
1289 {
1290 aclass = map_to_conf(aclass_conf);
1291
1292 assert(aclass->curr_user_count > 0);
1293
1294 if (conf->type == CLIENT_TYPE)
1295 remove_from_cidr_check(&client_p->localClient->ip, aclass);
1296 if (--aclass->curr_user_count == 0 && aclass->active == 0)
1297 delete_conf_item(aclass_conf);
1298 }
1299
1300 if (--aconf->clients == 0 && IsConfIllegal(aconf))
1301 delete_conf_item(conf);
1302
1303 break;
1304 default:
1305 break;
1306 }
1307
1308 if (type != CONF_TYPE)
1309 return 0;
1310 }
1311 }
1312
1313 return -1;
1314 }
1315
1316 /* attach_conf()
1317 *
1318 * inputs - client pointer
1319 * - conf pointer
1320 * output -
1321 * side effects - Associate a specific configuration entry to a *local*
1322 * client (this is the one which used in accepting the
1323 * connection). Note, that this automatically changes the
1324 * attachment if there was an old one...
1325 */
1326 int
1327 attach_conf(struct Client *client_p, struct ConfItem *conf)
1328 {
1329 struct AccessItem *aconf = map_to_conf(conf);
1330 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1331
1332 if (dlinkFind(&client_p->localClient->confs, conf) != NULL)
1333 return 1;
1334
1335 if (IsConfIllegal(aconf)) /* TBV: can't happen */
1336 return NOT_AUTHORIZED;
1337
1338 if (conf->type == CLIENT_TYPE)
1339 if (cidr_limit_reached(IsConfExemptLimits(aconf),
1340 &client_p->localClient->ip, aclass))
1341 return TOO_MANY; /* Already at maximum allowed */
1342
1343 aclass->curr_user_count++;
1344 aconf->clients++;
1345
1346 dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs);
1347
1348 return 0;
1349 }
1350
1351 /* attach_connect_block()
1352 *
1353 * inputs - pointer to server to attach
1354 * - name of server
1355 * - hostname of server
1356 * output - true (1) if both are found, otherwise return false (0)
1357 * side effects - find connect block and attach them to connecting client
1358 */
1359 int
1360 attach_connect_block(struct Client *client_p, const char *name,
1361 const char *host)
1362 {
1363 dlink_node *ptr;
1364 struct ConfItem *conf;
1365 struct AccessItem *aconf;
1366
1367 assert(client_p != NULL);
1368 assert(host != NULL);
1369
1370 if (client_p == NULL || host == NULL)
1371 return 0;
1372
1373 DLINK_FOREACH(ptr, server_items.head)
1374 {
1375 conf = ptr->data;
1376 aconf = map_to_conf(conf);
1377
1378 if (match(conf->name, name) == 0 || match(aconf->host, host) == 0)
1379 continue;
1380
1381 attach_conf(client_p, conf);
1382 return -1;
1383 }
1384
1385 return 0;
1386 }
1387
1388 /* find_conf_exact()
1389 *
1390 * inputs - type of ConfItem
1391 * - pointer to name to find
1392 * - pointer to username to find
1393 * - pointer to host to find
1394 * output - NULL or pointer to conf found
1395 * side effects - find a conf entry which matches the hostname
1396 * and has the same name.
1397 */
1398 struct ConfItem *
1399 find_conf_exact(ConfType type, const char *name, const char *user,
1400 const char *host)
1401 {
1402 dlink_node *ptr;
1403 dlink_list *list_p;
1404 struct ConfItem *conf = NULL;
1405 struct AccessItem *aconf;
1406
1407 /* Only valid for OPER_TYPE and ...? */
1408 list_p = map_to_list(type);
1409
1410 DLINK_FOREACH(ptr, (*list_p).head)
1411 {
1412 conf = ptr->data;
1413
1414 if (conf->name == NULL)
1415 continue;
1416 aconf = map_to_conf(conf);
1417 if (aconf->host == NULL)
1418 continue;
1419 if (irccmp(conf->name, name) != 0)
1420 continue;
1421
1422 /*
1423 ** Accept if the *real* hostname (usually sockethost)
1424 ** socket host) matches *either* host or name field
1425 ** of the configuration.
1426 */
1427 if (!match(aconf->host, host) || !match(aconf->user, user))
1428 continue;
1429 if (type == OPER_TYPE)
1430 {
1431 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1432
1433 if (aconf->clients >= aclass->max_total)
1434 continue;
1435 }
1436
1437 return conf;
1438 }
1439
1440 return NULL;
1441 }
1442
1443 /* find_conf_name()
1444 *
1445 * inputs - pointer to conf link list to search
1446 * - pointer to name to find
1447 * - int mask of type of conf to find
1448 * output - NULL or pointer to conf found
1449 * side effects - find a conf entry which matches the name
1450 * and has the given mask.
1451 */
1452 struct ConfItem *
1453 find_conf_name(dlink_list *list, const char *name, ConfType type)
1454 {
1455 dlink_node *ptr;
1456 struct ConfItem* conf;
1457
1458 DLINK_FOREACH(ptr, list->head)
1459 {
1460 conf = ptr->data;
1461
1462 if (conf->type == type)
1463 {
1464 if (conf->name && (irccmp(conf->name, name) == 0 ||
1465 match(conf->name, name)))
1466 return conf;
1467 }
1468 }
1469
1470 return NULL;
1471 }
1472
1473 /* map_to_list()
1474 *
1475 * inputs - ConfType conf
1476 * output - pointer to dlink_list to use
1477 * side effects - none
1478 */
1479 static dlink_list *
1480 map_to_list(ConfType type)
1481 {
1482 switch(type)
1483 {
1484 case RXLINE_TYPE:
1485 return(&rxconf_items);
1486 break;
1487 case XLINE_TYPE:
1488 return(&xconf_items);
1489 break;
1490 case ULINE_TYPE:
1491 return(&uconf_items);
1492 break;
1493 case NRESV_TYPE:
1494 return(&nresv_items);
1495 break;
1496 case OPER_TYPE:
1497 return(&oconf_items);
1498 break;
1499 case CLASS_TYPE:
1500 return(&class_items);
1501 break;
1502 case SERVER_TYPE:
1503 return(&server_items);
1504 break;
1505 case SERVICE_TYPE:
1506 return(&service_items);
1507 break;
1508 case CLUSTER_TYPE:
1509 return(&cluster_items);
1510 break;
1511 case CONF_TYPE:
1512 case GLINE_TYPE:
1513 case KLINE_TYPE:
1514 case DLINE_TYPE:
1515 case CRESV_TYPE:
1516 default:
1517 return NULL;
1518 }
1519 }
1520
1521 /* find_matching_name_conf()
1522 *
1523 * inputs - type of link list to look in
1524 * - pointer to name string to find
1525 * - pointer to user
1526 * - pointer to host
1527 * - optional action to match on as well
1528 * output - NULL or pointer to found struct MatchItem
1529 * side effects - looks for a match on name field
1530 */
1531 struct ConfItem *
1532 find_matching_name_conf(ConfType type, const char *name, const char *user,
1533 const char *host, int action)
1534 {
1535 dlink_node *ptr=NULL;
1536 struct ConfItem *conf=NULL;
1537 struct AccessItem *aconf=NULL;
1538 struct MatchItem *match_item=NULL;
1539 dlink_list *list_p = map_to_list(type);
1540
1541 switch (type)
1542 {
1543 #ifdef HAVE_LIBPCRE
1544 case RXLINE_TYPE:
1545 DLINK_FOREACH(ptr, list_p->head)
1546 {
1547 conf = ptr->data;
1548 assert(conf->regexpname);
1549
1550 if (!ircd_pcre_exec(conf->regexpname, name))
1551 return conf;
1552 }
1553 break;
1554 #endif
1555 case SERVICE_TYPE:
1556 DLINK_FOREACH(ptr, list_p->head)
1557 {
1558 conf = ptr->data;
1559
1560 if (EmptyString(conf->name))
1561 continue;
1562 if ((name != NULL) && !irccmp(name, conf->name))
1563 return conf;
1564 }
1565 break;
1566
1567 case XLINE_TYPE:
1568 case ULINE_TYPE:
1569 case NRESV_TYPE:
1570 DLINK_FOREACH(ptr, list_p->head)
1571 {
1572 conf = ptr->data;
1573
1574 match_item = map_to_conf(conf);
1575 if (EmptyString(conf->name))
1576 continue;
1577 if ((name != NULL) && match_esc(conf->name, name))
1578 {
1579 if ((user == NULL && (host == NULL)))
1580 return conf;
1581 if ((match_item->action & action) != action)
1582 continue;
1583 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1584 return conf;
1585 if (match(match_item->user, user) && match(match_item->host, host))
1586 return conf;
1587 }
1588 }
1589 break;
1590
1591 case SERVER_TYPE:
1592 DLINK_FOREACH(ptr, list_p->head)
1593 {
1594 conf = ptr->data;
1595 aconf = map_to_conf(conf);
1596
1597 if ((name != NULL) && match_esc(name, conf->name))
1598 return conf;
1599 else if ((host != NULL) && match_esc(host, aconf->host))
1600 return conf;
1601 }
1602 break;
1603
1604 default:
1605 break;
1606 }
1607 return NULL;
1608 }
1609
1610 /* find_exact_name_conf()
1611 *
1612 * inputs - type of link list to look in
1613 * - pointer to name string to find
1614 * - pointer to user
1615 * - pointer to host
1616 * output - NULL or pointer to found struct MatchItem
1617 * side effects - looks for an exact match on name field
1618 */
1619 struct ConfItem *
1620 find_exact_name_conf(ConfType type, const struct Client *who, const char *name,
1621 const char *user, const char *host)
1622 {
1623 dlink_node *ptr = NULL;
1624 struct AccessItem *aconf;
1625 struct ConfItem *conf;
1626 struct MatchItem *match_item;
1627 dlink_list *list_p;
1628
1629 list_p = map_to_list(type);
1630
1631 switch(type)
1632 {
1633 case RXLINE_TYPE:
1634 case XLINE_TYPE:
1635 case ULINE_TYPE:
1636 case NRESV_TYPE:
1637
1638 DLINK_FOREACH(ptr, list_p->head)
1639 {
1640 conf = ptr->data;
1641 match_item = (struct MatchItem *)map_to_conf(conf);
1642 if (EmptyString(conf->name))
1643 continue;
1644
1645 if (irccmp(conf->name, name) == 0)
1646 {
1647 if ((user == NULL && (host == NULL)))
1648 return (conf);
1649 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1650 return (conf);
1651 if (match(match_item->user, user) && match(match_item->host, host))
1652 return (conf);
1653 }
1654 }
1655 break;
1656
1657 case OPER_TYPE:
1658 DLINK_FOREACH(ptr, list_p->head)
1659 {
1660 conf = ptr->data;
1661 aconf = map_to_conf(conf);
1662
1663 if (EmptyString(conf->name))
1664 continue;
1665
1666 if (!irccmp(conf->name, name))
1667 {
1668 if (!who)
1669 return conf;
1670 if (EmptyString(aconf->user) || EmptyString(aconf->host))
1671 return conf;
1672 if (match(aconf->user, who->username))
1673 {
1674 switch (aconf->type)
1675 {
1676 case HM_HOST:
1677 if (match(aconf->host, who->host) || match(aconf->host, who->sockhost))
1678 return conf;
1679 break;
1680 case HM_IPV4:
1681 if (who->localClient->aftype == AF_INET)
1682 if (match_ipv4(&who->localClient->ip, &aconf->addr, aconf->bits))
1683 return conf;
1684 break;
1685 #ifdef IPV6
1686 case HM_IPV6:
1687 if (who->localClient->aftype == AF_INET6)
1688 if (match_ipv6(&who->localClient->ip, &aconf->addr, aconf->bits))
1689 return conf;
1690 break;
1691 #endif
1692 default:
1693 assert(0);
1694 }
1695 }
1696 }
1697 }
1698
1699 break;
1700
1701 case SERVER_TYPE:
1702 DLINK_FOREACH(ptr, list_p->head)
1703 {
1704 conf = ptr->data;
1705 aconf = (struct AccessItem *)map_to_conf(conf);
1706 if (EmptyString(conf->name))
1707 continue;
1708
1709 if (name == NULL)
1710 {
1711 if (EmptyString(aconf->host))
1712 continue;
1713 if (irccmp(aconf->host, host) == 0)
1714 return(conf);
1715 }
1716 else if (irccmp(conf->name, name) == 0)
1717 {
1718 return (conf);
1719 }
1720 }
1721 break;
1722
1723 case CLASS_TYPE:
1724 DLINK_FOREACH(ptr, list_p->head)
1725 {
1726 conf = ptr->data;
1727 if (EmptyString(conf->name))
1728 continue;
1729
1730 if (irccmp(conf->name, name) == 0)
1731 return (conf);
1732 }
1733 break;
1734
1735 default:
1736 break;
1737 }
1738 return(NULL);
1739 }
1740
1741 /* rehash()
1742 *
1743 * Actual REHASH service routine. Called with sig == 0 if it has been called
1744 * as a result of an operator issuing this command, else assume it has been
1745 * called as a result of the server receiving a HUP signal.
1746 */
1747 int
1748 rehash(int sig)
1749 {
1750 if (sig != 0)
1751 sendto_realops_flags(UMODE_ALL, L_ALL,
1752 "Got signal SIGHUP, reloading ircd.conf file");
1753
1754 restart_resolver();
1755
1756 /* don't close listeners until we know we can go ahead with the rehash */
1757
1758 /* Check to see if we magically got(or lost) IPv6 support */
1759 check_can_use_v6();
1760
1761 read_conf_files(0);
1762
1763 if (ServerInfo.description != NULL)
1764 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
1765
1766 load_conf_modules();
1767
1768 flush_deleted_I_P();
1769
1770 rehashed_klines = 1;
1771 /* XXX */
1772 if (ConfigLoggingEntry.use_logging)
1773 log_close_all();
1774
1775 return(0);
1776 }
1777
1778 /* set_default_conf()
1779 *
1780 * inputs - NONE
1781 * output - NONE
1782 * side effects - Set default values here.
1783 * This is called **PRIOR** to parsing the
1784 * configuration file. If you want to do some validation
1785 * of values later, put them in validate_conf().
1786 */
1787 static void
1788 set_default_conf(void)
1789 {
1790 /* verify init_class() ran, this should be an unnecessary check
1791 * but its not much work.
1792 */
1793 assert(class_default == (struct ConfItem *) class_items.tail->data);
1794
1795 #ifdef HAVE_LIBCRYPTO
1796 ServerInfo.rsa_private_key = NULL;
1797 ServerInfo.rsa_private_key_file = NULL;
1798 #endif
1799
1800 /* ServerInfo.name is not rehashable */
1801 /* ServerInfo.name = ServerInfo.name; */
1802 ServerInfo.description = NULL;
1803 DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
1804 DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
1805
1806 memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
1807 ServerInfo.specific_ipv4_vhost = 0;
1808 memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
1809 ServerInfo.specific_ipv6_vhost = 0;
1810
1811 ServerInfo.max_clients = MAXCLIENTS_MAX;
1812
1813 ServerInfo.hub = 0;
1814 ServerInfo.dns_host.sin_addr.s_addr = 0;
1815 ServerInfo.dns_host.sin_port = 0;
1816 AdminInfo.name = NULL;
1817 AdminInfo.email = NULL;
1818 AdminInfo.description = NULL;
1819
1820 log_close_all();
1821
1822 ConfigLoggingEntry.use_logging = 1;
1823
1824 ConfigChannel.disable_fake_channels = 0;
1825 ConfigChannel.restrict_channels = 0;
1826 ConfigChannel.disable_local_channels = 0;
1827 ConfigChannel.use_invex = 1;
1828 ConfigChannel.use_except = 1;
1829 ConfigChannel.use_knock = 1;
1830 ConfigChannel.knock_delay = 300;
1831 ConfigChannel.knock_delay_channel = 60;
1832 ConfigChannel.max_chans_per_user = 15;
1833 ConfigChannel.quiet_on_ban = 1;
1834 ConfigChannel.max_bans = 25;
1835 ConfigChannel.default_split_user_count = 0;
1836 ConfigChannel.default_split_server_count = 0;
1837 ConfigChannel.no_join_on_split = 0;
1838 ConfigChannel.no_create_on_split = 0;
1839
1840 ConfigServerHide.flatten_links = 0;
1841 ConfigServerHide.links_delay = 300;
1842 ConfigServerHide.hidden = 0;
1843 ConfigServerHide.disable_hidden = 0;
1844 ConfigServerHide.hide_servers = 0;
1845 DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1846 ConfigServerHide.hide_server_ips = 0;
1847
1848
1849 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1850 ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
1851 ConfigFileEntry.gline_min_cidr = 16;
1852 ConfigFileEntry.gline_min_cidr6 = 48;
1853 ConfigFileEntry.invisible_on_connect = 1;
1854 ConfigFileEntry.burst_away = 0;
1855 ConfigFileEntry.use_whois_actually = 1;
1856 ConfigFileEntry.tkline_expire_notices = 1;
1857 ConfigFileEntry.hide_spoof_ips = 1;
1858 ConfigFileEntry.ignore_bogus_ts = 0;
1859 ConfigFileEntry.disable_auth = 0;
1860 ConfigFileEntry.disable_remote = 0;
1861 ConfigFileEntry.kill_chase_time_limit = 90;
1862 ConfigFileEntry.default_floodcount = 8;
1863 ConfigFileEntry.failed_oper_notice = 1;
1864 ConfigFileEntry.dots_in_ident = 0;
1865 ConfigFileEntry.min_nonwildcard = 4;
1866 ConfigFileEntry.min_nonwildcard_simple = 3;
1867 ConfigFileEntry.max_accept = 20;
1868 ConfigFileEntry.anti_nick_flood = 0;
1869 ConfigFileEntry.max_nick_time = 20;
1870 ConfigFileEntry.max_nick_changes = 5;
1871 ConfigFileEntry.anti_spam_exit_message_time = 0;
1872 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1873 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1874 ConfigFileEntry.kline_with_reason = 1;
1875 ConfigFileEntry.kline_reason = NULL;
1876 ConfigFileEntry.warn_no_nline = 1;
1877 ConfigFileEntry.stats_o_oper_only = 0;
1878 ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1879 ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1880 ConfigFileEntry.stats_P_oper_only = 0;
1881 ConfigFileEntry.caller_id_wait = 60;
1882 ConfigFileEntry.opers_bypass_callerid = 0;
1883 ConfigFileEntry.pace_wait = 10;
1884 ConfigFileEntry.pace_wait_simple = 1;
1885 ConfigFileEntry.short_motd = 0;
1886 ConfigFileEntry.ping_cookie = 0;
1887 ConfigFileEntry.no_oper_flood = 0;
1888 ConfigFileEntry.true_no_oper_flood = 0;
1889 ConfigFileEntry.oper_pass_resv = 1;
1890 ConfigFileEntry.glines = 0;
1891 ConfigFileEntry.gline_time = 12 * 3600;
1892 ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1893 ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
1894 ConfigFileEntry.oper_only_umodes = UMODE_DEBUG;
1895 ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
1896 UMODE_OPERWALL | UMODE_WALLOP;
1897 ConfigFileEntry.use_egd = 0;
1898 ConfigFileEntry.egdpool_path = NULL;
1899 ConfigFileEntry.throttle_time = 10;
1900 }
1901
1902 static void
1903 validate_conf(void)
1904 {
1905 if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1906 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1907
1908 if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1909 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1910
1911 if (ServerInfo.network_name == NULL)
1912 DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1913
1914 if (ServerInfo.network_desc == NULL)
1915 DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1916
1917 if (ConfigFileEntry.service_name == NULL)
1918 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1919
1920 if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
1921 (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
1922 ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
1923
1924 ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
1925 }
1926
1927 /* read_conf()
1928 *
1929 * inputs - file descriptor pointing to config file to use
1930 * output - None
1931 * side effects - Read configuration file.
1932 */
1933 static void
1934 read_conf(FILE *file)
1935 {
1936 lineno = 0;
1937
1938 set_default_conf(); /* Set default values prior to conf parsing */
1939 conf_parser_ctx.pass = 1;
1940 yyparse(); /* pick up the classes first */
1941
1942 rewind(file);
1943
1944 conf_parser_ctx.pass = 2;
1945 yyparse(); /* Load the values from the conf */
1946 validate_conf(); /* Check to make sure some values are still okay. */
1947 /* Some global values are also loaded here. */
1948 check_class(); /* Make sure classes are valid */
1949 }
1950
1951 /* lookup_confhost()
1952 *
1953 * start DNS lookups of all hostnames in the conf
1954 * line and convert an IP addresses in a.b.c.d number for to IP#s.
1955 */
1956 static void
1957 lookup_confhost(struct ConfItem *conf)
1958 {
1959 struct AccessItem *aconf;
1960 struct addrinfo hints, *res;
1961
1962 aconf = map_to_conf(conf);
1963
1964 if (EmptyString(aconf->host) ||
1965 EmptyString(aconf->user))
1966 {
1967 ilog(LOG_TYPE_IRCD, "Host/server name error: (%s) (%s)",
1968 aconf->host, conf->name);
1969 return;
1970 }
1971
1972 if (strchr(aconf->host, '*') ||
1973 strchr(aconf->host, '?'))
1974 return;
1975
1976 /* Do name lookup now on hostnames given and store the
1977 * ip numbers in conf structure.
1978 */
1979 memset(&hints, 0, sizeof(hints));
1980
1981 hints.ai_family = AF_UNSPEC;
1982 hints.ai_socktype = SOCK_STREAM;
1983
1984 /* Get us ready for a bind() and don't bother doing dns lookup */
1985 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1986
1987 if (getaddrinfo(aconf->host, NULL, &hints, &res))
1988 {
1989 conf_dns_lookup(aconf);
1990 return;
1991 }
1992
1993 assert(res != NULL);
1994
1995 memcpy(&aconf->addr, res->ai_addr, res->ai_addrlen);
1996 aconf->addr.ss_len = res->ai_addrlen;
1997 aconf->addr.ss.ss_family = res->ai_family;
1998 freeaddrinfo(res);
1999 }
2000
2001 /* conf_connect_allowed()
2002 *
2003 * inputs - pointer to inaddr
2004 * - int type ipv4 or ipv6
2005 * output - BANNED or accepted
2006 * side effects - none
2007 */
2008 int
2009 conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
2010 {
2011 struct ip_entry *ip_found;
2012 struct AccessItem *aconf = find_dline_conf(addr, aftype);
2013
2014 /* DLINE exempt also gets you out of static limits/pacing... */
2015 if (aconf && (aconf->status & CONF_EXEMPTDLINE))
2016 return 0;
2017
2018 if (aconf != NULL)
2019 return BANNED_CLIENT;
2020
2021 ip_found = find_or_add_ip(addr);
2022
2023 if ((CurrentTime - ip_found->last_attempt) <
2024 ConfigFileEntry.throttle_time)
2025 {
2026 ip_found->last_attempt = CurrentTime;
2027 return TOO_FAST;
2028 }
2029
2030 ip_found->last_attempt = CurrentTime;
2031 return 0;
2032 }
2033
2034 static struct AccessItem *
2035 find_regexp_kline(const char *uhi[])
2036 {
2037 #ifdef HAVE_LIBPCRE
2038 const dlink_node *ptr = NULL;
2039
2040 DLINK_FOREACH(ptr, rkconf_items.head)
2041 {
2042 struct AccessItem *aptr = map_to_conf(ptr->data);
2043
2044 assert(aptr->regexuser);
2045 assert(aptr->regexhost);
2046
2047 if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
2048 (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
2049 !ircd_pcre_exec(aptr->regexhost, uhi[2])))
2050 return aptr;
2051 }
2052 #endif
2053 return NULL;
2054 }
2055
2056 /* find_kill()
2057 *
2058 * inputs - pointer to client structure
2059 * output - pointer to struct AccessItem if found
2060 * side effects - See if this user is klined already,
2061 * and if so, return struct AccessItem pointer
2062 */
2063 struct AccessItem *
2064 find_kill(struct Client *client_p)
2065 {
2066 struct AccessItem *aconf = NULL;
2067 const char *uhi[3];
2068
2069 uhi[0] = client_p->username;
2070 uhi[1] = client_p->host;
2071 uhi[2] = client_p->sockhost;
2072
2073 assert(client_p != NULL);
2074
2075 aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
2076 CONF_KLINE, client_p->localClient->aftype,
2077 client_p->username, NULL, 1);
2078 if (aconf == NULL)
2079 aconf = find_regexp_kline(uhi);
2080
2081 return aconf;
2082 }
2083
2084 struct AccessItem *
2085 find_gline(struct Client *client_p)
2086 {
2087 struct AccessItem *aconf;
2088
2089 assert(client_p != NULL);
2090
2091 aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
2092 CONF_GLINE, client_p->localClient->aftype,
2093 client_p->username, NULL, 1);
2094 return aconf;
2095 }
2096
2097 /* add_temp_line()
2098 *
2099 * inputs - pointer to struct ConfItem
2100 * output - none
2101 * Side effects - links in given struct ConfItem into
2102 * temporary *line link list
2103 */
2104 void
2105 add_temp_line(struct ConfItem *conf)
2106 {
2107 if (conf->type == XLINE_TYPE)
2108 {
2109 conf->flags |= CONF_FLAGS_TEMPORARY;
2110 dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
2111 }
2112 else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
2113 {
2114 conf->flags |= CONF_FLAGS_TEMPORARY;
2115 dlinkAdd(conf, make_dlink_node(), &temporary_resv);
2116 }
2117 }
2118
2119 /* cleanup_tklines()
2120 *
2121 * inputs - NONE
2122 * output - NONE
2123 * side effects - call function to expire temporary k/d lines
2124 * This is an event started off in ircd.c
2125 */
2126 void
2127 cleanup_tklines(void *notused)
2128 {
2129 hostmask_expire_temporary();
2130 expire_tklines(&temporary_xlines);
2131 expire_tklines(&temporary_resv);
2132 }
2133
2134 /* expire_tklines()
2135 *
2136 * inputs - tkline list pointer
2137 * output - NONE
2138 * side effects - expire tklines
2139 */
2140 static void
2141 expire_tklines(dlink_list *tklist)
2142 {
2143 dlink_node *ptr;
2144 dlink_node *next_ptr;
2145 struct ConfItem *conf;
2146 struct MatchItem *xconf;
2147 struct MatchItem *nconf;
2148 struct ResvChannel *cconf;
2149
2150 DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2151 {
2152 conf = ptr->data;
2153
2154 if (conf->type == XLINE_TYPE)
2155 {
2156 xconf = (struct MatchItem *)map_to_conf(conf);
2157 if (xconf->hold <= CurrentTime)
2158 {
2159 if (ConfigFileEntry.tkline_expire_notices)
2160 sendto_realops_flags(UMODE_ALL, L_ALL,
2161 "Temporary X-line for [%s] sexpired", conf->name);
2162 dlinkDelete(ptr, tklist);
2163 free_dlink_node(ptr);
2164 delete_conf_item(conf);
2165 }
2166 }
2167 else if (conf->type == NRESV_TYPE)
2168 {
2169 nconf = (struct MatchItem *)map_to_conf(conf);
2170 if (nconf->hold <= CurrentTime)
2171 {
2172 if (ConfigFileEntry.tkline_expire_notices)
2173 sendto_realops_flags(UMODE_ALL, L_ALL,
2174 "Temporary RESV for [%s] expired", conf->name);
2175 dlinkDelete(ptr, tklist);
2176 free_dlink_node(ptr);
2177 delete_conf_item(conf);
2178 }
2179 }
2180 else if (conf->type == CRESV_TYPE)
2181 {
2182 cconf = (struct ResvChannel *)map_to_conf(conf);
2183 if (cconf->hold <= CurrentTime)
2184 {
2185 if (ConfigFileEntry.tkline_expire_notices)
2186 sendto_realops_flags(UMODE_ALL, L_ALL,
2187 "Temporary RESV for [%s] expired", cconf->name);
2188 delete_channel_resv(cconf);
2189 }
2190 }
2191 }
2192 }
2193
2194 /* oper_privs_as_string()
2195 *
2196 * inputs - pointer to client_p
2197 * output - pointer to static string showing oper privs
2198 * side effects - return as string, the oper privs as derived from port
2199 */
2200 static const struct oper_privs
2201 {
2202 const unsigned int oprivs;
2203 const unsigned char c;
2204 } flag_list[] = {
2205 { OPER_FLAG_ADMIN, 'A' },
2206 { OPER_FLAG_REMOTEBAN, 'B' },
2207 { OPER_FLAG_DIE, 'D' },
2208 { OPER_FLAG_GLINE, 'G' },
2209 { OPER_FLAG_REHASH, 'H' },
2210 { OPER_FLAG_K, 'K' },
2211 { OPER_FLAG_OPERWALL, 'L' },
2212 { OPER_FLAG_N, 'N' },
2213 { OPER_FLAG_GLOBAL_KILL, 'O' },
2214 { OPER_FLAG_REMOTE, 'R' },
2215 { OPER_FLAG_OPER_SPY, 'S' },
2216 { OPER_FLAG_UNKLINE, 'U' },
2217 { OPER_FLAG_X, 'X' },
2218 { 0, '\0' }
2219 };
2220
2221 char *
2222 oper_privs_as_string(const unsigned int port)
2223 {
2224 static char privs_out[16];
2225 char *privs_ptr = privs_out;
2226 unsigned int i = 0;
2227
2228 for (; flag_list[i].oprivs; ++i)
2229 {
2230 if (port & flag_list[i].oprivs)
2231 *privs_ptr++ = flag_list[i].c;
2232 else
2233 *privs_ptr++ = ToLowerTab[flag_list[i].c];
2234 }
2235
2236 *privs_ptr = '\0';
2237
2238 return privs_out;
2239 }
2240
2241 /*
2242 * Input: A client to find the active oper{} name for.
2243 * Output: The nick!user@host{oper} of the oper.
2244 * "oper" is server name for remote opers
2245 * Side effects: None.
2246 */
2247 const char *
2248 get_oper_name(const struct Client *client_p)
2249 {
2250 dlink_node *cnode = NULL;
2251 /* +5 for !,@,{,} and null */
2252 static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
2253
2254 if (MyConnect(client_p))
2255 {
2256 if ((cnode = client_p->localClient->confs.head))
2257 {
2258 struct ConfItem *conf = cnode->data;
2259 const struct AccessItem *aconf = map_to_conf(conf);
2260
2261 if (IsConfOperator(aconf))
2262 {
2263 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2264 client_p->username, client_p->host, conf->name);
2265 return buffer;
2266 }
2267 }
2268
2269 /* Probably should assert here for now. If there is an oper out there
2270 * with no oper{} conf attached, it would be good for us to know...
2271 */
2272 assert(0); /* Oper without oper conf! */
2273 }
2274
2275 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2276 client_p->username, client_p->host, client_p->servptr->name);
2277 return buffer;
2278 }
2279
2280 /* read_conf_files()
2281 *
2282 * inputs - cold start YES or NO
2283 * output - none
2284 * side effects - read all conf files needed, ircd.conf kline.conf etc.
2285 */
2286 void
2287 read_conf_files(int cold)
2288 {
2289 const char *filename;
2290 char chanmodes[32];
2291 char chanlimit[32];
2292
2293 conf_parser_ctx.boot = cold;
2294 filename = get_conf_name(CONF_TYPE);
2295
2296 /* We need to know the initial filename for the yyerror() to report
2297 FIXME: The full path is in conffilenamebuf first time since we
2298 dont know anything else
2299
2300 - Gozem 2002-07-21
2301 */
2302 strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2303
2304 if ((conf_parser_ctx.conf_file = fopen(filename, "r")) == NULL)
2305 {
2306 if (cold)
2307 {
2308 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2309 filename, strerror(errno));
2310 exit(-1);
2311 }
2312 else
2313 {
2314 sendto_realops_flags(UMODE_ALL, L_ALL,
2315 "Unable to read configuration file '%s': %s",
2316 filename, strerror(errno));
2317 return;
2318 }
2319 }
2320
2321 if (!cold)
2322 clear_out_old_conf();
2323
2324 read_conf(conf_parser_ctx.conf_file);
2325 fclose(conf_parser_ctx.conf_file);
2326
2327 add_isupport("NETWORK", ServerInfo.network_name, -1);
2328 snprintf(chanmodes, sizeof(chanmodes), "b%s%s:%d",
2329 ConfigChannel.use_except ? "e" : "",
2330 ConfigChannel.use_invex ? "I" : "", ConfigChannel.max_bans);
2331 add_isupport("MAXLIST", chanmodes, -1);
2332 add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2333
2334 if (ConfigChannel.disable_local_channels)
2335 add_isupport("CHANTYPES", "#", -1);
2336 else
2337 add_isupport("CHANTYPES", "#&", -1);
2338
2339 snprintf(chanlimit, sizeof(chanlimit), "%s:%d",
2340 ConfigChannel.disable_local_channels ? "#" : "#&",
2341 ConfigChannel.max_chans_per_user);
2342 add_isupport("CHANLIMIT", chanlimit, -1);
2343 snprintf(chanmodes, sizeof(chanmodes), "%s%s%s",
2344 ConfigChannel.use_except ? "e" : "",
2345 ConfigChannel.use_invex ? "I" : "", "b,k,l,imnprstORS");
2346 add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
2347
2348 if (ConfigChannel.use_except)
2349 add_isupport("EXCEPTS", "e", -1);
2350 if (ConfigChannel.use_invex)
2351 add_isupport("INVEX", "I", -1);
2352 add_isupport("CHANMODES", chanmodes, -1);
2353
2354 /*
2355 * message_locale may have changed. rebuild isupport since it relies
2356 * on strlen(form_str(RPL_ISUPPORT))
2357 */
2358 rebuild_isupport_message_line();
2359
2360 #ifdef HAVE_LIBPCRE
2361 parse_conf_file(RKLINE_TYPE, cold);
2362 parse_conf_file(RXLINE_TYPE, cold);
2363 #endif
2364 parse_conf_file(KLINE_TYPE, cold);
2365 parse_conf_file(DLINE_TYPE, cold);
2366 parse_conf_file(XLINE_TYPE, cold);
2367 parse_conf_file(NRESV_TYPE, cold);
2368 parse_conf_file(CRESV_TYPE, cold);
2369 }
2370
2371 /* parse_conf_file()
2372 *
2373 * inputs - type of conf file to parse
2374 * output - none
2375 * side effects - conf file for givenconf type is opened and read then parsed
2376 */
2377 static void
2378 parse_conf_file(int type, int cold)
2379 {
2380 FILE *file = NULL;
2381 const char *filename = get_conf_name(type);
2382
2383 if ((file = fopen(filename, "r")) == NULL)
2384 {
2385 if (cold)
2386 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2387 filename, strerror(errno));
2388 else
2389 sendto_realops_flags(UMODE_ALL, L_ALL,
2390 "Unable to read configuration file '%s': %s",
2391 filename, strerror(errno));
2392 }
2393 else
2394 {
2395 parse_csv_file(file, type);
2396 fclose(file);
2397 }
2398 }
2399
2400 /* clear_out_old_conf()
2401 *
2402 * inputs - none
2403 * output - none
2404 * side effects - Clear out the old configuration
2405 */
2406 static void
2407 clear_out_old_conf(void)
2408 {
2409 dlink_node *ptr = NULL, *next_ptr = NULL;
2410 struct ConfItem *conf;
2411 struct AccessItem *aconf;
2412 struct ClassItem *cltmp;
2413 struct MatchItem *match_item;
2414 dlink_list *free_items [] = {
2415 &server_items, &oconf_items,
2416 &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2417 &nresv_items, &cluster_items, &gdeny_items, &service_items, NULL
2418 };
2419
2420 dlink_list ** iterator = free_items; /* C is dumb */
2421
2422 /* We only need to free anything allocated by yyparse() here.
2423 * Resetting structs, etc, is taken care of by set_default_conf().
2424 */
2425
2426 for (; *iterator != NULL; iterator++)
2427 {
2428 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2429 {
2430 conf = ptr->data;
2431 /* XXX This is less than pretty */
2432 if (conf->type == SERVER_TYPE)
2433 {
2434 aconf = map_to_conf(conf);
2435
2436 if (aconf->clients != 0)
2437 {
2438 SetConfIllegal(aconf);
2439 dlinkDelete(&conf->node, &server_items);
2440 }
2441 else
2442 {
2443 delete_conf_item(conf);
2444 }
2445 }
2446 else if (conf->type == OPER_TYPE)
2447 {
2448 aconf = map_to_conf(conf);
2449
2450 if (aconf->clients != 0)
2451 {
2452 SetConfIllegal(aconf);
2453 dlinkDelete(&conf->node, &oconf_items);
2454 }
2455 else
2456 {
2457 delete_conf_item(conf);
2458 }
2459 }
2460 else if (conf->type == XLINE_TYPE ||
2461 conf->type == RXLINE_TYPE ||
2462 conf->type == RKLINE_TYPE)
2463 {
2464 /* temporary (r)xlines are also on
2465 * the (r)xconf items list */
2466 if (conf->flags & CONF_FLAGS_TEMPORARY)
2467 continue;
2468
2469 delete_conf_item(conf);
2470 }
2471 else
2472 {
2473 delete_conf_item(conf);
2474 }
2475 }
2476 }
2477
2478 /*
2479 * don't delete the class table, rather mark all entries
2480 * for deletion. The table is cleaned up by check_class. - avalon
2481 */
2482 DLINK_FOREACH(ptr, class_items.head)
2483 {
2484 cltmp = map_to_conf(ptr->data);
2485
2486 if (ptr != class_items.tail) /* never mark the "default" class */
2487 cltmp->active = 0;
2488 }
2489
2490 clear_out_address_conf();
2491
2492 /* clean out module paths */
2493 mod_clear_paths();
2494
2495 /* clean out ServerInfo */
2496 MyFree(ServerInfo.description);
2497 ServerInfo.description = NULL;
2498 MyFree(ServerInfo.network_name);
2499 ServerInfo.network_name = NULL;
2500 MyFree(ServerInfo.network_desc);
2501 ServerInfo.network_desc = NULL;
2502 MyFree(ConfigFileEntry.egdpool_path);
2503 ConfigFileEntry.egdpool_path = NULL;
2504 #ifdef HAVE_LIBCRYPTO
2505 if (ServerInfo.rsa_private_key != NULL)
2506 {
2507 RSA_free(ServerInfo.rsa_private_key);
2508 ServerInfo.rsa_private_key = NULL;
2509 }
2510
2511 MyFree(ServerInfo.rsa_private_key_file);
2512 ServerInfo.rsa_private_key_file = NULL;
2513
2514 if (ServerInfo.server_ctx)
2515 SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|
2516 SSL_OP_NO_SSLv3|
2517 SSL_OP_NO_TLSv1);
2518 if (ServerInfo.client_ctx)
2519 SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|
2520 SSL_OP_NO_SSLv3|
2521 SSL_OP_NO_TLSv1);
2522 #endif
2523
2524 /* clean out old resvs from the conf */
2525 clear_conf_resv();
2526
2527 /* clean out AdminInfo */
2528 MyFree(AdminInfo.name);
2529 AdminInfo.name = NULL;
2530 MyFree(AdminInfo.email);
2531 AdminInfo.email = NULL;
2532 MyFree(AdminInfo.description);
2533 AdminInfo.description = NULL;
2534
2535 /* operator{} and class{} blocks are freed above */
2536 /* clean out listeners */
2537 close_listeners();
2538
2539 /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2540 * exempt{} and gecos{} blocks are freed above too
2541 */
2542
2543 /* clean out general */
2544 MyFree(ConfigFileEntry.service_name);
2545 ConfigFileEntry.service_name = NULL;
2546
2547 delete_isupport("INVEX");
2548 delete_isupport("EXCEPTS");
2549 }
2550
2551 /* flush_deleted_I_P()
2552 *
2553 * inputs - none
2554 * output - none
2555 * side effects - This function removes I/P conf items
2556 */
2557 static void
2558 flush_deleted_I_P(void)
2559 {
2560 dlink_node *ptr;
2561 dlink_node *next_ptr;
2562 struct ConfItem *conf;
2563 struct AccessItem *aconf;
2564 dlink_list * free_items [] = {
2565 &server_items, &oconf_items, NULL
2566 };
2567 dlink_list ** iterator = free_items; /* C is dumb */
2568
2569 /* flush out deleted I and P lines
2570 * although still in use.
2571 */
2572 for (; *iterator != NULL; iterator++)
2573 {
2574 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2575 {
2576 conf = ptr->data;
2577 aconf = (struct AccessItem *)map_to_conf(conf);
2578
2579 if (IsConfIllegal(aconf))
2580 {
2581 dlinkDelete(ptr, *iterator);
2582
2583 if (aconf->clients == 0)
2584 delete_conf_item(conf);
2585 }
2586 }
2587 }
2588 }
2589
2590 /* get_conf_name()
2591 *
2592 * inputs - type of conf file to return name of file for
2593 * output - pointer to filename for type of conf
2594 * side effects - none
2595 */
2596 const char *
2597 get_conf_name(ConfType type)
2598 {
2599 switch (type)
2600 {
2601 case CONF_TYPE:
2602 return ConfigFileEntry.configfile;
2603 break;
2604 case KLINE_TYPE:
2605 return ConfigFileEntry.klinefile;
2606 break;
2607 case RKLINE_TYPE:
2608 return ConfigFileEntry.rklinefile;
2609 break;
2610 case DLINE_TYPE:
2611 return ConfigFileEntry.dlinefile;
2612 break;
2613 case XLINE_TYPE:
2614 return ConfigFileEntry.xlinefile;
2615 break;
2616 case RXLINE_TYPE:
2617 return ConfigFileEntry.rxlinefile;
2618 break;
2619 case CRESV_TYPE:
2620 return ConfigFileEntry.cresvfile;
2621 break;
2622 case NRESV_TYPE:
2623 return ConfigFileEntry.nresvfile;
2624 break;
2625 case GLINE_TYPE:
2626 return ConfigFileEntry.glinefile;
2627 break;
2628
2629 default:
2630 return NULL; /* This should NEVER HAPPEN since we call this function
2631 only with the above values, this will cause us to core
2632 at some point if this happens so we know where it was */
2633 }
2634 }
2635
2636 #define BAD_PING (-1)
2637
2638 /* get_conf_ping()
2639 *
2640 * inputs - pointer to struct AccessItem
2641 * - pointer to a variable that receives ping warning time
2642 * output - ping frequency
2643 * side effects - NONE
2644 */
2645 static int
2646 get_conf_ping(struct ConfItem *conf, int *pingwarn)
2647 {
2648 struct ClassItem *aclass;
2649 struct AccessItem *aconf;
2650
2651 if (conf != NULL)
2652 {
2653 aconf = (struct AccessItem *)map_to_conf(conf);
2654 if (aconf->class_ptr != NULL)
2655 {
2656 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2657 *pingwarn = aclass->ping_warning;
2658 return aclass->ping_freq;
2659 }
2660 }
2661
2662 return BAD_PING;
2663 }
2664
2665 /* get_client_class()
2666 *
2667 * inputs - pointer to client struct
2668 * output - pointer to name of class
2669 * side effects - NONE
2670 */
2671 const char *
2672 get_client_class(struct Client *target_p)
2673 {
2674 dlink_node *cnode = NULL;
2675 struct AccessItem *aconf = NULL;
2676
2677 assert(!IsMe(target_p));
2678
2679 if ((cnode = target_p->localClient->confs.head))
2680 {
2681 struct ConfItem *conf = cnode->data;
2682
2683 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2684 (conf->type == OPER_TYPE));
2685
2686 aconf = map_to_conf(conf);
2687 if (aconf->class_ptr != NULL)
2688 return aconf->class_ptr->name;
2689 }
2690
2691 return "default";
2692 }
2693
2694 /* get_client_ping()
2695 *
2696 * inputs - pointer to client struct
2697 * - pointer to a variable that receives ping warning time
2698 * output - ping frequency
2699 * side effects - NONE
2700 */
2701 int
2702 get_client_ping(struct Client *target_p, int *pingwarn)
2703 {
2704 int ping = 0;
2705 dlink_node *cnode = NULL;
2706
2707 if ((cnode = target_p->localClient->confs.head))
2708 {
2709 struct ConfItem *conf = cnode->data;
2710
2711 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2712 (conf->type == OPER_TYPE));
2713
2714 ping = get_conf_ping(conf, pingwarn);
2715 if (ping > 0)
2716 return ping;
2717 }
2718
2719 *pingwarn = 0;
2720 return DEFAULT_PINGFREQUENCY;
2721 }
2722
2723 /* find_class()
2724 *
2725 * inputs - string name of class
2726 * output - corresponding Class pointer
2727 * side effects - NONE
2728 */
2729 struct ConfItem *
2730 find_class(const char *classname)
2731 {
2732 struct ConfItem *conf;
2733
2734 if ((conf = find_exact_name_conf(CLASS_TYPE, NULL, classname, NULL, NULL)) != NULL)
2735 return conf;
2736
2737 return class_default;
2738 }
2739
2740 /* check_class()
2741 *
2742 * inputs - NONE
2743 * output - NONE
2744 * side effects -
2745 */
2746 void
2747 check_class(void)
2748 {
2749 dlink_node *ptr = NULL, *next_ptr = NULL;
2750
2751 DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2752 {
2753 struct ClassItem *aclass = map_to_conf(ptr->data);
2754
2755 if (!aclass->active && !aclass->curr_user_count)
2756 {
2757 destroy_cidr_class(aclass);
2758 delete_conf_item(ptr->data);
2759 }
2760 }
2761 }
2762
2763 /* init_class()
2764 *
2765 * inputs - NONE
2766 * output - NONE
2767 * side effects -
2768 */
2769 void
2770 init_class(void)
2771 {
2772 struct ClassItem *aclass;
2773
2774 class_default = make_conf_item(CLASS_TYPE);
2775
2776 aclass = map_to_conf(class_default);
2777 aclass->active = 1;
2778 DupString(class_default->name, "default");
2779 aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
2780 aclass->ping_freq = DEFAULT_PINGFREQUENCY;
2781 aclass->max_total = MAXIMUM_LINKS_DEFAULT;
2782 aclass->max_sendq = DEFAULT_SENDQ;
2783
2784 client_check_cb = register_callback("check_client", check_client);
2785 }
2786
2787 /* get_sendq()
2788 *
2789 * inputs - pointer to client
2790 * output - sendq for this client as found from its class
2791 * side effects - NONE
2792 */
2793 unsigned int
2794 get_sendq(struct Client *client_p)
2795 {
2796 unsigned int sendq = DEFAULT_SENDQ;
2797 dlink_node *cnode;
2798 struct ConfItem *class_conf;
2799 struct ClassItem *aclass;
2800 struct AccessItem *aconf;
2801
2802 assert(!IsMe(client_p));
2803
2804 if ((cnode = client_p->localClient->confs.head))
2805 {
2806 struct ConfItem *conf = cnode->data;
2807
2808 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2809 (conf->type == OPER_TYPE));
2810
2811 aconf = map_to_conf(conf);
2812
2813 if ((class_conf = aconf->class_ptr) == NULL)
2814 return DEFAULT_SENDQ; /* TBV: shouldn't be possible at all */
2815
2816 aclass = map_to_conf(class_conf);
2817 sendq = aclass->max_sendq;
2818 return sendq;
2819 }
2820
2821 /* XXX return a default?
2822 * if here, then there wasn't an attached conf with a sendq
2823 * that is very bad -Dianora
2824 */
2825 return DEFAULT_SENDQ;
2826 }
2827
2828 /* conf_add_class_to_conf()
2829 *
2830 * inputs - pointer to config item
2831 * output - NONE
2832 * side effects - Add a class pointer to a conf
2833 */
2834 void
2835 conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
2836 {
2837 struct AccessItem *aconf = map_to_conf(conf);
2838 struct ClassItem *class = NULL;
2839
2840 if (class_name == NULL)
2841 {
2842 aconf->class_ptr = class_default;
2843
2844 if (conf->type == CLIENT_TYPE)
2845 sendto_realops_flags(UMODE_ALL, L_ALL,
2846 "Warning *** Defaulting to default class for %s@%s",
2847 aconf->user, aconf->host);
2848 else
2849 sendto_realops_flags(UMODE_ALL, L_ALL,
2850 "Warning *** Defaulting to default class for %s",
2851 conf->name);
2852 }
2853 else
2854 aconf->class_ptr = find_class(class_name);
2855
2856 if (aconf->class_ptr)
2857 class = map_to_conf(aconf->class_ptr);
2858
2859 if (aconf->class_ptr == NULL || !class->active)
2860 {
2861 if (conf->type == CLIENT_TYPE)
2862 sendto_realops_flags(UMODE_ALL, L_ALL,
2863 "Warning *** Defaulting to default class for %s@%s",
2864 aconf->user, aconf->host);
2865 else
2866 sendto_realops_flags(UMODE_ALL, L_ALL,
2867 "Warning *** Defaulting to default class for %s",
2868 conf->name);
2869 aconf->class_ptr = class_default;
2870 }
2871 }
2872
2873 /* conf_add_server()
2874 *
2875 * inputs - pointer to config item
2876 * - pointer to link count already on this conf
2877 * output - NONE
2878 * side effects - Add a connect block
2879 */
2880 int
2881 conf_add_server(struct ConfItem *conf, const char *class_name)
2882 {
2883 struct AccessItem *aconf = map_to_conf(conf);
2884
2885 conf_add_class_to_conf(conf, class_name);
2886
2887 if (!aconf->host || !conf->name)
2888 {
2889 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
2890 ilog(LOG_TYPE_IRCD, "Bad connect block");
2891 return -1;
2892 }
2893
2894 if (EmptyString(aconf->passwd))
2895 {
2896 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
2897 conf->name);
2898 ilog(LOG_TYPE_IRCD, "Bad connect block, host %s", conf->name);
2899 return -1;
2900 }
2901
2902 lookup_confhost(conf);
2903
2904 return 0;
2905 }
2906
2907 /* yyerror()
2908 *
2909 * inputs - message from parser
2910 * output - NONE
2911 * side effects - message to opers and log file entry is made
2912 */
2913 void
2914 yyerror(const char *msg)
2915 {
2916 char newlinebuf[IRCD_BUFSIZE];
2917
2918 if (conf_parser_ctx.pass != 1)
2919 return;
2920
2921 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
2922 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
2923 conffilebuf, lineno + 1, msg, newlinebuf);
2924 ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s",
2925 conffilebuf, lineno + 1, msg, newlinebuf);
2926 }
2927
2928 /*
2929 * valid_tkline()
2930 *
2931 * inputs - pointer to ascii string to check
2932 * - whether the specified time is in seconds or minutes
2933 * output - -1 not enough parameters
2934 * - 0 if not an integer number, else the number
2935 * side effects - none
2936 * Originally written by Dianora (Diane, db@db.net)
2937 */
2938 time_t
2939 valid_tkline(const char *p, int minutes)
2940 {
2941 time_t result = 0;
2942
2943 for (; *p; ++p)
2944 {
2945 if (!IsDigit(*p))
2946 return 0;
2947
2948 result *= 10;
2949 result += ((*p) & 0xF);
2950 }
2951
2952 /*
2953 * In the degenerate case where oper does a /quote kline 0 user@host :reason
2954 * i.e. they specifically use 0, I am going to return 1 instead
2955 * as a return value of non-zero is used to flag it as a temporary kline
2956 */
2957 if (result == 0)
2958 result = 1;
2959
2960 /*
2961 * If the incoming time is in seconds convert it to minutes for the purpose
2962 * of this calculation
2963 */
2964 if (!minutes)
2965 result = result / (time_t)60;
2966
2967 if (result > MAX_TDKLINE_TIME)
2968 result = MAX_TDKLINE_TIME;
2969
2970 result = result * (time_t)60; /* turn it into seconds */
2971
2972 return result;
2973 }
2974
2975 /* valid_wild_card()
2976 *
2977 * input - pointer to client
2978 * - int flag, 0 for no warning oper 1 for warning oper
2979 * - count of following varargs to check
2980 * output - 0 if not valid, 1 if valid
2981 * side effects - NOTICE is given to source_p if warn is 1
2982 */
2983 int
2984 valid_wild_card(struct Client *source_p, int warn, int count, ...)
2985 {
2986 char *p;
2987 char tmpch;
2988 int nonwild = 0;
2989 va_list args;
2990
2991 /*
2992 * Now we must check the user and host to make sure there
2993 * are at least NONWILDCHARS non-wildcard characters in
2994 * them, otherwise assume they are attempting to kline
2995 * *@* or some variant of that. This code will also catch
2996 * people attempting to kline *@*.tld, as long as NONWILDCHARS
2997 * is greater than 3. In that case, there are only 3 non-wild
2998 * characters (tld), so if NONWILDCHARS is 4, the kline will
2999 * be disallowed.
3000 * -wnder
3001 */
3002
3003 va_start(args, count);
3004
3005 while (count--)
3006 {
3007 p = va_arg(args, char *);
3008 if (p == NULL)
3009 continue;
3010
3011 while ((tmpch = *p++))
3012 {
3013 if (!IsKWildChar(tmpch))
3014 {
3015 /*
3016 * If we find enough non-wild characters, we can
3017 * break - no point in searching further.
3018 */
3019 if (++nonwild >= ConfigFileEntry.min_nonwildcard)
3020 return 1;
3021 }
3022 }
3023 }
3024
3025 if (warn)
3026 sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
3027 me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
3028 return 0;
3029 }
3030
3031 /* XXX should this go into a separate file ? -Dianora */
3032 /* parse_aline
3033 *
3034 * input - pointer to cmd name being used
3035 * - pointer to client using cmd
3036 * - parc parameter count
3037 * - parv[] list of parameters to parse
3038 * - parse_flags bit map of things to test
3039 * - pointer to user or string to parse into
3040 * - pointer to host or NULL to parse into if non NULL
3041 * - pointer to optional tkline time or NULL
3042 * - pointer to target_server to parse into if non NULL
3043 * - pointer to reason to parse into
3044 *
3045 * output - 1 if valid, -1 if not valid
3046 * side effects - A generalised k/d/x etc. line parser,
3047 * "ALINE [time] user@host|string [ON] target :reason"
3048 * will parse returning a parsed user, host if
3049 * h_p pointer is non NULL, string otherwise.
3050 * if tkline_time pointer is non NULL a tk line will be set
3051 * to non zero if found.
3052 * if tkline_time pointer is NULL and tk line is found,
3053 * error is reported.
3054 * if target_server is NULL and an "ON" is found error
3055 * is reported.
3056 * if reason pointer is NULL ignore pointer,
3057 * this allows use of parse_a_line in unkline etc.
3058 *
3059 * - Dianora
3060 */
3061 int
3062 parse_aline(const char *cmd, struct Client *source_p,
3063 int parc, char **parv,
3064 int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
3065 char **target_server, char **reason)
3066 {
3067 int found_tkline_time=0;
3068 static char def_reason[] = "No Reason";
3069 static char user[USERLEN*4+1];
3070 static char host[HOSTLEN*4+1];
3071
3072 parv++;
3073 parc--;
3074
3075 found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3076
3077 if (found_tkline_time != 0)
3078 {
3079 parv++;
3080 parc--;
3081
3082 if (tkline_time != NULL)
3083 *tkline_time = found_tkline_time;
3084 else
3085 {
3086 sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3087 me.name, source_p->name, cmd);
3088 return -1;
3089 }
3090 }
3091
3092 if (parc == 0)
3093 {
3094 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3095 me.name, source_p->name, cmd);
3096 return -1;
3097 }
3098
3099 if (h_p == NULL)
3100 *up_p = *parv;
3101 else
3102 {
3103 if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3104 return -1;
3105
3106 *up_p = user;
3107 *h_p = host;
3108 }
3109
3110 parc--;
3111 parv++;
3112
3113 if (parc != 0)
3114 {
3115 if (irccmp(*parv, "ON") == 0)
3116 {
3117 parc--;
3118 parv++;
3119
3120 if (target_server == NULL)
3121 {
3122 sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3123 me.name, source_p->name, cmd);
3124 return -1;
3125 }
3126
3127 if (!HasOFlag(source_p, OPER_FLAG_REMOTEBAN))
3128 {
3129 sendto_one(source_p, form_str(ERR_NOPRIVS),
3130 me.name, source_p->name, "remoteban");
3131 return -1;
3132 }
3133
3134 if (parc == 0 || EmptyString(*parv))
3135 {
3136 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3137 me.name, source_p->name, cmd);
3138 return -1;
3139 }
3140
3141 *target_server = *parv;
3142 parc--;
3143 parv++;
3144 }
3145 else
3146 {
3147 /* Make sure target_server *is* NULL if no ON server found
3148 * caller probably NULL'd it first, but no harm to do it again -db
3149 */
3150 if (target_server != NULL)
3151 *target_server = NULL;
3152 }
3153 }
3154
3155 if (h_p != NULL)
3156 {
3157 if (strchr(user, '!') != NULL)
3158 {
3159 sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3160 me.name, source_p->name);
3161 return -1;
3162 }
3163
3164 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 2, *up_p, *h_p))
3165 return -1;
3166 }
3167 else
3168 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 1, *up_p))
3169 return -1;
3170
3171 if (reason != NULL)
3172 {
3173 if (parc != 0 && !EmptyString(*parv))
3174 {
3175 *reason = *parv;
3176 if (!valid_comment(source_p, *reason, 1))
3177 return -1;
3178 }
3179 else
3180 *reason = def_reason;
3181 }
3182
3183 return 1;
3184 }
3185
3186 /* find_user_host()
3187 *
3188 * inputs - pointer to client placing kline
3189 * - pointer to user_host_or_nick
3190 * - pointer to user buffer
3191 * - pointer to host buffer
3192 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3193 * side effects -
3194 */
3195 static int
3196 find_user_host(struct Client *source_p, char *user_host_or_nick,
3197 char *luser, char *lhost, unsigned int flags)
3198 {
3199 struct Client *target_p = NULL;
3200 char *hostp = NULL;
3201
3202 if (lhost == NULL)
3203 {
3204 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3205 return 1;
3206 }
3207
3208 if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3209 {
3210 /* Explicit user@host mask given */
3211
3212 if (hostp != NULL) /* I'm a little user@host */
3213 {
3214 *(hostp++) = '\0'; /* short and squat */
3215 if (*user_host_or_nick)
3216 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3217 else
3218 strcpy(luser, "*");
3219 if (*hostp)
3220 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3221 else
3222 strcpy(lhost, "*");
3223 }
3224 else
3225 {
3226 luser[0] = '*'; /* no @ found, assume its *@somehost */
3227 luser[1] = '\0';
3228 strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3229 }
3230
3231 return 1;
3232 }
3233 else if (!(flags & NOUSERLOOKUP))
3234 {
3235 /* Try to find user@host mask from nick */
3236 /* Okay to use source_p as the first param, because source_p == client_p */
3237 if ((target_p =
3238 find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3239 return 0;
3240
3241 if (IsExemptKline(target_p))
3242 {
3243 if (!IsServer(source_p))
3244 sendto_one(source_p,
3245 ":%s NOTICE %s :%s is E-lined",
3246 me.name, source_p->name, target_p->name);
3247 return 0;
3248 }
3249
3250 /*
3251 * turn the "user" bit into "*user", blow away '~'
3252 * if found in original user name (non-idented)
3253 */
3254 strlcpy(luser, target_p->username, USERLEN*4 + 1);
3255
3256 if (target_p->username[0] == '~')
3257 luser[0] = '*';
3258
3259 if (target_p->sockhost[0] == '\0' ||
3260 (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3261 strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3262 else
3263 strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3264 return 1;
3265 }
3266
3267 return 0;
3268 }
3269
3270 /* valid_comment()
3271 *
3272 * inputs - pointer to client
3273 * - pointer to comment
3274 * output - 0 if no valid comment,
3275 * - 1 if valid
3276 * side effects - truncates reason where necessary
3277 */
3278 int
3279 valid_comment(struct Client *source_p, char *comment, int warn)
3280 {
3281 if (strchr(comment, '"'))
3282 {
3283 if (warn)
3284 sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3285 me.name, source_p->name);
3286 return 0;
3287 }
3288
3289 if (strlen(comment) > REASONLEN)
3290 comment[REASONLEN-1] = '\0';
3291
3292 return 1;
3293 }
3294
3295 /* match_conf_password()
3296 *
3297 * inputs - pointer to given password
3298 * - pointer to Conf
3299 * output - 1 or 0 if match
3300 * side effects - none
3301 */
3302 int
3303 match_conf_password(const char *password, const struct AccessItem *aconf)
3304 {
3305 const char *encr = NULL;
3306
3307 if (EmptyString(password) || EmptyString(aconf->passwd))
3308 return 0;
3309
3310 if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3311 encr = crypt(password, aconf->passwd);
3312 else
3313 encr = password;
3314
3315 return !strcmp(encr, aconf->passwd);
3316 }
3317
3318 /*
3319 * cluster_a_line
3320 *
3321 * inputs - client sending the cluster
3322 * - command name "KLINE" "XLINE" etc.
3323 * - capab -- CAP_KLN etc. from s_serv.h
3324 * - cluster type -- CLUSTER_KLINE etc. from conf.h
3325 * - pattern and args to send along
3326 * output - none
3327 * side effects - Take source_p send the pattern with args given
3328 * along to all servers that match capab and cluster type
3329 */
3330 void
3331 cluster_a_line(struct Client *source_p, const char *command,
3332 int capab, int cluster_type, const char *pattern, ...)
3333 {
3334 va_list args;
3335 char buffer[IRCD_BUFSIZE];
3336 const dlink_node *ptr = NULL;
3337
3338 va_start(args, pattern);
3339 vsnprintf(buffer, sizeof(buffer), pattern, args);
3340 va_end(args);
3341
3342 DLINK_FOREACH(ptr, cluster_items.head)
3343 {
3344 const struct ConfItem *conf = ptr->data;
3345
3346 if (conf->flags & cluster_type)
3347 sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3348 "%s %s %s", command, conf->name, buffer);
3349 }
3350 }
3351
3352 /*
3353 * split_nuh
3354 *
3355 * inputs - pointer to original mask (modified in place)
3356 * - pointer to pointer where nick should go
3357 * - pointer to pointer where user should go
3358 * - pointer to pointer where host should go
3359 * output - NONE
3360 * side effects - mask is modified in place
3361 * If nick pointer is NULL, ignore writing to it
3362 * this allows us to use this function elsewhere.
3363 *
3364 * mask nick user host
3365 * ---------------------- ------- ------- ------
3366 * Dianora!db@db.net Dianora db db.net
3367 * Dianora Dianora * *
3368 * db.net * * db.net
3369 * OR if nick pointer is NULL
3370 * Dianora - * Dianora
3371 * Dianora! Dianora * *
3372 * Dianora!@ Dianora * *
3373 * Dianora!db Dianora db *
3374 * Dianora!@db.net Dianora * db.net
3375 * db@db.net * db db.net
3376 * !@ * * *
3377 * @ * * *
3378 * ! * * *
3379 */
3380 void
3381 split_nuh(struct split_nuh_item *const iptr)
3382 {
3383 char *p = NULL, *q = NULL;
3384
3385 if (iptr->nickptr)
3386 strlcpy(iptr->nickptr, "*", iptr->nicksize);
3387 if (iptr->userptr)
3388 strlcpy(iptr->userptr, "*", iptr->usersize);
3389 if (iptr->hostptr)
3390 strlcpy(iptr->hostptr, "*", iptr->hostsize);
3391
3392 if ((p = strchr(iptr->nuhmask, '!')))
3393 {
3394 *p = '\0';
3395
3396 if (iptr->nickptr && *iptr->nuhmask != '\0')
3397 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3398
3399 if ((q = strchr(++p, '@'))) {
3400 *q++ = '\0';
3401
3402 if (*p != '\0')
3403 strlcpy(iptr->userptr, p, iptr->usersize);
3404
3405 if (*q != '\0')
3406 strlcpy(iptr->hostptr, q, iptr->hostsize);
3407 }
3408 else
3409 {
3410 if (*p != '\0')
3411 strlcpy(iptr->userptr, p, iptr->usersize);
3412 }
3413 }
3414 else
3415 {
3416 /* No ! found so lets look for a user@host */
3417 if ((p = strchr(iptr->nuhmask, '@')))
3418 {
3419 /* if found a @ */
3420 *p++ = '\0';
3421
3422 if (*iptr->nuhmask != '\0')
3423 strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
3424
3425 if (*p != '\0')
3426 strlcpy(iptr->hostptr, p, iptr->hostsize);
3427 }
3428 else
3429 {
3430 /* no @ found */
3431 if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
3432 strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
3433 else
3434 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3435 }
3436 }
3437 }
3438
3439 /*
3440 * flags_to_ascii
3441 *
3442 * inputs - flags is a bitmask
3443 * - pointer to table of ascii letters corresponding
3444 * to each bit
3445 * - flag 1 for convert ToLower if bit missing
3446 * 0 if ignore.
3447 * output - none
3448 * side effects - string pointed to by p has bitmap chars written to it
3449 */
3450 static void
3451 flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3452 int lowerit)
3453 {
3454 unsigned int mask = 1;
3455 int i = 0;
3456
3457 for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3458 {
3459 if (flags & mask)
3460 *p++ = bit_table[i];
3461 else if (lowerit)
3462 *p++ = ToLower(bit_table[i]);
3463 }
3464 *p = '\0';
3465 }
3466
3467 /*
3468 * cidr_limit_reached
3469 *
3470 * inputs - int flag allowing over_rule of limits
3471 * - pointer to the ip to be added
3472 * - pointer to the class
3473 * output - non zero if limit reached
3474 * 0 if limit not reached
3475 * side effects -
3476 */
3477 static int
3478 cidr_limit_reached(int over_rule,
3479 struct irc_ssaddr *ip, struct ClassItem *aclass)
3480 {
3481 dlink_node *ptr = NULL;
3482 struct CidrItem *cidr;
3483
3484 if (aclass->number_per_cidr <= 0)
3485 return 0;
3486
3487 if (ip->ss.ss_family == AF_INET)
3488 {
3489 if (aclass->cidr_bitlen_ipv4 <= 0)
3490 return 0;
3491
3492 DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3493 {
3494 cidr = ptr->data;
3495 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3496 {
3497 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3498 return -1;
3499 cidr->number_on_this_cidr++;
3500 return 0;
3501 }
3502 }
3503 cidr = MyMalloc(sizeof(struct CidrItem));
3504 cidr->number_on_this_cidr = 1;
3505 cidr->mask = *ip;
3506 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv4);
3507 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3508 }
3509 #ifdef IPV6
3510 else if (aclass->cidr_bitlen_ipv6 > 0)
3511 {
3512 DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3513 {
3514 cidr = ptr->data;
3515 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3516 {
3517 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3518 return -1;
3519 cidr->number_on_this_cidr++;
3520 return 0;
3521 }
3522 }
3523 cidr = MyMalloc(sizeof(struct CidrItem));
3524 cidr->number_on_this_cidr = 1;
3525 cidr->mask = *ip;
3526 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv6);
3527 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3528 }
3529 #endif
3530 return 0;
3531 }
3532
3533 /*
3534 * remove_from_cidr_check
3535 *
3536 * inputs - pointer to the ip to be removed
3537 * - pointer to the class
3538 * output - NONE
3539 * side effects -
3540 */
3541 static void
3542 remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3543 {
3544 dlink_node *ptr = NULL;
3545 dlink_node *next_ptr = NULL;
3546 struct CidrItem *cidr;
3547
3548 if (aclass->number_per_cidr == 0)
3549 return;
3550
3551 if (ip->ss.ss_family == AF_INET)
3552 {
3553 if (aclass->cidr_bitlen_ipv4 <= 0)
3554 return;
3555
3556 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3557 {
3558 cidr = ptr->data;
3559 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3560 {
3561 cidr->number_on_this_cidr--;
3562 if (cidr->number_on_this_cidr == 0)
3563 {
3564 dlinkDelete(ptr, &aclass->list_ipv4);
3565 MyFree(cidr);
3566 return;
3567 }
3568 }
3569 }
3570 }
3571 #ifdef IPV6
3572 else if (aclass->cidr_bitlen_ipv6 > 0)
3573 {
3574 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3575 {
3576 cidr = ptr->data;
3577 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3578 {
3579 cidr->number_on_this_cidr--;
3580 if (cidr->number_on_this_cidr == 0)
3581 {
3582 dlinkDelete(ptr, &aclass->list_ipv6);
3583 MyFree(cidr);
3584 return;
3585 }
3586 }
3587 }
3588 }
3589 #endif
3590 }
3591
3592 static void
3593 rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3594 dlink_list *old_list, dlink_list *new_list, int changed)
3595 {
3596 dlink_node *ptr;
3597 struct Client *client_p;
3598 struct ConfItem *conf;
3599 struct AccessItem *aconf;
3600
3601 if (!changed)
3602 {
3603 *new_list = *old_list;
3604 old_list->head = old_list->tail = NULL;
3605 old_list->length = 0;
3606 return;
3607 }
3608
3609 DLINK_FOREACH(ptr, local_client_list.head)
3610 {
3611 client_p = ptr->data;
3612 if (client_p->localClient->aftype != aftype)
3613 continue;
3614 if (dlink_list_length(&client_p->localClient->confs) == 0)
3615 continue;
3616
3617 conf = client_p->localClient->confs.tail->data;
3618 if (conf->type == CLIENT_TYPE)
3619 {
3620 aconf = map_to_conf(conf);
3621 if (aconf->class_ptr == oldcl)
3622 cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3623 }
3624 }
3625 }
3626
3627 /*
3628 * rebuild_cidr_class
3629 *
3630 * inputs - pointer to old conf
3631 * - pointer to new_class
3632 * output - none
3633 * side effects - rebuilds the class link list of cidr blocks
3634 */
3635 void
3636 rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3637 {
3638 struct ClassItem *old_class = map_to_conf(conf);
3639
3640 if (old_class->number_per_cidr > 0 && new_class->number_per_cidr > 0)
3641 {
3642 if (old_class->cidr_bitlen_ipv4 > 0 && new_class->cidr_bitlen_ipv4 > 0)
3643 rebuild_cidr_list(AF_INET, conf, new_class,
3644 &old_class->list_ipv4, &new_class->list_ipv4,
3645 old_class->cidr_bitlen_ipv4 != new_class->cidr_bitlen_ipv4);
3646
3647 #ifdef IPV6
3648 if (old_class->cidr_bitlen_ipv6 > 0 && new_class->cidr_bitlen_ipv6 > 0)
3649 rebuild_cidr_list(AF_INET6, conf, new_class,
3650 &old_class->list_ipv6, &new_class->list_ipv6,
3651 old_class->cidr_bitlen_ipv6 != new_class->cidr_bitlen_ipv6);
3652 #endif
3653 }
3654
3655 destroy_cidr_class(old_class);
3656 }
3657
3658 /*
3659 * destroy_cidr_list
3660 *
3661 * inputs - pointer to class dlink list of cidr blocks
3662 * output - none
3663 * side effects - completely destroys the class link list of cidr blocks
3664 */
3665 static void
3666 destroy_cidr_list(dlink_list *list)
3667 {
3668 dlink_node *ptr = NULL, *next_ptr = NULL;
3669
3670 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3671 {
3672 dlinkDelete(ptr, list);
3673 MyFree(ptr->data);
3674 }
3675 }
3676
3677 /*
3678 * destroy_cidr_class
3679 *
3680 * inputs - pointer to class
3681 * output - none
3682 * side effects - completely destroys the class link list of cidr blocks
3683 */
3684 static void
3685 destroy_cidr_class(struct ClassItem *aclass)
3686 {
3687 destroy_cidr_list(&aclass->list_ipv4);
3688 destroy_cidr_list(&aclass->list_ipv6);
3689 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision