ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1363
Committed: Sun Apr 22 19:15:48 2012 UTC (13 years, 4 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 99481 byte(s)
Log Message:
- conf.c: remove unused prototypes

File Contents

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

Properties

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