ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1316
Committed: Tue Mar 27 17:05:51 2012 UTC (12 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 99937 byte(s)
Log Message:
- Removed 'ssl_server_protocol' configuration directive and
  added 'ssl_client_method' and 'ssl_server_method' instead.

  Both of these options can now be changed at runtime.

- src/Makefile.am: swapped order of conf_parser.y and conf_lexer.l
- Update example configuration files

File Contents

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

Properties

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