ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1394
Committed: Wed May 2 19:29:19 2012 UTC (13 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 93518 byte(s)
Log Message:
- conf.c:attach_conf(): remove useless conftype test.
  conf is now always one of CLIENT_TYPE, SERVER_TYPE,
  or OPER_TYPE.

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

Properties

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