ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1387
Committed: Tue May 1 11:50:01 2012 UTC (11 years, 10 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 94004 byte(s)
Log Message:
- conf.c: cleanup get_sendq(), get_client_class() and get_client_ping().
  Now that we don't have any other attached conf than CONF_CLIENT|CONF_SERVER|CONF_OPER,
  we may simply use the last attached conf pointed by x->confs.head

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->ipnum, addr, sizeof(aconf->ipnum));
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 if (dlinkFind(&client_p->localClient->confs, conf) != NULL)
1329 return 1;
1330
1331 if (conf->type == CLIENT_TYPE ||
1332 conf->type == SERVER_TYPE ||
1333 conf->type == OPER_TYPE)
1334 {
1335 struct AccessItem *aconf = map_to_conf(conf);
1336 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1337
1338 if (IsConfIllegal(aconf))
1339 return NOT_AUTHORIZED;
1340
1341 if (conf->type == CLIENT_TYPE)
1342 if (cidr_limit_reached(IsConfExemptLimits(aconf),
1343 &client_p->localClient->ip, aclass))
1344 return TOO_MANY; /* Already at maximum allowed */
1345
1346 aclass->curr_user_count++;
1347 aconf->clients++;
1348 }
1349
1350 dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs);
1351
1352 return 0;
1353 }
1354
1355 /* attach_connect_block()
1356 *
1357 * inputs - pointer to server to attach
1358 * - name of server
1359 * - hostname of server
1360 * output - true (1) if both are found, otherwise return false (0)
1361 * side effects - find connect block and attach them to connecting client
1362 */
1363 int
1364 attach_connect_block(struct Client *client_p, const char *name,
1365 const char *host)
1366 {
1367 dlink_node *ptr;
1368 struct ConfItem *conf;
1369 struct AccessItem *aconf;
1370
1371 assert(client_p != NULL);
1372 assert(host != NULL);
1373
1374 if (client_p == NULL || host == NULL)
1375 return 0;
1376
1377 DLINK_FOREACH(ptr, server_items.head)
1378 {
1379 conf = ptr->data;
1380 aconf = map_to_conf(conf);
1381
1382 if (match(conf->name, name) == 0 || match(aconf->host, host) == 0)
1383 continue;
1384
1385 attach_conf(client_p, conf);
1386 return -1;
1387 }
1388
1389 return 0;
1390 }
1391
1392 /* find_conf_exact()
1393 *
1394 * inputs - type of ConfItem
1395 * - pointer to name to find
1396 * - pointer to username to find
1397 * - pointer to host to find
1398 * output - NULL or pointer to conf found
1399 * side effects - find a conf entry which matches the hostname
1400 * and has the same name.
1401 */
1402 struct ConfItem *
1403 find_conf_exact(ConfType type, const char *name, const char *user,
1404 const char *host)
1405 {
1406 dlink_node *ptr;
1407 dlink_list *list_p;
1408 struct ConfItem *conf = NULL;
1409 struct AccessItem *aconf;
1410
1411 /* Only valid for OPER_TYPE and ...? */
1412 list_p = map_to_list(type);
1413
1414 DLINK_FOREACH(ptr, (*list_p).head)
1415 {
1416 conf = ptr->data;
1417
1418 if (conf->name == NULL)
1419 continue;
1420 aconf = map_to_conf(conf);
1421 if (aconf->host == NULL)
1422 continue;
1423 if (irccmp(conf->name, name) != 0)
1424 continue;
1425
1426 /*
1427 ** Accept if the *real* hostname (usually sockethost)
1428 ** socket host) matches *either* host or name field
1429 ** of the configuration.
1430 */
1431 if (!match(aconf->host, host) || !match(aconf->user, user))
1432 continue;
1433 if (type == OPER_TYPE)
1434 {
1435 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1436
1437 if (aconf->clients >= aclass->max_total)
1438 continue;
1439 }
1440
1441 return conf;
1442 }
1443
1444 return NULL;
1445 }
1446
1447 /* find_conf_name()
1448 *
1449 * inputs - pointer to conf link list to search
1450 * - pointer to name to find
1451 * - int mask of type of conf to find
1452 * output - NULL or pointer to conf found
1453 * side effects - find a conf entry which matches the name
1454 * and has the given mask.
1455 */
1456 struct ConfItem *
1457 find_conf_name(dlink_list *list, const char *name, ConfType type)
1458 {
1459 dlink_node *ptr;
1460 struct ConfItem* conf;
1461
1462 DLINK_FOREACH(ptr, list->head)
1463 {
1464 conf = ptr->data;
1465
1466 if (conf->type == type)
1467 {
1468 if (conf->name && (irccmp(conf->name, name) == 0 ||
1469 match(conf->name, name)))
1470 return conf;
1471 }
1472 }
1473
1474 return NULL;
1475 }
1476
1477 /* map_to_list()
1478 *
1479 * inputs - ConfType conf
1480 * output - pointer to dlink_list to use
1481 * side effects - none
1482 */
1483 static dlink_list *
1484 map_to_list(ConfType type)
1485 {
1486 switch(type)
1487 {
1488 case RXLINE_TYPE:
1489 return(&rxconf_items);
1490 break;
1491 case XLINE_TYPE:
1492 return(&xconf_items);
1493 break;
1494 case ULINE_TYPE:
1495 return(&uconf_items);
1496 break;
1497 case NRESV_TYPE:
1498 return(&nresv_items);
1499 break;
1500 case OPER_TYPE:
1501 return(&oconf_items);
1502 break;
1503 case CLASS_TYPE:
1504 return(&class_items);
1505 break;
1506 case SERVER_TYPE:
1507 return(&server_items);
1508 break;
1509 case SERVICE_TYPE:
1510 return(&service_items);
1511 break;
1512 case CLUSTER_TYPE:
1513 return(&cluster_items);
1514 break;
1515 case CONF_TYPE:
1516 case GLINE_TYPE:
1517 case KLINE_TYPE:
1518 case DLINE_TYPE:
1519 case CRESV_TYPE:
1520 default:
1521 return NULL;
1522 }
1523 }
1524
1525 /* find_matching_name_conf()
1526 *
1527 * inputs - type of link list to look in
1528 * - pointer to name string to find
1529 * - pointer to user
1530 * - pointer to host
1531 * - optional action to match on as well
1532 * output - NULL or pointer to found struct MatchItem
1533 * side effects - looks for a match on name field
1534 */
1535 struct ConfItem *
1536 find_matching_name_conf(ConfType type, const char *name, const char *user,
1537 const char *host, int action)
1538 {
1539 dlink_node *ptr=NULL;
1540 struct ConfItem *conf=NULL;
1541 struct AccessItem *aconf=NULL;
1542 struct MatchItem *match_item=NULL;
1543 dlink_list *list_p = map_to_list(type);
1544
1545 switch (type)
1546 {
1547 #ifdef HAVE_LIBPCRE
1548 case RXLINE_TYPE:
1549 DLINK_FOREACH(ptr, list_p->head)
1550 {
1551 conf = ptr->data;
1552 assert(conf->regexpname);
1553
1554 if (!ircd_pcre_exec(conf->regexpname, name))
1555 return conf;
1556 }
1557 break;
1558 #endif
1559 case SERVICE_TYPE:
1560 DLINK_FOREACH(ptr, list_p->head)
1561 {
1562 conf = ptr->data;
1563
1564 if (EmptyString(conf->name))
1565 continue;
1566 if ((name != NULL) && !irccmp(name, conf->name))
1567 return conf;
1568 }
1569 break;
1570
1571 case XLINE_TYPE:
1572 case ULINE_TYPE:
1573 case NRESV_TYPE:
1574 DLINK_FOREACH(ptr, list_p->head)
1575 {
1576 conf = ptr->data;
1577
1578 match_item = map_to_conf(conf);
1579 if (EmptyString(conf->name))
1580 continue;
1581 if ((name != NULL) && match_esc(conf->name, name))
1582 {
1583 if ((user == NULL && (host == NULL)))
1584 return conf;
1585 if ((match_item->action & action) != action)
1586 continue;
1587 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1588 return conf;
1589 if (match(match_item->user, user) && match(match_item->host, host))
1590 return conf;
1591 }
1592 }
1593 break;
1594
1595 case SERVER_TYPE:
1596 DLINK_FOREACH(ptr, list_p->head)
1597 {
1598 conf = ptr->data;
1599 aconf = map_to_conf(conf);
1600
1601 if ((name != NULL) && match_esc(name, conf->name))
1602 return conf;
1603 else if ((host != NULL) && match_esc(host, aconf->host))
1604 return conf;
1605 }
1606 break;
1607
1608 default:
1609 break;
1610 }
1611 return NULL;
1612 }
1613
1614 /* find_exact_name_conf()
1615 *
1616 * inputs - type of link list to look in
1617 * - pointer to name string to find
1618 * - pointer to user
1619 * - pointer to host
1620 * output - NULL or pointer to found struct MatchItem
1621 * side effects - looks for an exact match on name field
1622 */
1623 struct ConfItem *
1624 find_exact_name_conf(ConfType type, const struct Client *who, const char *name,
1625 const char *user, const char *host)
1626 {
1627 dlink_node *ptr = NULL;
1628 struct AccessItem *aconf;
1629 struct ConfItem *conf;
1630 struct MatchItem *match_item;
1631 dlink_list *list_p;
1632
1633 list_p = map_to_list(type);
1634
1635 switch(type)
1636 {
1637 case RXLINE_TYPE:
1638 case XLINE_TYPE:
1639 case ULINE_TYPE:
1640 case NRESV_TYPE:
1641
1642 DLINK_FOREACH(ptr, list_p->head)
1643 {
1644 conf = ptr->data;
1645 match_item = (struct MatchItem *)map_to_conf(conf);
1646 if (EmptyString(conf->name))
1647 continue;
1648
1649 if (irccmp(conf->name, name) == 0)
1650 {
1651 if ((user == NULL && (host == NULL)))
1652 return (conf);
1653 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1654 return (conf);
1655 if (match(match_item->user, user) && match(match_item->host, host))
1656 return (conf);
1657 }
1658 }
1659 break;
1660
1661 case OPER_TYPE:
1662 DLINK_FOREACH(ptr, list_p->head)
1663 {
1664 conf = ptr->data;
1665 aconf = map_to_conf(conf);
1666
1667 if (EmptyString(conf->name))
1668 continue;
1669
1670 if (!irccmp(conf->name, name))
1671 {
1672 if (!who)
1673 return conf;
1674 if (EmptyString(aconf->user) || EmptyString(aconf->host))
1675 return conf;
1676 if (match(aconf->user, who->username))
1677 {
1678 switch (aconf->type)
1679 {
1680 case HM_HOST:
1681 if (match(aconf->host, who->host) || match(aconf->host, who->sockhost))
1682 return conf;
1683 break;
1684 case HM_IPV4:
1685 if (who->localClient->aftype == AF_INET)
1686 if (match_ipv4(&who->localClient->ip, &aconf->ipnum, aconf->bits))
1687 return conf;
1688 break;
1689 #ifdef IPV6
1690 case HM_IPV6:
1691 if (who->localClient->aftype == AF_INET6)
1692 if (match_ipv6(&who->localClient->ip, &aconf->ipnum, aconf->bits))
1693 return conf;
1694 break;
1695 #endif
1696 default:
1697 assert(0);
1698 }
1699 }
1700 }
1701 }
1702
1703 break;
1704
1705 case SERVER_TYPE:
1706 DLINK_FOREACH(ptr, list_p->head)
1707 {
1708 conf = ptr->data;
1709 aconf = (struct AccessItem *)map_to_conf(conf);
1710 if (EmptyString(conf->name))
1711 continue;
1712
1713 if (name == NULL)
1714 {
1715 if (EmptyString(aconf->host))
1716 continue;
1717 if (irccmp(aconf->host, host) == 0)
1718 return(conf);
1719 }
1720 else if (irccmp(conf->name, name) == 0)
1721 {
1722 return (conf);
1723 }
1724 }
1725 break;
1726
1727 case CLASS_TYPE:
1728 DLINK_FOREACH(ptr, list_p->head)
1729 {
1730 conf = ptr->data;
1731 if (EmptyString(conf->name))
1732 continue;
1733
1734 if (irccmp(conf->name, name) == 0)
1735 return (conf);
1736 }
1737 break;
1738
1739 default:
1740 break;
1741 }
1742 return(NULL);
1743 }
1744
1745 /* rehash()
1746 *
1747 * Actual REHASH service routine. Called with sig == 0 if it has been called
1748 * as a result of an operator issuing this command, else assume it has been
1749 * called as a result of the server receiving a HUP signal.
1750 */
1751 int
1752 rehash(int sig)
1753 {
1754 if (sig != 0)
1755 sendto_realops_flags(UMODE_ALL, L_ALL,
1756 "Got signal SIGHUP, reloading ircd.conf file");
1757
1758 restart_resolver();
1759
1760 /* don't close listeners until we know we can go ahead with the rehash */
1761
1762 /* Check to see if we magically got(or lost) IPv6 support */
1763 check_can_use_v6();
1764
1765 read_conf_files(0);
1766
1767 if (ServerInfo.description != NULL)
1768 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
1769
1770 load_conf_modules();
1771
1772 flush_deleted_I_P();
1773
1774 rehashed_klines = 1;
1775 /* XXX */
1776 if (ConfigLoggingEntry.use_logging)
1777 log_close_all();
1778
1779 return(0);
1780 }
1781
1782 /* set_default_conf()
1783 *
1784 * inputs - NONE
1785 * output - NONE
1786 * side effects - Set default values here.
1787 * This is called **PRIOR** to parsing the
1788 * configuration file. If you want to do some validation
1789 * of values later, put them in validate_conf().
1790 */
1791 static void
1792 set_default_conf(void)
1793 {
1794 /* verify init_class() ran, this should be an unnecessary check
1795 * but its not much work.
1796 */
1797 assert(class_default == (struct ConfItem *) class_items.tail->data);
1798
1799 #ifdef HAVE_LIBCRYPTO
1800 ServerInfo.rsa_private_key = NULL;
1801 ServerInfo.rsa_private_key_file = NULL;
1802 #endif
1803
1804 /* ServerInfo.name is not rehashable */
1805 /* ServerInfo.name = ServerInfo.name; */
1806 ServerInfo.description = NULL;
1807 DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
1808 DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
1809
1810 memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
1811 ServerInfo.specific_ipv4_vhost = 0;
1812 memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
1813 ServerInfo.specific_ipv6_vhost = 0;
1814
1815 ServerInfo.max_clients = MAXCLIENTS_MAX;
1816
1817 ServerInfo.hub = 0;
1818 ServerInfo.dns_host.sin_addr.s_addr = 0;
1819 ServerInfo.dns_host.sin_port = 0;
1820 AdminInfo.name = NULL;
1821 AdminInfo.email = NULL;
1822 AdminInfo.description = NULL;
1823
1824 log_close_all();
1825
1826 ConfigLoggingEntry.use_logging = 1;
1827
1828 ConfigChannel.disable_fake_channels = 0;
1829 ConfigChannel.restrict_channels = 0;
1830 ConfigChannel.disable_local_channels = 0;
1831 ConfigChannel.use_invex = 1;
1832 ConfigChannel.use_except = 1;
1833 ConfigChannel.use_knock = 1;
1834 ConfigChannel.knock_delay = 300;
1835 ConfigChannel.knock_delay_channel = 60;
1836 ConfigChannel.max_chans_per_user = 15;
1837 ConfigChannel.quiet_on_ban = 1;
1838 ConfigChannel.max_bans = 25;
1839 ConfigChannel.default_split_user_count = 0;
1840 ConfigChannel.default_split_server_count = 0;
1841 ConfigChannel.no_join_on_split = 0;
1842 ConfigChannel.no_create_on_split = 0;
1843 ConfigChannel.burst_topicwho = 1;
1844
1845 ConfigServerHide.flatten_links = 0;
1846 ConfigServerHide.links_delay = 300;
1847 ConfigServerHide.hidden = 0;
1848 ConfigServerHide.disable_hidden = 0;
1849 ConfigServerHide.hide_servers = 0;
1850 DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1851 ConfigServerHide.hide_server_ips = 0;
1852
1853
1854 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1855 ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
1856 ConfigFileEntry.gline_min_cidr = 16;
1857 ConfigFileEntry.gline_min_cidr6 = 48;
1858 ConfigFileEntry.invisible_on_connect = 1;
1859 ConfigFileEntry.burst_away = 0;
1860 ConfigFileEntry.use_whois_actually = 1;
1861 ConfigFileEntry.tkline_expire_notices = 1;
1862 ConfigFileEntry.hide_spoof_ips = 1;
1863 ConfigFileEntry.ignore_bogus_ts = 0;
1864 ConfigFileEntry.disable_auth = 0;
1865 ConfigFileEntry.disable_remote = 0;
1866 ConfigFileEntry.kill_chase_time_limit = 90;
1867 ConfigFileEntry.default_floodcount = 8;
1868 ConfigFileEntry.failed_oper_notice = 1;
1869 ConfigFileEntry.dots_in_ident = 0;
1870 ConfigFileEntry.min_nonwildcard = 4;
1871 ConfigFileEntry.min_nonwildcard_simple = 3;
1872 ConfigFileEntry.max_accept = 20;
1873 ConfigFileEntry.anti_nick_flood = 0;
1874 ConfigFileEntry.max_nick_time = 20;
1875 ConfigFileEntry.max_nick_changes = 5;
1876 ConfigFileEntry.anti_spam_exit_message_time = 0;
1877 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1878 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1879 ConfigFileEntry.kline_with_reason = 1;
1880 ConfigFileEntry.kline_reason = NULL;
1881 ConfigFileEntry.warn_no_nline = 1;
1882 ConfigFileEntry.stats_o_oper_only = 0;
1883 ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1884 ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1885 ConfigFileEntry.stats_P_oper_only = 0;
1886 ConfigFileEntry.caller_id_wait = 60;
1887 ConfigFileEntry.opers_bypass_callerid = 0;
1888 ConfigFileEntry.pace_wait = 10;
1889 ConfigFileEntry.pace_wait_simple = 1;
1890 ConfigFileEntry.short_motd = 0;
1891 ConfigFileEntry.ping_cookie = 0;
1892 ConfigFileEntry.no_oper_flood = 0;
1893 ConfigFileEntry.true_no_oper_flood = 0;
1894 ConfigFileEntry.oper_pass_resv = 1;
1895 ConfigFileEntry.glines = 0;
1896 ConfigFileEntry.gline_time = 12 * 3600;
1897 ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1898 ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
1899 ConfigFileEntry.oper_only_umodes = UMODE_DEBUG;
1900 ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
1901 UMODE_OPERWALL | UMODE_WALLOP;
1902 ConfigFileEntry.use_egd = 0;
1903 ConfigFileEntry.egdpool_path = NULL;
1904 ConfigFileEntry.throttle_time = 10;
1905 }
1906
1907 static void
1908 validate_conf(void)
1909 {
1910 if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1911 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1912
1913 if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1914 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1915
1916 if (ServerInfo.network_name == NULL)
1917 DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1918
1919 if (ServerInfo.network_desc == NULL)
1920 DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1921
1922 if (ConfigFileEntry.service_name == NULL)
1923 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1924
1925 if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
1926 (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
1927 ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
1928
1929 ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
1930 }
1931
1932 /* read_conf()
1933 *
1934 * inputs - file descriptor pointing to config file to use
1935 * output - None
1936 * side effects - Read configuration file.
1937 */
1938 static void
1939 read_conf(FILE *file)
1940 {
1941 lineno = 0;
1942
1943 set_default_conf(); /* Set default values prior to conf parsing */
1944 conf_parser_ctx.pass = 1;
1945 yyparse(); /* pick up the classes first */
1946
1947 rewind(file);
1948
1949 conf_parser_ctx.pass = 2;
1950 yyparse(); /* Load the values from the conf */
1951 validate_conf(); /* Check to make sure some values are still okay. */
1952 /* Some global values are also loaded here. */
1953 check_class(); /* Make sure classes are valid */
1954 }
1955
1956 /* lookup_confhost()
1957 *
1958 * start DNS lookups of all hostnames in the conf
1959 * line and convert an IP addresses in a.b.c.d number for to IP#s.
1960 */
1961 static void
1962 lookup_confhost(struct ConfItem *conf)
1963 {
1964 struct AccessItem *aconf;
1965 struct addrinfo hints, *res;
1966
1967 aconf = map_to_conf(conf);
1968
1969 if (EmptyString(aconf->host) ||
1970 EmptyString(aconf->user))
1971 {
1972 ilog(LOG_TYPE_IRCD, "Host/server name error: (%s) (%s)",
1973 aconf->host, conf->name);
1974 return;
1975 }
1976
1977 if (strchr(aconf->host, '*') ||
1978 strchr(aconf->host, '?'))
1979 return;
1980
1981 /* Do name lookup now on hostnames given and store the
1982 * ip numbers in conf structure.
1983 */
1984 memset(&hints, 0, sizeof(hints));
1985
1986 hints.ai_family = AF_UNSPEC;
1987 hints.ai_socktype = SOCK_STREAM;
1988
1989 /* Get us ready for a bind() and don't bother doing dns lookup */
1990 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1991
1992 if (getaddrinfo(aconf->host, NULL, &hints, &res))
1993 {
1994 conf_dns_lookup(aconf);
1995 return;
1996 }
1997
1998 assert(res != NULL);
1999
2000 memcpy(&aconf->ipnum, res->ai_addr, res->ai_addrlen);
2001 aconf->ipnum.ss_len = res->ai_addrlen;
2002 aconf->ipnum.ss.ss_family = res->ai_family;
2003 freeaddrinfo(res);
2004 }
2005
2006 /* conf_connect_allowed()
2007 *
2008 * inputs - pointer to inaddr
2009 * - int type ipv4 or ipv6
2010 * output - BANNED or accepted
2011 * side effects - none
2012 */
2013 int
2014 conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
2015 {
2016 struct ip_entry *ip_found;
2017 struct AccessItem *aconf = find_dline_conf(addr, aftype);
2018
2019 /* DLINE exempt also gets you out of static limits/pacing... */
2020 if (aconf && (aconf->status & CONF_EXEMPTDLINE))
2021 return 0;
2022
2023 if (aconf != NULL)
2024 return BANNED_CLIENT;
2025
2026 ip_found = find_or_add_ip(addr);
2027
2028 if ((CurrentTime - ip_found->last_attempt) <
2029 ConfigFileEntry.throttle_time)
2030 {
2031 ip_found->last_attempt = CurrentTime;
2032 return TOO_FAST;
2033 }
2034
2035 ip_found->last_attempt = CurrentTime;
2036 return 0;
2037 }
2038
2039 static struct AccessItem *
2040 find_regexp_kline(const char *uhi[])
2041 {
2042 #ifdef HAVE_LIBPCRE
2043 const dlink_node *ptr = NULL;
2044
2045 DLINK_FOREACH(ptr, rkconf_items.head)
2046 {
2047 struct AccessItem *aptr = map_to_conf(ptr->data);
2048
2049 assert(aptr->regexuser);
2050 assert(aptr->regexhost);
2051
2052 if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
2053 (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
2054 !ircd_pcre_exec(aptr->regexhost, uhi[2])))
2055 return aptr;
2056 }
2057 #endif
2058 return NULL;
2059 }
2060
2061 /* find_kill()
2062 *
2063 * inputs - pointer to client structure
2064 * output - pointer to struct AccessItem if found
2065 * side effects - See if this user is klined already,
2066 * and if so, return struct AccessItem pointer
2067 */
2068 struct AccessItem *
2069 find_kill(struct Client *client_p)
2070 {
2071 struct AccessItem *aconf = NULL;
2072 const char *uhi[3];
2073
2074 uhi[0] = client_p->username;
2075 uhi[1] = client_p->host;
2076 uhi[2] = client_p->sockhost;
2077
2078 assert(client_p != NULL);
2079
2080 aconf = find_kline_conf(client_p->host, client_p->username,
2081 &client_p->localClient->ip,
2082 client_p->localClient->aftype);
2083 if (aconf == NULL)
2084 aconf = find_regexp_kline(uhi);
2085
2086 if (aconf && (aconf->status & CONF_KLINE))
2087 return aconf;
2088
2089 return NULL;
2090 }
2091
2092 struct AccessItem *
2093 find_gline(struct Client *client_p)
2094 {
2095 struct AccessItem *aconf;
2096
2097 assert(client_p != NULL);
2098
2099 aconf = find_gline_conf(client_p->host, client_p->username,
2100 &client_p->localClient->ip,
2101 client_p->localClient->aftype);
2102
2103 if (aconf && (aconf->status & CONF_GLINE))
2104 return aconf;
2105
2106 return NULL;
2107 }
2108
2109 /* add_temp_line()
2110 *
2111 * inputs - pointer to struct ConfItem
2112 * output - none
2113 * Side effects - links in given struct ConfItem into
2114 * temporary *line link list
2115 */
2116 void
2117 add_temp_line(struct ConfItem *conf)
2118 {
2119 if (conf->type == XLINE_TYPE)
2120 {
2121 conf->flags |= CONF_FLAGS_TEMPORARY;
2122 dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
2123 }
2124 else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
2125 {
2126 conf->flags |= CONF_FLAGS_TEMPORARY;
2127 dlinkAdd(conf, make_dlink_node(), &temporary_resv);
2128 }
2129 }
2130
2131 /* cleanup_tklines()
2132 *
2133 * inputs - NONE
2134 * output - NONE
2135 * side effects - call function to expire temporary k/d lines
2136 * This is an event started off in ircd.c
2137 */
2138 void
2139 cleanup_tklines(void *notused)
2140 {
2141 hostmask_expire_temporary();
2142 expire_tklines(&temporary_xlines);
2143 expire_tklines(&temporary_resv);
2144 }
2145
2146 /* expire_tklines()
2147 *
2148 * inputs - tkline list pointer
2149 * output - NONE
2150 * side effects - expire tklines
2151 */
2152 static void
2153 expire_tklines(dlink_list *tklist)
2154 {
2155 dlink_node *ptr;
2156 dlink_node *next_ptr;
2157 struct ConfItem *conf;
2158 struct MatchItem *xconf;
2159 struct MatchItem *nconf;
2160 struct ResvChannel *cconf;
2161
2162 DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2163 {
2164 conf = ptr->data;
2165
2166 if (conf->type == XLINE_TYPE)
2167 {
2168 xconf = (struct MatchItem *)map_to_conf(conf);
2169 if (xconf->hold <= CurrentTime)
2170 {
2171 if (ConfigFileEntry.tkline_expire_notices)
2172 sendto_realops_flags(UMODE_ALL, L_ALL,
2173 "Temporary X-line for [%s] sexpired", conf->name);
2174 dlinkDelete(ptr, tklist);
2175 free_dlink_node(ptr);
2176 delete_conf_item(conf);
2177 }
2178 }
2179 else if (conf->type == NRESV_TYPE)
2180 {
2181 nconf = (struct MatchItem *)map_to_conf(conf);
2182 if (nconf->hold <= CurrentTime)
2183 {
2184 if (ConfigFileEntry.tkline_expire_notices)
2185 sendto_realops_flags(UMODE_ALL, L_ALL,
2186 "Temporary RESV for [%s] expired", conf->name);
2187 dlinkDelete(ptr, tklist);
2188 free_dlink_node(ptr);
2189 delete_conf_item(conf);
2190 }
2191 }
2192 else if (conf->type == CRESV_TYPE)
2193 {
2194 cconf = (struct ResvChannel *)map_to_conf(conf);
2195 if (cconf->hold <= CurrentTime)
2196 {
2197 if (ConfigFileEntry.tkline_expire_notices)
2198 sendto_realops_flags(UMODE_ALL, L_ALL,
2199 "Temporary RESV for [%s] expired", cconf->name);
2200 delete_channel_resv(cconf);
2201 }
2202 }
2203 }
2204 }
2205
2206 /* oper_privs_as_string()
2207 *
2208 * inputs - pointer to client_p
2209 * output - pointer to static string showing oper privs
2210 * side effects - return as string, the oper privs as derived from port
2211 */
2212 static const struct oper_privs
2213 {
2214 const unsigned int oprivs;
2215 const unsigned char c;
2216 } flag_list[] = {
2217 { OPER_FLAG_ADMIN, 'A' },
2218 { OPER_FLAG_REMOTEBAN, 'B' },
2219 { OPER_FLAG_DIE, 'D' },
2220 { OPER_FLAG_GLINE, 'G' },
2221 { OPER_FLAG_REHASH, 'H' },
2222 { OPER_FLAG_K, 'K' },
2223 { OPER_FLAG_OPERWALL, 'L' },
2224 { OPER_FLAG_N, 'N' },
2225 { OPER_FLAG_GLOBAL_KILL, 'O' },
2226 { OPER_FLAG_REMOTE, 'R' },
2227 { OPER_FLAG_OPER_SPY, 'S' },
2228 { OPER_FLAG_UNKLINE, 'U' },
2229 { OPER_FLAG_X, 'X' },
2230 { 0, '\0' }
2231 };
2232
2233 char *
2234 oper_privs_as_string(const unsigned int port)
2235 {
2236 static char privs_out[16];
2237 char *privs_ptr = privs_out;
2238 unsigned int i = 0;
2239
2240 for (; flag_list[i].oprivs; ++i)
2241 {
2242 if (port & flag_list[i].oprivs)
2243 *privs_ptr++ = flag_list[i].c;
2244 else
2245 *privs_ptr++ = ToLowerTab[flag_list[i].c];
2246 }
2247
2248 *privs_ptr = '\0';
2249
2250 return privs_out;
2251 }
2252
2253 /*
2254 * Input: A client to find the active oper{} name for.
2255 * Output: The nick!user@host{oper} of the oper.
2256 * "oper" is server name for remote opers
2257 * Side effects: None.
2258 */
2259 const char *
2260 get_oper_name(const struct Client *client_p)
2261 {
2262 dlink_node *cnode = NULL;
2263 /* +5 for !,@,{,} and null */
2264 static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
2265
2266 if (MyConnect(client_p))
2267 {
2268 if ((cnode = client_p->localClient->confs.head))
2269 {
2270 struct ConfItem *conf = cnode->data;
2271 const struct AccessItem *aconf = map_to_conf(conf);
2272
2273 if (IsConfOperator(aconf))
2274 {
2275 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2276 client_p->username, client_p->host, conf->name);
2277 return buffer;
2278 }
2279 }
2280
2281 /* Probably should assert here for now. If there is an oper out there
2282 * with no oper{} conf attached, it would be good for us to know...
2283 */
2284 assert(0); /* Oper without oper conf! */
2285 }
2286
2287 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2288 client_p->username, client_p->host, client_p->servptr->name);
2289 return buffer;
2290 }
2291
2292 /* read_conf_files()
2293 *
2294 * inputs - cold start YES or NO
2295 * output - none
2296 * side effects - read all conf files needed, ircd.conf kline.conf etc.
2297 */
2298 void
2299 read_conf_files(int cold)
2300 {
2301 const char *filename;
2302 char chanmodes[32];
2303 char chanlimit[32];
2304
2305 conf_parser_ctx.boot = cold;
2306 filename = get_conf_name(CONF_TYPE);
2307
2308 /* We need to know the initial filename for the yyerror() to report
2309 FIXME: The full path is in conffilenamebuf first time since we
2310 dont know anything else
2311
2312 - Gozem 2002-07-21
2313 */
2314 strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2315
2316 if ((conf_parser_ctx.conf_file = fopen(filename, "r")) == NULL)
2317 {
2318 if (cold)
2319 {
2320 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2321 filename, strerror(errno));
2322 exit(-1);
2323 }
2324 else
2325 {
2326 sendto_realops_flags(UMODE_ALL, L_ALL,
2327 "Unable to read configuration file '%s': %s",
2328 filename, strerror(errno));
2329 return;
2330 }
2331 }
2332
2333 if (!cold)
2334 clear_out_old_conf();
2335
2336 read_conf(conf_parser_ctx.conf_file);
2337 fclose(conf_parser_ctx.conf_file);
2338
2339 add_isupport("NETWORK", ServerInfo.network_name, -1);
2340 snprintf(chanmodes, sizeof(chanmodes), "b%s%s:%d",
2341 ConfigChannel.use_except ? "e" : "",
2342 ConfigChannel.use_invex ? "I" : "", ConfigChannel.max_bans);
2343 add_isupport("MAXLIST", chanmodes, -1);
2344 add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2345
2346 if (ConfigChannel.disable_local_channels)
2347 add_isupport("CHANTYPES", "#", -1);
2348 else
2349 add_isupport("CHANTYPES", "#&", -1);
2350
2351 snprintf(chanlimit, sizeof(chanlimit), "%s:%d",
2352 ConfigChannel.disable_local_channels ? "#" : "#&",
2353 ConfigChannel.max_chans_per_user);
2354 add_isupport("CHANLIMIT", chanlimit, -1);
2355 snprintf(chanmodes, sizeof(chanmodes), "%s%s%s",
2356 ConfigChannel.use_except ? "e" : "",
2357 ConfigChannel.use_invex ? "I" : "", "b,k,l,imnprstORS");
2358 add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
2359
2360 if (ConfigChannel.use_except)
2361 add_isupport("EXCEPTS", "e", -1);
2362 if (ConfigChannel.use_invex)
2363 add_isupport("INVEX", "I", -1);
2364 add_isupport("CHANMODES", chanmodes, -1);
2365
2366 /*
2367 * message_locale may have changed. rebuild isupport since it relies
2368 * on strlen(form_str(RPL_ISUPPORT))
2369 */
2370 rebuild_isupport_message_line();
2371
2372 #ifdef HAVE_LIBPCRE
2373 parse_conf_file(RKLINE_TYPE, cold);
2374 parse_conf_file(RXLINE_TYPE, cold);
2375 #endif
2376 parse_conf_file(KLINE_TYPE, cold);
2377 parse_conf_file(DLINE_TYPE, cold);
2378 parse_conf_file(XLINE_TYPE, cold);
2379 parse_conf_file(NRESV_TYPE, cold);
2380 parse_conf_file(CRESV_TYPE, cold);
2381 }
2382
2383 /* parse_conf_file()
2384 *
2385 * inputs - type of conf file to parse
2386 * output - none
2387 * side effects - conf file for givenconf type is opened and read then parsed
2388 */
2389 static void
2390 parse_conf_file(int type, int cold)
2391 {
2392 FILE *file = NULL;
2393 const char *filename = get_conf_name(type);
2394
2395 if ((file = fopen(filename, "r")) == NULL)
2396 {
2397 if (cold)
2398 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2399 filename, strerror(errno));
2400 else
2401 sendto_realops_flags(UMODE_ALL, L_ALL,
2402 "Unable to read configuration file '%s': %s",
2403 filename, strerror(errno));
2404 }
2405 else
2406 {
2407 parse_csv_file(file, type);
2408 fclose(file);
2409 }
2410 }
2411
2412 /* clear_out_old_conf()
2413 *
2414 * inputs - none
2415 * output - none
2416 * side effects - Clear out the old configuration
2417 */
2418 static void
2419 clear_out_old_conf(void)
2420 {
2421 dlink_node *ptr = NULL, *next_ptr = NULL;
2422 struct ConfItem *conf;
2423 struct AccessItem *aconf;
2424 struct ClassItem *cltmp;
2425 struct MatchItem *match_item;
2426 dlink_list *free_items [] = {
2427 &server_items, &oconf_items,
2428 &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2429 &nresv_items, &cluster_items, &gdeny_items, &service_items, NULL
2430 };
2431
2432 dlink_list ** iterator = free_items; /* C is dumb */
2433
2434 /* We only need to free anything allocated by yyparse() here.
2435 * Resetting structs, etc, is taken care of by set_default_conf().
2436 */
2437
2438 for (; *iterator != NULL; iterator++)
2439 {
2440 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2441 {
2442 conf = ptr->data;
2443 /* XXX This is less than pretty */
2444 if (conf->type == SERVER_TYPE)
2445 {
2446 aconf = map_to_conf(conf);
2447
2448 if (aconf->clients != 0)
2449 {
2450 SetConfIllegal(aconf);
2451 dlinkDelete(&conf->node, &server_items);
2452 }
2453 else
2454 {
2455 delete_conf_item(conf);
2456 }
2457 }
2458 else if (conf->type == OPER_TYPE)
2459 {
2460 aconf = map_to_conf(conf);
2461
2462 if (aconf->clients != 0)
2463 {
2464 SetConfIllegal(aconf);
2465 dlinkDelete(&conf->node, &oconf_items);
2466 }
2467 else
2468 {
2469 delete_conf_item(conf);
2470 }
2471 }
2472 else if (conf->type == XLINE_TYPE ||
2473 conf->type == RXLINE_TYPE ||
2474 conf->type == RKLINE_TYPE)
2475 {
2476 /* temporary (r)xlines are also on
2477 * the (r)xconf items list */
2478 if (conf->flags & CONF_FLAGS_TEMPORARY)
2479 continue;
2480
2481 delete_conf_item(conf);
2482 }
2483 else
2484 {
2485 delete_conf_item(conf);
2486 }
2487 }
2488 }
2489
2490 /*
2491 * don't delete the class table, rather mark all entries
2492 * for deletion. The table is cleaned up by check_class. - avalon
2493 */
2494 DLINK_FOREACH(ptr, class_items.head)
2495 {
2496 cltmp = map_to_conf(ptr->data);
2497
2498 if (ptr != class_items.tail) /* never mark the "default" class */
2499 cltmp->active = 0;
2500 }
2501
2502 clear_out_address_conf();
2503
2504 /* clean out module paths */
2505 mod_clear_paths();
2506
2507 /* clean out ServerInfo */
2508 MyFree(ServerInfo.description);
2509 ServerInfo.description = NULL;
2510 MyFree(ServerInfo.network_name);
2511 ServerInfo.network_name = NULL;
2512 MyFree(ServerInfo.network_desc);
2513 ServerInfo.network_desc = NULL;
2514 MyFree(ConfigFileEntry.egdpool_path);
2515 ConfigFileEntry.egdpool_path = NULL;
2516 #ifdef HAVE_LIBCRYPTO
2517 if (ServerInfo.rsa_private_key != NULL)
2518 {
2519 RSA_free(ServerInfo.rsa_private_key);
2520 ServerInfo.rsa_private_key = NULL;
2521 }
2522
2523 MyFree(ServerInfo.rsa_private_key_file);
2524 ServerInfo.rsa_private_key_file = NULL;
2525
2526 if (ServerInfo.server_ctx)
2527 SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|
2528 SSL_OP_NO_SSLv3|
2529 SSL_OP_NO_TLSv1);
2530 if (ServerInfo.client_ctx)
2531 SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|
2532 SSL_OP_NO_SSLv3|
2533 SSL_OP_NO_TLSv1);
2534 #endif
2535
2536 /* clean out old resvs from the conf */
2537 clear_conf_resv();
2538
2539 /* clean out AdminInfo */
2540 MyFree(AdminInfo.name);
2541 AdminInfo.name = NULL;
2542 MyFree(AdminInfo.email);
2543 AdminInfo.email = NULL;
2544 MyFree(AdminInfo.description);
2545 AdminInfo.description = NULL;
2546
2547 /* operator{} and class{} blocks are freed above */
2548 /* clean out listeners */
2549 close_listeners();
2550
2551 /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2552 * exempt{} and gecos{} blocks are freed above too
2553 */
2554
2555 /* clean out general */
2556 MyFree(ConfigFileEntry.service_name);
2557 ConfigFileEntry.service_name = NULL;
2558
2559 delete_isupport("INVEX");
2560 delete_isupport("EXCEPTS");
2561 }
2562
2563 /* flush_deleted_I_P()
2564 *
2565 * inputs - none
2566 * output - none
2567 * side effects - This function removes I/P conf items
2568 */
2569 static void
2570 flush_deleted_I_P(void)
2571 {
2572 dlink_node *ptr;
2573 dlink_node *next_ptr;
2574 struct ConfItem *conf;
2575 struct AccessItem *aconf;
2576 dlink_list * free_items [] = {
2577 &server_items, &oconf_items, NULL
2578 };
2579 dlink_list ** iterator = free_items; /* C is dumb */
2580
2581 /* flush out deleted I and P lines
2582 * although still in use.
2583 */
2584 for (; *iterator != NULL; iterator++)
2585 {
2586 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2587 {
2588 conf = ptr->data;
2589 aconf = (struct AccessItem *)map_to_conf(conf);
2590
2591 if (IsConfIllegal(aconf))
2592 {
2593 dlinkDelete(ptr, *iterator);
2594
2595 if (aconf->clients == 0)
2596 delete_conf_item(conf);
2597 }
2598 }
2599 }
2600 }
2601
2602 /* get_conf_name()
2603 *
2604 * inputs - type of conf file to return name of file for
2605 * output - pointer to filename for type of conf
2606 * side effects - none
2607 */
2608 const char *
2609 get_conf_name(ConfType type)
2610 {
2611 switch (type)
2612 {
2613 case CONF_TYPE:
2614 return ConfigFileEntry.configfile;
2615 break;
2616 case KLINE_TYPE:
2617 return ConfigFileEntry.klinefile;
2618 break;
2619 case RKLINE_TYPE:
2620 return ConfigFileEntry.rklinefile;
2621 break;
2622 case DLINE_TYPE:
2623 return ConfigFileEntry.dlinefile;
2624 break;
2625 case XLINE_TYPE:
2626 return ConfigFileEntry.xlinefile;
2627 break;
2628 case RXLINE_TYPE:
2629 return ConfigFileEntry.rxlinefile;
2630 break;
2631 case CRESV_TYPE:
2632 return ConfigFileEntry.cresvfile;
2633 break;
2634 case NRESV_TYPE:
2635 return ConfigFileEntry.nresvfile;
2636 break;
2637 case GLINE_TYPE:
2638 return ConfigFileEntry.glinefile;
2639 break;
2640
2641 default:
2642 return NULL; /* This should NEVER HAPPEN since we call this function
2643 only with the above values, this will cause us to core
2644 at some point if this happens so we know where it was */
2645 }
2646 }
2647
2648 #define BAD_PING (-1)
2649
2650 /* get_conf_ping()
2651 *
2652 * inputs - pointer to struct AccessItem
2653 * - pointer to a variable that receives ping warning time
2654 * output - ping frequency
2655 * side effects - NONE
2656 */
2657 static int
2658 get_conf_ping(struct ConfItem *conf, int *pingwarn)
2659 {
2660 struct ClassItem *aclass;
2661 struct AccessItem *aconf;
2662
2663 if (conf != NULL)
2664 {
2665 aconf = (struct AccessItem *)map_to_conf(conf);
2666 if (aconf->class_ptr != NULL)
2667 {
2668 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2669 *pingwarn = aclass->ping_warning;
2670 return aclass->ping_freq;
2671 }
2672 }
2673
2674 return BAD_PING;
2675 }
2676
2677 /* get_client_class()
2678 *
2679 * inputs - pointer to client struct
2680 * output - pointer to name of class
2681 * side effects - NONE
2682 */
2683 const char *
2684 get_client_class(struct Client *target_p)
2685 {
2686 dlink_node *cnode = NULL;
2687 struct AccessItem *aconf = NULL;
2688
2689 assert(!IsMe(target_p));
2690
2691 if ((cnode = target_p->localClient->confs.head))
2692 {
2693 struct ConfItem *conf = cnode->data;
2694
2695 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2696 (conf->type == OPER_TYPE));
2697
2698 aconf = map_to_conf(conf);
2699 if (aconf->class_ptr != NULL)
2700 return aconf->class_ptr->name;
2701 }
2702
2703 return "default";
2704 }
2705
2706 /* get_client_ping()
2707 *
2708 * inputs - pointer to client struct
2709 * - pointer to a variable that receives ping warning time
2710 * output - ping frequency
2711 * side effects - NONE
2712 */
2713 int
2714 get_client_ping(struct Client *target_p, int *pingwarn)
2715 {
2716 int ping = 0;
2717 dlink_node *cnode = NULL;
2718
2719 if ((cnode = target_p->localClient->confs.head))
2720 {
2721 struct ConfItem *conf = cnode->data;
2722
2723 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2724 (conf->type == OPER_TYPE));
2725
2726 ping = get_conf_ping(conf, pingwarn);
2727 if (ping > 0)
2728 return ping;
2729 }
2730
2731 *pingwarn = 0;
2732 return DEFAULT_PINGFREQUENCY;
2733 }
2734
2735 /* find_class()
2736 *
2737 * inputs - string name of class
2738 * output - corresponding Class pointer
2739 * side effects - NONE
2740 */
2741 struct ConfItem *
2742 find_class(const char *classname)
2743 {
2744 struct ConfItem *conf;
2745
2746 if ((conf = find_exact_name_conf(CLASS_TYPE, NULL, classname, NULL, NULL)) != NULL)
2747 return conf;
2748
2749 return class_default;
2750 }
2751
2752 /* check_class()
2753 *
2754 * inputs - NONE
2755 * output - NONE
2756 * side effects -
2757 */
2758 void
2759 check_class(void)
2760 {
2761 dlink_node *ptr = NULL, *next_ptr = NULL;
2762
2763 DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2764 {
2765 struct ClassItem *aclass = map_to_conf(ptr->data);
2766
2767 if (!aclass->active && !aclass->curr_user_count)
2768 {
2769 destroy_cidr_class(aclass);
2770 delete_conf_item(ptr->data);
2771 }
2772 }
2773 }
2774
2775 /* init_class()
2776 *
2777 * inputs - NONE
2778 * output - NONE
2779 * side effects -
2780 */
2781 void
2782 init_class(void)
2783 {
2784 struct ClassItem *aclass;
2785
2786 class_default = make_conf_item(CLASS_TYPE);
2787
2788 aclass = map_to_conf(class_default);
2789 aclass->active = 1;
2790 DupString(class_default->name, "default");
2791 aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
2792 aclass->ping_freq = DEFAULT_PINGFREQUENCY;
2793 aclass->max_total = MAXIMUM_LINKS_DEFAULT;
2794 aclass->max_sendq = DEFAULT_SENDQ;
2795
2796 client_check_cb = register_callback("check_client", check_client);
2797 }
2798
2799 /* get_sendq()
2800 *
2801 * inputs - pointer to client
2802 * output - sendq for this client as found from its class
2803 * side effects - NONE
2804 */
2805 unsigned int
2806 get_sendq(struct Client *client_p)
2807 {
2808 unsigned int sendq = DEFAULT_SENDQ;
2809 dlink_node *cnode;
2810 struct ConfItem *class_conf;
2811 struct ClassItem *aclass;
2812 struct AccessItem *aconf;
2813
2814 assert(IsMe(client_p));
2815
2816 if ((cnode = client_p->localClient->confs.head))
2817 {
2818 struct ConfItem *conf = cnode->data;
2819
2820 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2821 (conf->type == OPER_TYPE));
2822
2823 aconf = map_to_conf(conf);
2824
2825 if ((class_conf = aconf->class_ptr) == NULL)
2826 return DEFAULT_SENDQ; /* TBV: shouldn't be possible at all */
2827
2828 aclass = map_to_conf(class_conf);
2829 sendq = aclass->max_sendq;
2830 return sendq;
2831 }
2832
2833 /* XXX return a default?
2834 * if here, then there wasn't an attached conf with a sendq
2835 * that is very bad -Dianora
2836 */
2837 return DEFAULT_SENDQ;
2838 }
2839
2840 /* conf_add_class_to_conf()
2841 *
2842 * inputs - pointer to config item
2843 * output - NONE
2844 * side effects - Add a class pointer to a conf
2845 */
2846 void
2847 conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
2848 {
2849 struct AccessItem *aconf = map_to_conf(conf);
2850 struct ClassItem *class = NULL;
2851
2852 if (class_name == NULL)
2853 {
2854 aconf->class_ptr = class_default;
2855
2856 if (conf->type == CLIENT_TYPE)
2857 sendto_realops_flags(UMODE_ALL, L_ALL,
2858 "Warning *** Defaulting to default class for %s@%s",
2859 aconf->user, aconf->host);
2860 else
2861 sendto_realops_flags(UMODE_ALL, L_ALL,
2862 "Warning *** Defaulting to default class for %s",
2863 conf->name);
2864 }
2865 else
2866 aconf->class_ptr = find_class(class_name);
2867
2868 if (aconf->class_ptr)
2869 class = map_to_conf(aconf->class_ptr);
2870
2871 if (aconf->class_ptr == NULL || !class->active)
2872 {
2873 if (conf->type == CLIENT_TYPE)
2874 sendto_realops_flags(UMODE_ALL, L_ALL,
2875 "Warning *** Defaulting to default class for %s@%s",
2876 aconf->user, aconf->host);
2877 else
2878 sendto_realops_flags(UMODE_ALL, L_ALL,
2879 "Warning *** Defaulting to default class for %s",
2880 conf->name);
2881 aconf->class_ptr = class_default;
2882 }
2883 }
2884
2885 /* conf_add_server()
2886 *
2887 * inputs - pointer to config item
2888 * - pointer to link count already on this conf
2889 * output - NONE
2890 * side effects - Add a connect block
2891 */
2892 int
2893 conf_add_server(struct ConfItem *conf, const char *class_name)
2894 {
2895 struct AccessItem *aconf = map_to_conf(conf);
2896
2897 conf_add_class_to_conf(conf, class_name);
2898
2899 if (!aconf->host || !conf->name)
2900 {
2901 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
2902 ilog(LOG_TYPE_IRCD, "Bad connect block");
2903 return -1;
2904 }
2905
2906 if (EmptyString(aconf->passwd))
2907 {
2908 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
2909 conf->name);
2910 ilog(LOG_TYPE_IRCD, "Bad connect block, host %s", conf->name);
2911 return -1;
2912 }
2913
2914 lookup_confhost(conf);
2915
2916 return 0;
2917 }
2918
2919 /* yyerror()
2920 *
2921 * inputs - message from parser
2922 * output - NONE
2923 * side effects - message to opers and log file entry is made
2924 */
2925 void
2926 yyerror(const char *msg)
2927 {
2928 char newlinebuf[IRCD_BUFSIZE];
2929
2930 if (conf_parser_ctx.pass != 1)
2931 return;
2932
2933 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
2934 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
2935 conffilebuf, lineno + 1, msg, newlinebuf);
2936 ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s",
2937 conffilebuf, lineno + 1, msg, newlinebuf);
2938 }
2939
2940 /*
2941 * valid_tkline()
2942 *
2943 * inputs - pointer to ascii string to check
2944 * - whether the specified time is in seconds or minutes
2945 * output - -1 not enough parameters
2946 * - 0 if not an integer number, else the number
2947 * side effects - none
2948 * Originally written by Dianora (Diane, db@db.net)
2949 */
2950 time_t
2951 valid_tkline(const char *p, int minutes)
2952 {
2953 time_t result = 0;
2954
2955 for (; *p; ++p)
2956 {
2957 if (!IsDigit(*p))
2958 return 0;
2959
2960 result *= 10;
2961 result += ((*p) & 0xF);
2962 }
2963
2964 /*
2965 * In the degenerate case where oper does a /quote kline 0 user@host :reason
2966 * i.e. they specifically use 0, I am going to return 1 instead
2967 * as a return value of non-zero is used to flag it as a temporary kline
2968 */
2969 if (result == 0)
2970 result = 1;
2971
2972 /*
2973 * If the incoming time is in seconds convert it to minutes for the purpose
2974 * of this calculation
2975 */
2976 if (!minutes)
2977 result = result / (time_t)60;
2978
2979 if (result > MAX_TDKLINE_TIME)
2980 result = MAX_TDKLINE_TIME;
2981
2982 result = result * (time_t)60; /* turn it into seconds */
2983
2984 return result;
2985 }
2986
2987 /* valid_wild_card()
2988 *
2989 * input - pointer to client
2990 * - int flag, 0 for no warning oper 1 for warning oper
2991 * - count of following varargs to check
2992 * output - 0 if not valid, 1 if valid
2993 * side effects - NOTICE is given to source_p if warn is 1
2994 */
2995 int
2996 valid_wild_card(struct Client *source_p, int warn, int count, ...)
2997 {
2998 char *p;
2999 char tmpch;
3000 int nonwild = 0;
3001 va_list args;
3002
3003 /*
3004 * Now we must check the user and host to make sure there
3005 * are at least NONWILDCHARS non-wildcard characters in
3006 * them, otherwise assume they are attempting to kline
3007 * *@* or some variant of that. This code will also catch
3008 * people attempting to kline *@*.tld, as long as NONWILDCHARS
3009 * is greater than 3. In that case, there are only 3 non-wild
3010 * characters (tld), so if NONWILDCHARS is 4, the kline will
3011 * be disallowed.
3012 * -wnder
3013 */
3014
3015 va_start(args, count);
3016
3017 while (count--)
3018 {
3019 p = va_arg(args, char *);
3020 if (p == NULL)
3021 continue;
3022
3023 while ((tmpch = *p++))
3024 {
3025 if (!IsKWildChar(tmpch))
3026 {
3027 /*
3028 * If we find enough non-wild characters, we can
3029 * break - no point in searching further.
3030 */
3031 if (++nonwild >= ConfigFileEntry.min_nonwildcard)
3032 return 1;
3033 }
3034 }
3035 }
3036
3037 if (warn)
3038 sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
3039 me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
3040 return 0;
3041 }
3042
3043 /* XXX should this go into a separate file ? -Dianora */
3044 /* parse_aline
3045 *
3046 * input - pointer to cmd name being used
3047 * - pointer to client using cmd
3048 * - parc parameter count
3049 * - parv[] list of parameters to parse
3050 * - parse_flags bit map of things to test
3051 * - pointer to user or string to parse into
3052 * - pointer to host or NULL to parse into if non NULL
3053 * - pointer to optional tkline time or NULL
3054 * - pointer to target_server to parse into if non NULL
3055 * - pointer to reason to parse into
3056 *
3057 * output - 1 if valid, -1 if not valid
3058 * side effects - A generalised k/d/x etc. line parser,
3059 * "ALINE [time] user@host|string [ON] target :reason"
3060 * will parse returning a parsed user, host if
3061 * h_p pointer is non NULL, string otherwise.
3062 * if tkline_time pointer is non NULL a tk line will be set
3063 * to non zero if found.
3064 * if tkline_time pointer is NULL and tk line is found,
3065 * error is reported.
3066 * if target_server is NULL and an "ON" is found error
3067 * is reported.
3068 * if reason pointer is NULL ignore pointer,
3069 * this allows use of parse_a_line in unkline etc.
3070 *
3071 * - Dianora
3072 */
3073 int
3074 parse_aline(const char *cmd, struct Client *source_p,
3075 int parc, char **parv,
3076 int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
3077 char **target_server, char **reason)
3078 {
3079 int found_tkline_time=0;
3080 static char def_reason[] = "No Reason";
3081 static char user[USERLEN*4+1];
3082 static char host[HOSTLEN*4+1];
3083
3084 parv++;
3085 parc--;
3086
3087 found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3088
3089 if (found_tkline_time != 0)
3090 {
3091 parv++;
3092 parc--;
3093
3094 if (tkline_time != NULL)
3095 *tkline_time = found_tkline_time;
3096 else
3097 {
3098 sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3099 me.name, source_p->name, cmd);
3100 return -1;
3101 }
3102 }
3103
3104 if (parc == 0)
3105 {
3106 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3107 me.name, source_p->name, cmd);
3108 return -1;
3109 }
3110
3111 if (h_p == NULL)
3112 *up_p = *parv;
3113 else
3114 {
3115 if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3116 return -1;
3117
3118 *up_p = user;
3119 *h_p = host;
3120 }
3121
3122 parc--;
3123 parv++;
3124
3125 if (parc != 0)
3126 {
3127 if (irccmp(*parv, "ON") == 0)
3128 {
3129 parc--;
3130 parv++;
3131
3132 if (target_server == NULL)
3133 {
3134 sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3135 me.name, source_p->name, cmd);
3136 return -1;
3137 }
3138
3139 if (!HasOFlag(source_p, OPER_FLAG_REMOTEBAN))
3140 {
3141 sendto_one(source_p, form_str(ERR_NOPRIVS),
3142 me.name, source_p->name, "remoteban");
3143 return -1;
3144 }
3145
3146 if (parc == 0 || EmptyString(*parv))
3147 {
3148 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3149 me.name, source_p->name, cmd);
3150 return -1;
3151 }
3152
3153 *target_server = *parv;
3154 parc--;
3155 parv++;
3156 }
3157 else
3158 {
3159 /* Make sure target_server *is* NULL if no ON server found
3160 * caller probably NULL'd it first, but no harm to do it again -db
3161 */
3162 if (target_server != NULL)
3163 *target_server = NULL;
3164 }
3165 }
3166
3167 if (h_p != NULL)
3168 {
3169 if (strchr(user, '!') != NULL)
3170 {
3171 sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3172 me.name, source_p->name);
3173 return -1;
3174 }
3175
3176 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 2, *up_p, *h_p))
3177 return -1;
3178 }
3179 else
3180 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 1, *up_p))
3181 return -1;
3182
3183 if (reason != NULL)
3184 {
3185 if (parc != 0 && !EmptyString(*parv))
3186 {
3187 *reason = *parv;
3188 if (!valid_comment(source_p, *reason, 1))
3189 return -1;
3190 }
3191 else
3192 *reason = def_reason;
3193 }
3194
3195 return 1;
3196 }
3197
3198 /* find_user_host()
3199 *
3200 * inputs - pointer to client placing kline
3201 * - pointer to user_host_or_nick
3202 * - pointer to user buffer
3203 * - pointer to host buffer
3204 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3205 * side effects -
3206 */
3207 static int
3208 find_user_host(struct Client *source_p, char *user_host_or_nick,
3209 char *luser, char *lhost, unsigned int flags)
3210 {
3211 struct Client *target_p = NULL;
3212 char *hostp = NULL;
3213
3214 if (lhost == NULL)
3215 {
3216 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3217 return 1;
3218 }
3219
3220 if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3221 {
3222 /* Explicit user@host mask given */
3223
3224 if (hostp != NULL) /* I'm a little user@host */
3225 {
3226 *(hostp++) = '\0'; /* short and squat */
3227 if (*user_host_or_nick)
3228 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3229 else
3230 strcpy(luser, "*");
3231 if (*hostp)
3232 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3233 else
3234 strcpy(lhost, "*");
3235 }
3236 else
3237 {
3238 luser[0] = '*'; /* no @ found, assume its *@somehost */
3239 luser[1] = '\0';
3240 strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3241 }
3242
3243 return 1;
3244 }
3245 else if (!(flags & NOUSERLOOKUP))
3246 {
3247 /* Try to find user@host mask from nick */
3248 /* Okay to use source_p as the first param, because source_p == client_p */
3249 if ((target_p =
3250 find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3251 return 0;
3252
3253 if (IsExemptKline(target_p))
3254 {
3255 if (!IsServer(source_p))
3256 sendto_one(source_p,
3257 ":%s NOTICE %s :%s is E-lined",
3258 me.name, source_p->name, target_p->name);
3259 return 0;
3260 }
3261
3262 /*
3263 * turn the "user" bit into "*user", blow away '~'
3264 * if found in original user name (non-idented)
3265 */
3266 strlcpy(luser, target_p->username, USERLEN*4 + 1);
3267
3268 if (target_p->username[0] == '~')
3269 luser[0] = '*';
3270
3271 if (target_p->sockhost[0] == '\0' ||
3272 (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3273 strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3274 else
3275 strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3276 return 1;
3277 }
3278
3279 return 0;
3280 }
3281
3282 /* valid_comment()
3283 *
3284 * inputs - pointer to client
3285 * - pointer to comment
3286 * output - 0 if no valid comment,
3287 * - 1 if valid
3288 * side effects - truncates reason where necessary
3289 */
3290 int
3291 valid_comment(struct Client *source_p, char *comment, int warn)
3292 {
3293 if (strchr(comment, '"'))
3294 {
3295 if (warn)
3296 sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3297 me.name, source_p->name);
3298 return 0;
3299 }
3300
3301 if (strlen(comment) > REASONLEN)
3302 comment[REASONLEN-1] = '\0';
3303
3304 return 1;
3305 }
3306
3307 /* match_conf_password()
3308 *
3309 * inputs - pointer to given password
3310 * - pointer to Conf
3311 * output - 1 or 0 if match
3312 * side effects - none
3313 */
3314 int
3315 match_conf_password(const char *password, const struct AccessItem *aconf)
3316 {
3317 const char *encr = NULL;
3318
3319 if (password == NULL || aconf->passwd == NULL)
3320 return 0;
3321
3322 if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3323 {
3324 /* use first two chars of the password they send in as salt */
3325 /* If the password in the conf is MD5, and ircd is linked
3326 * to scrypt on FreeBSD, or the standard crypt library on
3327 * glibc Linux, then this code will work fine on generating
3328 * the proper encrypted hash for comparison.
3329 */
3330 if (*aconf->passwd)
3331 encr = crypt(password, aconf->passwd);
3332 else
3333 encr = "";
3334 }
3335 else
3336 encr = password;
3337
3338 return !strcmp(encr, aconf->passwd);
3339 }
3340
3341 /*
3342 * cluster_a_line
3343 *
3344 * inputs - client sending the cluster
3345 * - command name "KLINE" "XLINE" etc.
3346 * - capab -- CAP_KLN etc. from s_serv.h
3347 * - cluster type -- CLUSTER_KLINE etc. from conf.h
3348 * - pattern and args to send along
3349 * output - none
3350 * side effects - Take source_p send the pattern with args given
3351 * along to all servers that match capab and cluster type
3352 */
3353 void
3354 cluster_a_line(struct Client *source_p, const char *command,
3355 int capab, int cluster_type, const char *pattern, ...)
3356 {
3357 va_list args;
3358 char buffer[IRCD_BUFSIZE];
3359 const dlink_node *ptr = NULL;
3360
3361 va_start(args, pattern);
3362 vsnprintf(buffer, sizeof(buffer), pattern, args);
3363 va_end(args);
3364
3365 DLINK_FOREACH(ptr, cluster_items.head)
3366 {
3367 const struct ConfItem *conf = ptr->data;
3368
3369 if (conf->flags & cluster_type)
3370 sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3371 "%s %s %s", command, conf->name, buffer);
3372 }
3373 }
3374
3375 /*
3376 * split_nuh
3377 *
3378 * inputs - pointer to original mask (modified in place)
3379 * - pointer to pointer where nick should go
3380 * - pointer to pointer where user should go
3381 * - pointer to pointer where host should go
3382 * output - NONE
3383 * side effects - mask is modified in place
3384 * If nick pointer is NULL, ignore writing to it
3385 * this allows us to use this function elsewhere.
3386 *
3387 * mask nick user host
3388 * ---------------------- ------- ------- ------
3389 * Dianora!db@db.net Dianora db db.net
3390 * Dianora Dianora * *
3391 * db.net * * db.net
3392 * OR if nick pointer is NULL
3393 * Dianora - * Dianora
3394 * Dianora! Dianora * *
3395 * Dianora!@ Dianora * *
3396 * Dianora!db Dianora db *
3397 * Dianora!@db.net Dianora * db.net
3398 * db@db.net * db db.net
3399 * !@ * * *
3400 * @ * * *
3401 * ! * * *
3402 */
3403 void
3404 split_nuh(struct split_nuh_item *const iptr)
3405 {
3406 char *p = NULL, *q = NULL;
3407
3408 if (iptr->nickptr)
3409 strlcpy(iptr->nickptr, "*", iptr->nicksize);
3410 if (iptr->userptr)
3411 strlcpy(iptr->userptr, "*", iptr->usersize);
3412 if (iptr->hostptr)
3413 strlcpy(iptr->hostptr, "*", iptr->hostsize);
3414
3415 if ((p = strchr(iptr->nuhmask, '!')))
3416 {
3417 *p = '\0';
3418
3419 if (iptr->nickptr && *iptr->nuhmask != '\0')
3420 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3421
3422 if ((q = strchr(++p, '@'))) {
3423 *q++ = '\0';
3424
3425 if (*p != '\0')
3426 strlcpy(iptr->userptr, p, iptr->usersize);
3427
3428 if (*q != '\0')
3429 strlcpy(iptr->hostptr, q, iptr->hostsize);
3430 }
3431 else
3432 {
3433 if (*p != '\0')
3434 strlcpy(iptr->userptr, p, iptr->usersize);
3435 }
3436 }
3437 else
3438 {
3439 /* No ! found so lets look for a user@host */
3440 if ((p = strchr(iptr->nuhmask, '@')))
3441 {
3442 /* if found a @ */
3443 *p++ = '\0';
3444
3445 if (*iptr->nuhmask != '\0')
3446 strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
3447
3448 if (*p != '\0')
3449 strlcpy(iptr->hostptr, p, iptr->hostsize);
3450 }
3451 else
3452 {
3453 /* no @ found */
3454 if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
3455 strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
3456 else
3457 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3458 }
3459 }
3460 }
3461
3462 /*
3463 * flags_to_ascii
3464 *
3465 * inputs - flags is a bitmask
3466 * - pointer to table of ascii letters corresponding
3467 * to each bit
3468 * - flag 1 for convert ToLower if bit missing
3469 * 0 if ignore.
3470 * output - none
3471 * side effects - string pointed to by p has bitmap chars written to it
3472 */
3473 static void
3474 flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3475 int lowerit)
3476 {
3477 unsigned int mask = 1;
3478 int i = 0;
3479
3480 for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3481 {
3482 if (flags & mask)
3483 *p++ = bit_table[i];
3484 else if (lowerit)
3485 *p++ = ToLower(bit_table[i]);
3486 }
3487 *p = '\0';
3488 }
3489
3490 /*
3491 * cidr_limit_reached
3492 *
3493 * inputs - int flag allowing over_rule of limits
3494 * - pointer to the ip to be added
3495 * - pointer to the class
3496 * output - non zero if limit reached
3497 * 0 if limit not reached
3498 * side effects -
3499 */
3500 static int
3501 cidr_limit_reached(int over_rule,
3502 struct irc_ssaddr *ip, struct ClassItem *aclass)
3503 {
3504 dlink_node *ptr = NULL;
3505 struct CidrItem *cidr;
3506
3507 if (aclass->number_per_cidr <= 0)
3508 return 0;
3509
3510 if (ip->ss.ss_family == AF_INET)
3511 {
3512 if (aclass->cidr_bitlen_ipv4 <= 0)
3513 return 0;
3514
3515 DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3516 {
3517 cidr = ptr->data;
3518 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3519 {
3520 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3521 return -1;
3522 cidr->number_on_this_cidr++;
3523 return 0;
3524 }
3525 }
3526 cidr = MyMalloc(sizeof(struct CidrItem));
3527 cidr->number_on_this_cidr = 1;
3528 cidr->mask = *ip;
3529 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv4);
3530 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3531 }
3532 #ifdef IPV6
3533 else if (aclass->cidr_bitlen_ipv6 > 0)
3534 {
3535 DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3536 {
3537 cidr = ptr->data;
3538 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3539 {
3540 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3541 return -1;
3542 cidr->number_on_this_cidr++;
3543 return 0;
3544 }
3545 }
3546 cidr = MyMalloc(sizeof(struct CidrItem));
3547 cidr->number_on_this_cidr = 1;
3548 cidr->mask = *ip;
3549 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv6);
3550 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3551 }
3552 #endif
3553 return 0;
3554 }
3555
3556 /*
3557 * remove_from_cidr_check
3558 *
3559 * inputs - pointer to the ip to be removed
3560 * - pointer to the class
3561 * output - NONE
3562 * side effects -
3563 */
3564 static void
3565 remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3566 {
3567 dlink_node *ptr = NULL;
3568 dlink_node *next_ptr = NULL;
3569 struct CidrItem *cidr;
3570
3571 if (aclass->number_per_cidr == 0)
3572 return;
3573
3574 if (ip->ss.ss_family == AF_INET)
3575 {
3576 if (aclass->cidr_bitlen_ipv4 <= 0)
3577 return;
3578
3579 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3580 {
3581 cidr = ptr->data;
3582 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3583 {
3584 cidr->number_on_this_cidr--;
3585 if (cidr->number_on_this_cidr == 0)
3586 {
3587 dlinkDelete(ptr, &aclass->list_ipv4);
3588 MyFree(cidr);
3589 return;
3590 }
3591 }
3592 }
3593 }
3594 #ifdef IPV6
3595 else if (aclass->cidr_bitlen_ipv6 > 0)
3596 {
3597 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3598 {
3599 cidr = ptr->data;
3600 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3601 {
3602 cidr->number_on_this_cidr--;
3603 if (cidr->number_on_this_cidr == 0)
3604 {
3605 dlinkDelete(ptr, &aclass->list_ipv6);
3606 MyFree(cidr);
3607 return;
3608 }
3609 }
3610 }
3611 }
3612 #endif
3613 }
3614
3615 static void
3616 rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3617 dlink_list *old_list, dlink_list *new_list, int changed)
3618 {
3619 dlink_node *ptr;
3620 struct Client *client_p;
3621 struct ConfItem *conf;
3622 struct AccessItem *aconf;
3623
3624 if (!changed)
3625 {
3626 *new_list = *old_list;
3627 old_list->head = old_list->tail = NULL;
3628 old_list->length = 0;
3629 return;
3630 }
3631
3632 DLINK_FOREACH(ptr, local_client_list.head)
3633 {
3634 client_p = ptr->data;
3635 if (client_p->localClient->aftype != aftype)
3636 continue;
3637 if (dlink_list_length(&client_p->localClient->confs) == 0)
3638 continue;
3639
3640 conf = client_p->localClient->confs.tail->data;
3641 if (conf->type == CLIENT_TYPE)
3642 {
3643 aconf = map_to_conf(conf);
3644 if (aconf->class_ptr == oldcl)
3645 cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3646 }
3647 }
3648 }
3649
3650 /*
3651 * rebuild_cidr_class
3652 *
3653 * inputs - pointer to old conf
3654 * - pointer to new_class
3655 * output - none
3656 * side effects - rebuilds the class link list of cidr blocks
3657 */
3658 void
3659 rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3660 {
3661 struct ClassItem *old_class = map_to_conf(conf);
3662
3663 if (old_class->number_per_cidr > 0 && new_class->number_per_cidr > 0)
3664 {
3665 if (old_class->cidr_bitlen_ipv4 > 0 && new_class->cidr_bitlen_ipv4 > 0)
3666 rebuild_cidr_list(AF_INET, conf, new_class,
3667 &old_class->list_ipv4, &new_class->list_ipv4,
3668 old_class->cidr_bitlen_ipv4 != new_class->cidr_bitlen_ipv4);
3669
3670 #ifdef IPV6
3671 if (old_class->cidr_bitlen_ipv6 > 0 && new_class->cidr_bitlen_ipv6 > 0)
3672 rebuild_cidr_list(AF_INET6, conf, new_class,
3673 &old_class->list_ipv6, &new_class->list_ipv6,
3674 old_class->cidr_bitlen_ipv6 != new_class->cidr_bitlen_ipv6);
3675 #endif
3676 }
3677
3678 destroy_cidr_class(old_class);
3679 }
3680
3681 /*
3682 * destroy_cidr_list
3683 *
3684 * inputs - pointer to class dlink list of cidr blocks
3685 * output - none
3686 * side effects - completely destroys the class link list of cidr blocks
3687 */
3688 static void
3689 destroy_cidr_list(dlink_list *list)
3690 {
3691 dlink_node *ptr = NULL, *next_ptr = NULL;
3692
3693 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3694 {
3695 dlinkDelete(ptr, list);
3696 MyFree(ptr->data);
3697 }
3698 }
3699
3700 /*
3701 * destroy_cidr_class
3702 *
3703 * inputs - pointer to class
3704 * output - none
3705 * side effects - completely destroys the class link list of cidr blocks
3706 */
3707 static void
3708 destroy_cidr_class(struct ClassItem *aclass)
3709 {
3710 destroy_cidr_list(&aclass->list_ipv4);
3711 destroy_cidr_list(&aclass->list_ipv6);
3712 }

Properties

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