ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/conf.c
Revision: 1123
Committed: Sun Feb 6 21:57:50 2011 UTC (13 years, 2 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.3/src/s_conf.c
File size: 99166 byte(s)
Log Message:
- Got rid of irc_addrinfo.c and irc_getnameinfo.c
- Fixed broken ipv6 detection due to incorrect use of AC_CHECK_TYPES

File Contents

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

Properties

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