ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 992
Committed: Mon Aug 17 19:19:16 2009 UTC (14 years, 8 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100185 byte(s)
Log Message:
- fix possible auth/dns related memleaks

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

Properties

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