ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1157
Committed: Tue Aug 9 22:03:59 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_conf.c
File size: 100223 byte(s)
Log Message:
- preliminary services support

File Contents

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

Properties

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