ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1432
Committed: Sat Jun 9 19:40:08 2012 UTC (13 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 93561 byte(s)
Log Message:
- Added channel::max_chans_per_oper configuration directive. The old way
  was to let ircops join three times the amount of max_chans_per_user.

  I'd rather would make this a class{} based limit, but this would require us
  to reprint the ISUPPORT buffer every time a client connects.

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

Properties

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