ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1172
Committed: Sat Aug 13 18:49:37 2011 UTC (14 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_conf.c
File size: 100283 byte(s)
Log Message:
- update s_conf.c:map_to_list

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 SERVICE_TYPE:
1559 return(&service_items);
1560 break;
1561 case CLUSTER_TYPE:
1562 return(&cluster_items);
1563 break;
1564 case CONF_TYPE:
1565 case GLINE_TYPE:
1566 case KLINE_TYPE:
1567 case DLINE_TYPE:
1568 case CRESV_TYPE:
1569 default:
1570 return NULL;
1571 }
1572 }
1573
1574 /* find_matching_name_conf()
1575 *
1576 * inputs - type of link list to look in
1577 * - pointer to name string to find
1578 * - pointer to user
1579 * - pointer to host
1580 * - optional action to match on as well
1581 * output - NULL or pointer to found struct MatchItem
1582 * side effects - looks for a match on name field
1583 */
1584 struct ConfItem *
1585 find_matching_name_conf(ConfType type, const char *name, const char *user,
1586 const char *host, int action)
1587 {
1588 dlink_node *ptr=NULL;
1589 struct ConfItem *conf=NULL;
1590 struct AccessItem *aconf=NULL;
1591 struct MatchItem *match_item=NULL;
1592 dlink_list *list_p = map_to_list(type);
1593
1594 switch (type)
1595 {
1596 #ifdef HAVE_LIBPCRE
1597 case RXLINE_TYPE:
1598 DLINK_FOREACH(ptr, list_p->head)
1599 {
1600 conf = ptr->data;
1601 assert(conf->regexpname);
1602
1603 if (!ircd_pcre_exec(conf->regexpname, name))
1604 return conf;
1605 }
1606 break;
1607 #endif
1608 case SERVICE_TYPE:
1609 DLINK_FOREACH(ptr, list_p->head)
1610 {
1611 conf = ptr->data;
1612
1613 if (EmptyString(conf->name))
1614 continue;
1615 if ((name != NULL) && !irccmp(name, conf->name))
1616 return conf;
1617 }
1618 break;
1619
1620 case XLINE_TYPE:
1621 case ULINE_TYPE:
1622 case NRESV_TYPE:
1623 DLINK_FOREACH(ptr, list_p->head)
1624 {
1625 conf = ptr->data;
1626
1627 match_item = map_to_conf(conf);
1628 if (EmptyString(conf->name))
1629 continue;
1630 if ((name != NULL) && match_esc(conf->name, name))
1631 {
1632 if ((user == NULL && (host == NULL)))
1633 return conf;
1634 if ((match_item->action & action) != action)
1635 continue;
1636 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1637 return conf;
1638 if (match(match_item->user, user) && match(match_item->host, host))
1639 return conf;
1640 }
1641 }
1642 break;
1643
1644 case SERVER_TYPE:
1645 DLINK_FOREACH(ptr, list_p->head)
1646 {
1647 conf = ptr->data;
1648 aconf = map_to_conf(conf);
1649
1650 if ((name != NULL) && match_esc(name, conf->name))
1651 return conf;
1652 else if ((host != NULL) && match_esc(host, aconf->host))
1653 return conf;
1654 }
1655 break;
1656
1657 default:
1658 break;
1659 }
1660 return NULL;
1661 }
1662
1663 /* find_exact_name_conf()
1664 *
1665 * inputs - type of link list to look in
1666 * - pointer to name string to find
1667 * - pointer to user
1668 * - pointer to host
1669 * output - NULL or pointer to found struct MatchItem
1670 * side effects - looks for an exact match on name field
1671 */
1672 struct ConfItem *
1673 find_exact_name_conf(ConfType type, const char *name,
1674 const char *user, const char *host)
1675 {
1676 dlink_node *ptr = NULL;
1677 struct AccessItem *aconf;
1678 struct ConfItem *conf;
1679 struct MatchItem *match_item;
1680 dlink_list *list_p;
1681
1682 list_p = map_to_list(type);
1683
1684 switch(type)
1685 {
1686 case RXLINE_TYPE:
1687 case XLINE_TYPE:
1688 case ULINE_TYPE:
1689 case NRESV_TYPE:
1690
1691 DLINK_FOREACH(ptr, list_p->head)
1692 {
1693 conf = ptr->data;
1694 match_item = (struct MatchItem *)map_to_conf(conf);
1695 if (EmptyString(conf->name))
1696 continue;
1697
1698 if (irccmp(conf->name, name) == 0)
1699 {
1700 if ((user == NULL && (host == NULL)))
1701 return (conf);
1702 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1703 return (conf);
1704 if (match(match_item->user, user) && match(match_item->host, host))
1705 return (conf);
1706 }
1707 }
1708 break;
1709
1710 case OPER_TYPE:
1711 DLINK_FOREACH(ptr, list_p->head)
1712 {
1713 conf = ptr->data;
1714 aconf = (struct AccessItem *)map_to_conf(conf);
1715 if (EmptyString(conf->name))
1716 continue;
1717
1718 if (irccmp(conf->name, name) == 0)
1719 {
1720 if ((user == NULL && (host == NULL)))
1721 return (conf);
1722 if (EmptyString(aconf->user) || EmptyString(aconf->host))
1723 return (conf);
1724 if (match(aconf->user, user) && match(aconf->host, host))
1725 return (conf);
1726 }
1727 }
1728 break;
1729
1730 case SERVER_TYPE:
1731 DLINK_FOREACH(ptr, list_p->head)
1732 {
1733 conf = ptr->data;
1734 aconf = (struct AccessItem *)map_to_conf(conf);
1735 if (EmptyString(conf->name))
1736 continue;
1737
1738 if (name == NULL)
1739 {
1740 if (EmptyString(aconf->host))
1741 continue;
1742 if (irccmp(aconf->host, host) == 0)
1743 return(conf);
1744 }
1745 else if (irccmp(conf->name, name) == 0)
1746 {
1747 return (conf);
1748 }
1749 }
1750 break;
1751
1752 case CLASS_TYPE:
1753 DLINK_FOREACH(ptr, list_p->head)
1754 {
1755 conf = ptr->data;
1756 if (EmptyString(conf->name))
1757 continue;
1758
1759 if (irccmp(conf->name, name) == 0)
1760 return (conf);
1761 }
1762 break;
1763
1764 default:
1765 break;
1766 }
1767 return(NULL);
1768 }
1769
1770 /* rehash()
1771 *
1772 * Actual REHASH service routine. Called with sig == 0 if it has been called
1773 * as a result of an operator issuing this command, else assume it has been
1774 * called as a result of the server receiving a HUP signal.
1775 */
1776 int
1777 rehash(int sig)
1778 {
1779 if (sig != 0)
1780 sendto_realops_flags(UMODE_ALL, L_ALL,
1781 "Got signal SIGHUP, reloading ircd.conf file");
1782
1783 restart_resolver();
1784
1785 /* don't close listeners until we know we can go ahead with the rehash */
1786
1787 /* Check to see if we magically got(or lost) IPv6 support */
1788 check_can_use_v6();
1789
1790 read_conf_files(0);
1791
1792 if (ServerInfo.description != NULL)
1793 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
1794
1795 load_conf_modules();
1796
1797 flush_deleted_I_P();
1798
1799 rehashed_klines = 1;
1800
1801 if (ConfigLoggingEntry.use_logging)
1802 reopen_log(logFileName);
1803
1804 return(0);
1805 }
1806
1807 /* set_default_conf()
1808 *
1809 * inputs - NONE
1810 * output - NONE
1811 * side effects - Set default values here.
1812 * This is called **PRIOR** to parsing the
1813 * configuration file. If you want to do some validation
1814 * of values later, put them in validate_conf().
1815 */
1816 static void
1817 set_default_conf(void)
1818 {
1819 /* verify init_class() ran, this should be an unnecessary check
1820 * but its not much work.
1821 */
1822 assert(class_default == (struct ConfItem *) class_items.tail->data);
1823
1824 #ifdef HAVE_LIBCRYPTO
1825 ServerInfo.rsa_private_key = NULL;
1826 ServerInfo.rsa_private_key_file = NULL;
1827 #endif
1828
1829 /* ServerInfo.name is not rehashable */
1830 /* ServerInfo.name = ServerInfo.name; */
1831 ServerInfo.description = NULL;
1832 DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
1833 DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
1834
1835 memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
1836 ServerInfo.specific_ipv4_vhost = 0;
1837 memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
1838 ServerInfo.specific_ipv6_vhost = 0;
1839
1840 ServerInfo.max_clients = MAXCLIENTS_MAX;
1841
1842 ServerInfo.hub = 0;
1843 ServerInfo.dns_host.sin_addr.s_addr = 0;
1844 ServerInfo.dns_host.sin_port = 0;
1845 AdminInfo.name = NULL;
1846 AdminInfo.email = NULL;
1847 AdminInfo.description = NULL;
1848
1849 set_log_level(L_NOTICE);
1850 ConfigLoggingEntry.use_logging = 1;
1851 ConfigLoggingEntry.operlog[0] = '\0';
1852 ConfigLoggingEntry.userlog[0] = '\0';
1853 ConfigLoggingEntry.klinelog[0] = '\0';
1854 ConfigLoggingEntry.glinelog[0] = '\0';
1855 ConfigLoggingEntry.killlog[0] = '\0';
1856 ConfigLoggingEntry.operspylog[0] = '\0';
1857 ConfigLoggingEntry.ioerrlog[0] = '\0';
1858 ConfigLoggingEntry.failed_operlog[0] = '\0';
1859
1860 ConfigChannel.disable_fake_channels = NO;
1861 ConfigChannel.restrict_channels = NO;
1862 ConfigChannel.disable_local_channels = NO;
1863 ConfigChannel.use_invex = YES;
1864 ConfigChannel.use_except = YES;
1865 ConfigChannel.use_knock = YES;
1866 ConfigChannel.knock_delay = 300;
1867 ConfigChannel.knock_delay_channel = 60;
1868 ConfigChannel.max_chans_per_user = 15;
1869 ConfigChannel.quiet_on_ban = YES;
1870 ConfigChannel.max_bans = 25;
1871 ConfigChannel.default_split_user_count = 0;
1872 ConfigChannel.default_split_server_count = 0;
1873 ConfigChannel.no_join_on_split = NO;
1874 ConfigChannel.no_create_on_split = NO;
1875 ConfigChannel.burst_topicwho = YES;
1876
1877 ConfigServerHide.flatten_links = NO;
1878 ConfigServerHide.links_delay = 300;
1879 ConfigServerHide.hidden = NO;
1880 ConfigServerHide.disable_hidden = NO;
1881 ConfigServerHide.hide_servers = NO;
1882 DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1883 ConfigServerHide.hide_server_ips = NO;
1884
1885
1886 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1887 ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
1888 ConfigFileEntry.gline_min_cidr = 16;
1889 ConfigFileEntry.gline_min_cidr6 = 48;
1890 ConfigFileEntry.invisible_on_connect = YES;
1891 ConfigFileEntry.burst_away = NO;
1892 ConfigFileEntry.use_whois_actually = YES;
1893 ConfigFileEntry.tkline_expire_notices = YES;
1894 ConfigFileEntry.hide_spoof_ips = YES;
1895 ConfigFileEntry.ignore_bogus_ts = NO;
1896 ConfigFileEntry.disable_auth = NO;
1897 ConfigFileEntry.disable_remote = NO;
1898 ConfigFileEntry.kill_chase_time_limit = 90;
1899 ConfigFileEntry.default_floodcount = 8;
1900 ConfigFileEntry.failed_oper_notice = YES;
1901 ConfigFileEntry.dots_in_ident = 0;
1902 ConfigFileEntry.min_nonwildcard = 4;
1903 ConfigFileEntry.min_nonwildcard_simple = 3;
1904 ConfigFileEntry.max_accept = 20;
1905 ConfigFileEntry.anti_nick_flood = NO;
1906 ConfigFileEntry.max_nick_time = 20;
1907 ConfigFileEntry.max_nick_changes = 5;
1908 ConfigFileEntry.anti_spam_exit_message_time = 0;
1909 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1910 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1911 ConfigFileEntry.kline_with_reason = YES;
1912 ConfigFileEntry.kline_reason = NULL;
1913 ConfigFileEntry.warn_no_nline = YES;
1914 ConfigFileEntry.stats_o_oper_only = NO;
1915 ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1916 ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1917 ConfigFileEntry.stats_P_oper_only = NO;
1918 ConfigFileEntry.caller_id_wait = 60;
1919 ConfigFileEntry.opers_bypass_callerid = NO;
1920 ConfigFileEntry.pace_wait = 10;
1921 ConfigFileEntry.pace_wait_simple = 1;
1922 ConfigFileEntry.short_motd = NO;
1923 ConfigFileEntry.ping_cookie = NO;
1924 ConfigFileEntry.no_oper_flood = NO;
1925 ConfigFileEntry.true_no_oper_flood = NO;
1926 ConfigFileEntry.oper_pass_resv = YES;
1927 ConfigFileEntry.glines = NO;
1928 ConfigFileEntry.gline_time = 12 * 3600;
1929 ConfigFileEntry.idletime = 0;
1930 ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1931 ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
1932 ConfigFileEntry.oper_only_umodes = UMODE_DEBUG;
1933 ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
1934 UMODE_OPERWALL | UMODE_WALLOP;
1935 DupString(ConfigFileEntry.servlink_path, SLPATH);
1936 #ifdef HAVE_LIBCRYPTO
1937 /* jdc -- This is our default value for a cipher. According to the
1938 * CRYPTLINK document (doc/cryptlink.txt), BF/128 must be supported
1939 * under all circumstances if cryptlinks are enabled. So,
1940 * this will be our default.
1941 *
1942 * NOTE: I apologise for the hard-coded value of "1" (BF/128).
1943 * This should be moved into a find_cipher() routine.
1944 */
1945 ConfigFileEntry.default_cipher_preference = &CipherTable[1];
1946 #endif
1947 ConfigFileEntry.use_egd = NO;
1948 ConfigFileEntry.egdpool_path = NULL;
1949 #ifdef HAVE_LIBZ
1950 ConfigFileEntry.compression_level = 0;
1951 #endif
1952 ConfigFileEntry.throttle_time = 10;
1953 }
1954
1955 /* read_conf()
1956 *
1957 * inputs - file descriptor pointing to config file to use
1958 * output - None
1959 * side effects - Read configuration file.
1960 */
1961 static void
1962 read_conf(FBFILE *file)
1963 {
1964 lineno = 0;
1965
1966 set_default_conf(); /* Set default values prior to conf parsing */
1967 conf_parser_ctx.pass = 1;
1968 yyparse(); /* pick up the classes first */
1969
1970 fbrewind(file);
1971
1972 conf_parser_ctx.pass = 2;
1973 yyparse(); /* Load the values from the conf */
1974 validate_conf(); /* Check to make sure some values are still okay. */
1975 /* Some global values are also loaded here. */
1976 check_class(); /* Make sure classes are valid */
1977 }
1978
1979 static void
1980 validate_conf(void)
1981 {
1982 if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1983 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1984
1985 if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1986 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1987
1988 if (ConfigFileEntry.servlink_path == NULL)
1989 DupString(ConfigFileEntry.servlink_path, SLPATH);
1990
1991 if (ServerInfo.network_name == NULL)
1992 DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1993
1994 if (ServerInfo.network_desc == NULL)
1995 DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1996
1997 if (ConfigFileEntry.service_name == NULL)
1998 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1999
2000 if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
2001 (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
2002 ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
2003
2004 ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
2005 }
2006
2007 /* lookup_confhost()
2008 *
2009 * start DNS lookups of all hostnames in the conf
2010 * line and convert an IP addresses in a.b.c.d number for to IP#s.
2011 */
2012 static void
2013 lookup_confhost(struct ConfItem *conf)
2014 {
2015 struct AccessItem *aconf;
2016 struct addrinfo hints, *res;
2017
2018 aconf = map_to_conf(conf);
2019
2020 if (EmptyString(aconf->host) ||
2021 EmptyString(aconf->user))
2022 {
2023 ilog(L_ERROR, "Host/server name error: (%s) (%s)",
2024 aconf->host, conf->name);
2025 return;
2026 }
2027
2028 if (strchr(aconf->host, '*') ||
2029 strchr(aconf->host, '?'))
2030 return;
2031
2032 /* Do name lookup now on hostnames given and store the
2033 * ip numbers in conf structure.
2034 */
2035 memset(&hints, 0, sizeof(hints));
2036
2037 hints.ai_family = AF_UNSPEC;
2038 hints.ai_socktype = SOCK_STREAM;
2039
2040 /* Get us ready for a bind() and don't bother doing dns lookup */
2041 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2042
2043 if (getaddrinfo(aconf->host, NULL, &hints, &res))
2044 {
2045 conf_dns_lookup(aconf);
2046 return;
2047 }
2048
2049 assert(res != NULL);
2050
2051 memcpy(&aconf->ipnum, res->ai_addr, res->ai_addrlen);
2052 aconf->ipnum.ss_len = res->ai_addrlen;
2053 aconf->ipnum.ss.ss_family = res->ai_family;
2054 freeaddrinfo(res);
2055 }
2056
2057 /* conf_connect_allowed()
2058 *
2059 * inputs - pointer to inaddr
2060 * - int type ipv4 or ipv6
2061 * output - BANNED or accepted
2062 * side effects - none
2063 */
2064 int
2065 conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
2066 {
2067 struct ip_entry *ip_found;
2068 struct AccessItem *aconf = find_dline_conf(addr, aftype);
2069
2070 /* DLINE exempt also gets you out of static limits/pacing... */
2071 if (aconf && (aconf->status & CONF_EXEMPTDLINE))
2072 return 0;
2073
2074 if (aconf != NULL)
2075 return BANNED_CLIENT;
2076
2077 ip_found = find_or_add_ip(addr);
2078
2079 if ((CurrentTime - ip_found->last_attempt) <
2080 ConfigFileEntry.throttle_time)
2081 {
2082 ip_found->last_attempt = CurrentTime;
2083 return TOO_FAST;
2084 }
2085
2086 ip_found->last_attempt = CurrentTime;
2087 return 0;
2088 }
2089
2090 static struct AccessItem *
2091 find_regexp_kline(const char *uhi[])
2092 {
2093 #ifdef HAVE_LIBPCRE
2094 const dlink_node *ptr = NULL;
2095
2096 DLINK_FOREACH(ptr, rkconf_items.head)
2097 {
2098 struct AccessItem *aptr = map_to_conf(ptr->data);
2099
2100 assert(aptr->regexuser);
2101 assert(aptr->regexhost);
2102
2103 if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
2104 (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
2105 !ircd_pcre_exec(aptr->regexhost, uhi[2])))
2106 return aptr;
2107 }
2108 #endif
2109 return NULL;
2110 }
2111
2112 /* find_kill()
2113 *
2114 * inputs - pointer to client structure
2115 * output - pointer to struct AccessItem if found
2116 * side effects - See if this user is klined already,
2117 * and if so, return struct AccessItem pointer
2118 */
2119 struct AccessItem *
2120 find_kill(struct Client *client_p)
2121 {
2122 struct AccessItem *aconf = NULL;
2123 const char *uhi[3];
2124
2125 uhi[0] = client_p->username;
2126 uhi[1] = client_p->host;
2127 uhi[2] = client_p->sockhost;
2128
2129 assert(client_p != NULL);
2130
2131 aconf = find_kline_conf(client_p->host, client_p->username,
2132 &client_p->localClient->ip,
2133 client_p->localClient->aftype);
2134 if (aconf == NULL)
2135 aconf = find_regexp_kline(uhi);
2136
2137 if (aconf && (aconf->status & CONF_KLINE))
2138 return aconf;
2139
2140 return NULL;
2141 }
2142
2143 struct AccessItem *
2144 find_gline(struct Client *client_p)
2145 {
2146 struct AccessItem *aconf;
2147
2148 assert(client_p != NULL);
2149
2150 aconf = find_gline_conf(client_p->host, client_p->username,
2151 &client_p->localClient->ip,
2152 client_p->localClient->aftype);
2153
2154 if (aconf && (aconf->status & CONF_GLINE))
2155 return aconf;
2156
2157 return NULL;
2158 }
2159
2160 /* add_temp_line()
2161 *
2162 * inputs - pointer to struct ConfItem
2163 * output - none
2164 * Side effects - links in given struct ConfItem into
2165 * temporary *line link list
2166 */
2167 void
2168 add_temp_line(struct ConfItem *conf)
2169 {
2170 struct AccessItem *aconf;
2171
2172 if (conf->type == DLINE_TYPE)
2173 {
2174 aconf = map_to_conf(conf);
2175 SetConfTemporary(aconf);
2176 dlinkAdd(conf, &conf->node, &temporary_dlines);
2177 MyFree(aconf->user);
2178 aconf->user = NULL;
2179 add_conf_by_address(CONF_DLINE, aconf);
2180 }
2181 else if (conf->type == KLINE_TYPE)
2182 {
2183 aconf = map_to_conf(conf);
2184 SetConfTemporary(aconf);
2185 dlinkAdd(conf, &conf->node, &temporary_klines);
2186 add_conf_by_address(CONF_KILL, aconf);
2187 }
2188 else if (conf->type == GLINE_TYPE)
2189 {
2190 aconf = map_to_conf(conf);
2191 SetConfTemporary(aconf);
2192 dlinkAdd(conf, &conf->node, &temporary_glines);
2193 add_conf_by_address(CONF_GLINE, aconf);
2194 }
2195 else if (conf->type == XLINE_TYPE)
2196 {
2197 conf->flags |= CONF_FLAGS_TEMPORARY;
2198 dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
2199 }
2200 else if (conf->type == RXLINE_TYPE)
2201 {
2202 conf->flags |= CONF_FLAGS_TEMPORARY;
2203 dlinkAdd(conf, make_dlink_node(), &temporary_rxlines);
2204 }
2205 else if (conf->type == RKLINE_TYPE)
2206 {
2207 conf->flags |= CONF_FLAGS_TEMPORARY;
2208 dlinkAdd(conf, make_dlink_node(), &temporary_rklines);
2209 }
2210 else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
2211 {
2212 conf->flags |= CONF_FLAGS_TEMPORARY;
2213 dlinkAdd(conf, make_dlink_node(), &temporary_resv);
2214 }
2215 }
2216
2217 /* cleanup_tklines()
2218 *
2219 * inputs - NONE
2220 * output - NONE
2221 * side effects - call function to expire temporary k/d lines
2222 * This is an event started off in ircd.c
2223 */
2224 void
2225 cleanup_tklines(void *notused)
2226 {
2227 expire_tklines(&temporary_glines);
2228 expire_tklines(&temporary_klines);
2229 expire_tklines(&temporary_dlines);
2230 expire_tklines(&temporary_xlines);
2231 expire_tklines(&temporary_rxlines);
2232 expire_tklines(&temporary_rklines);
2233 expire_tklines(&temporary_resv);
2234 }
2235
2236 /* expire_tklines()
2237 *
2238 * inputs - tkline list pointer
2239 * output - NONE
2240 * side effects - expire tklines
2241 */
2242 static void
2243 expire_tklines(dlink_list *tklist)
2244 {
2245 dlink_node *ptr;
2246 dlink_node *next_ptr;
2247 struct ConfItem *conf;
2248 struct MatchItem *xconf;
2249 struct MatchItem *nconf;
2250 struct AccessItem *aconf;
2251 struct ResvChannel *cconf;
2252
2253 DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2254 {
2255 conf = ptr->data;
2256 if (conf->type == GLINE_TYPE ||
2257 conf->type == KLINE_TYPE ||
2258 conf->type == DLINE_TYPE)
2259 {
2260 aconf = (struct AccessItem *)map_to_conf(conf);
2261 if (aconf->hold <= CurrentTime)
2262 {
2263 /* XXX - Do we want GLINE expiry notices?? */
2264 /* Alert opers that a TKline expired - Hwy */
2265 if (ConfigFileEntry.tkline_expire_notices)
2266 {
2267 if (aconf->status & CONF_KILL)
2268 {
2269 sendto_realops_flags(UMODE_ALL, L_ALL,
2270 "Temporary K-line for [%s@%s] expired",
2271 (aconf->user) ? aconf->user : "*",
2272 (aconf->host) ? aconf->host : "*");
2273 }
2274 else if (conf->type == DLINE_TYPE)
2275 {
2276 sendto_realops_flags(UMODE_ALL, L_ALL,
2277 "Temporary D-line for [%s] expired",
2278 (aconf->host) ? aconf->host : "*");
2279 }
2280 }
2281
2282 dlinkDelete(ptr, tklist);
2283 delete_one_address_conf(aconf->host, aconf);
2284 }
2285 }
2286 else if (conf->type == XLINE_TYPE ||
2287 conf->type == RXLINE_TYPE)
2288 {
2289 xconf = (struct MatchItem *)map_to_conf(conf);
2290 if (xconf->hold <= CurrentTime)
2291 {
2292 if (ConfigFileEntry.tkline_expire_notices)
2293 sendto_realops_flags(UMODE_ALL, L_ALL,
2294 "Temporary X-line for [%s] %sexpired", conf->name,
2295 conf->type == RXLINE_TYPE ? "(REGEX) " : "");
2296 dlinkDelete(ptr, tklist);
2297 free_dlink_node(ptr);
2298 delete_conf_item(conf);
2299 }
2300 }
2301 else if (conf->type == RKLINE_TYPE)
2302 {
2303 aconf = map_to_conf(conf);
2304 if (aconf->hold <= CurrentTime)
2305 {
2306 if (ConfigFileEntry.tkline_expire_notices)
2307 sendto_realops_flags(UMODE_ALL, L_ALL,
2308 "Temporary K-line for [%s@%s] (REGEX) expired",
2309 (aconf->user) ? aconf->user : "*",
2310 (aconf->host) ? aconf->host : "*");
2311 dlinkDelete(ptr, tklist);
2312 free_dlink_node(ptr);
2313 delete_conf_item(conf);
2314 }
2315 }
2316 else if (conf->type == NRESV_TYPE)
2317 {
2318 nconf = (struct MatchItem *)map_to_conf(conf);
2319 if (nconf->hold <= CurrentTime)
2320 {
2321 if (ConfigFileEntry.tkline_expire_notices)
2322 sendto_realops_flags(UMODE_ALL, L_ALL,
2323 "Temporary RESV for [%s] expired", conf->name);
2324 dlinkDelete(ptr, tklist);
2325 free_dlink_node(ptr);
2326 delete_conf_item(conf);
2327 }
2328 }
2329 else if (conf->type == CRESV_TYPE)
2330 {
2331 cconf = (struct ResvChannel *)map_to_conf(conf);
2332 if (cconf->hold <= CurrentTime)
2333 {
2334 if (ConfigFileEntry.tkline_expire_notices)
2335 sendto_realops_flags(UMODE_ALL, L_ALL,
2336 "Temporary RESV for [%s] expired", cconf->name);
2337 delete_channel_resv(cconf);
2338 }
2339 }
2340 }
2341 }
2342
2343 /* oper_privs_as_string()
2344 *
2345 * inputs - pointer to client_p
2346 * output - pointer to static string showing oper privs
2347 * side effects - return as string, the oper privs as derived from port
2348 */
2349 static const struct oper_privs
2350 {
2351 const unsigned int oprivs;
2352 const unsigned int hidden;
2353 const unsigned char c;
2354 } flag_list[] = {
2355 { OPER_FLAG_ADMIN, OPER_FLAG_HIDDEN_ADMIN, 'A' },
2356 { OPER_FLAG_REMOTEBAN, 0, 'B' },
2357 { OPER_FLAG_DIE, 0, 'D' },
2358 { OPER_FLAG_GLINE, 0, 'G' },
2359 { OPER_FLAG_REHASH, 0, 'H' },
2360 { OPER_FLAG_K, 0, 'K' },
2361 { OPER_FLAG_OPERWALL, 0, 'L' },
2362 { OPER_FLAG_N, 0, 'N' },
2363 { OPER_FLAG_GLOBAL_KILL, 0, 'O' },
2364 { OPER_FLAG_REMOTE, 0, 'R' },
2365 { OPER_FLAG_OPER_SPY, 0, 'S' },
2366 { OPER_FLAG_UNKLINE, 0, 'U' },
2367 { OPER_FLAG_X, 0, 'X' },
2368 { 0, 0, '\0' }
2369 };
2370
2371 char *
2372 oper_privs_as_string(const unsigned int port)
2373 {
2374 static char privs_out[16];
2375 char *privs_ptr = privs_out;
2376 unsigned int i = 0;
2377
2378 for (; flag_list[i].oprivs; ++i)
2379 {
2380 if ((port & flag_list[i].oprivs) &&
2381 (port & flag_list[i].hidden) == 0)
2382 *privs_ptr++ = flag_list[i].c;
2383 else
2384 *privs_ptr++ = ToLowerTab[flag_list[i].c];
2385 }
2386
2387 *privs_ptr = '\0';
2388
2389 return privs_out;
2390 }
2391
2392 /*
2393 * Input: A client to find the active oper{} name for.
2394 * Output: The nick!user@host{oper} of the oper.
2395 * "oper" is server name for remote opers
2396 * Side effects: None.
2397 */
2398 char *
2399 get_oper_name(const struct Client *client_p)
2400 {
2401 dlink_node *cnode;
2402 struct ConfItem *conf;
2403 struct AccessItem *aconf;
2404
2405 /* +5 for !,@,{,} and null */
2406 static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
2407
2408 if (MyConnect(client_p))
2409 {
2410 DLINK_FOREACH(cnode, client_p->localClient->confs.head)
2411 {
2412 conf = cnode->data;
2413 aconf = map_to_conf(conf);
2414
2415 if (IsConfOperator(aconf))
2416 {
2417 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2418 client_p->username, client_p->host, conf->name);
2419 return buffer;
2420 }
2421 }
2422
2423 /* Probably should assert here for now. If there is an oper out there
2424 * with no oper{} conf attached, it would be good for us to know...
2425 */
2426 assert(0); /* Oper without oper conf! */
2427 }
2428
2429 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2430 client_p->username, client_p->host, client_p->servptr->name);
2431 return buffer;
2432 }
2433
2434 /* read_conf_files()
2435 *
2436 * inputs - cold start YES or NO
2437 * output - none
2438 * side effects - read all conf files needed, ircd.conf kline.conf etc.
2439 */
2440 void
2441 read_conf_files(int cold)
2442 {
2443 const char *filename;
2444 char chanmodes[32];
2445 char chanlimit[32];
2446
2447 conf_parser_ctx.boot = cold;
2448 filename = get_conf_name(CONF_TYPE);
2449
2450 /* We need to know the initial filename for the yyerror() to report
2451 FIXME: The full path is in conffilenamebuf first time since we
2452 dont know anything else
2453
2454 - Gozem 2002-07-21
2455 */
2456 strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2457
2458 if ((conf_parser_ctx.conf_file = fbopen(filename, "r")) == NULL)
2459 {
2460 if (cold)
2461 {
2462 ilog(L_CRIT, "Unable to read configuration file '%s': %s",
2463 filename, strerror(errno));
2464 exit(-1);
2465 }
2466 else
2467 {
2468 sendto_realops_flags(UMODE_ALL, L_ALL,
2469 "Unable to read configuration file '%s': %s",
2470 filename, strerror(errno));
2471 return;
2472 }
2473 }
2474
2475 if (!cold)
2476 clear_out_old_conf();
2477
2478 read_conf(conf_parser_ctx.conf_file);
2479 fbclose(conf_parser_ctx.conf_file);
2480
2481 add_isupport("NETWORK", ServerInfo.network_name, -1);
2482 snprintf(chanmodes, sizeof(chanmodes), "b%s%s:%d",
2483 ConfigChannel.use_except ? "e" : "",
2484 ConfigChannel.use_invex ? "I" : "", ConfigChannel.max_bans);
2485 add_isupport("MAXLIST", chanmodes, -1);
2486 add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2487
2488 if (ConfigChannel.disable_local_channels)
2489 add_isupport("CHANTYPES", "#", -1);
2490 else
2491 add_isupport("CHANTYPES", "#&", -1);
2492
2493 snprintf(chanlimit, sizeof(chanlimit), "%s:%d",
2494 ConfigChannel.disable_local_channels ? "#" : "#&",
2495 ConfigChannel.max_chans_per_user);
2496 add_isupport("CHANLIMIT", chanlimit, -1);
2497 snprintf(chanmodes, sizeof(chanmodes), "%s%s%s",
2498 ConfigChannel.use_except ? "e" : "",
2499 ConfigChannel.use_invex ? "I" : "", "b,k,l,imnpstOS");
2500 add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
2501
2502 if (ConfigChannel.use_except)
2503 add_isupport("EXCEPTS", "e", -1);
2504 if (ConfigChannel.use_invex)
2505 add_isupport("INVEX", "I", -1);
2506 add_isupport("CHANMODES", chanmodes, -1);
2507
2508 /*
2509 * message_locale may have changed. rebuild isupport since it relies
2510 * on strlen(form_str(RPL_ISUPPORT))
2511 */
2512 rebuild_isupport_message_line();
2513
2514 #ifdef HAVE_LIBPCRE
2515 parse_conf_file(RKLINE_TYPE, cold);
2516 parse_conf_file(RXLINE_TYPE, cold);
2517 #endif
2518 parse_conf_file(KLINE_TYPE, cold);
2519 parse_conf_file(DLINE_TYPE, cold);
2520 parse_conf_file(XLINE_TYPE, cold);
2521 parse_conf_file(NRESV_TYPE, cold);
2522 parse_conf_file(CRESV_TYPE, cold);
2523 }
2524
2525 /* parse_conf_file()
2526 *
2527 * inputs - type of conf file to parse
2528 * output - none
2529 * side effects - conf file for givenconf type is opened and read then parsed
2530 */
2531 static void
2532 parse_conf_file(int type, int cold)
2533 {
2534 FBFILE *file = NULL;
2535 const char *filename = get_conf_name(type);
2536
2537 if ((file = fbopen(filename, "r")) == NULL)
2538 {
2539 if (cold)
2540 ilog(L_ERROR, "Unable to read configuration file '%s': %s",
2541 filename, strerror(errno));
2542 else
2543 sendto_realops_flags(UMODE_ALL, L_ALL,
2544 "Unable to read configuration file '%s': %s",
2545 filename, strerror(errno));
2546 }
2547 else
2548 {
2549 parse_csv_file(file, type);
2550 fbclose(file);
2551 }
2552 }
2553
2554 /* clear_out_old_conf()
2555 *
2556 * inputs - none
2557 * output - none
2558 * side effects - Clear out the old configuration
2559 */
2560 static void
2561 clear_out_old_conf(void)
2562 {
2563 dlink_node *ptr = NULL, *next_ptr = NULL;
2564 struct ConfItem *conf;
2565 struct AccessItem *aconf;
2566 struct ClassItem *cltmp;
2567 struct MatchItem *match_item;
2568 dlink_list *free_items [] = {
2569 &server_items, &oconf_items, &hub_items, &leaf_items,
2570 &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2571 &nresv_items, &cluster_items, &gdeny_items, &service_items, NULL
2572 };
2573
2574 dlink_list ** iterator = free_items; /* C is dumb */
2575
2576 /* We only need to free anything allocated by yyparse() here.
2577 * Resetting structs, etc, is taken care of by set_default_conf().
2578 */
2579
2580 for (; *iterator != NULL; iterator++)
2581 {
2582 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2583 {
2584 conf = ptr->data;
2585 /* XXX This is less than pretty */
2586 if (conf->type == SERVER_TYPE)
2587 {
2588 aconf = map_to_conf(conf);
2589
2590 if (aconf->clients != 0)
2591 {
2592 SetConfIllegal(aconf);
2593 dlinkDelete(&conf->node, &server_items);
2594 }
2595 else
2596 {
2597 delete_conf_item(conf);
2598 }
2599 }
2600 else if (conf->type == OPER_TYPE)
2601 {
2602 aconf = map_to_conf(conf);
2603
2604 if (aconf->clients != 0)
2605 {
2606 SetConfIllegal(aconf);
2607 dlinkDelete(&conf->node, &oconf_items);
2608 }
2609 else
2610 {
2611 delete_conf_item(conf);
2612 }
2613 }
2614 else if (conf->type == CLIENT_TYPE)
2615 {
2616 aconf = map_to_conf(conf);
2617
2618 if (aconf->clients != 0)
2619 {
2620 SetConfIllegal(aconf);
2621 }
2622 else
2623 {
2624 delete_conf_item(conf);
2625 }
2626 }
2627 else if (conf->type == XLINE_TYPE ||
2628 conf->type == RXLINE_TYPE ||
2629 conf->type == RKLINE_TYPE)
2630 {
2631 /* temporary (r)xlines are also on
2632 * the (r)xconf items list */
2633 if (conf->flags & CONF_FLAGS_TEMPORARY)
2634 continue;
2635
2636 delete_conf_item(conf);
2637 }
2638 else
2639 {
2640 if ((conf->type == LEAF_TYPE) || (conf->type == HUB_TYPE))
2641 {
2642 match_item = map_to_conf(conf);
2643 if (match_item->ref_count <= 0)
2644 delete_conf_item(conf);
2645 else
2646 {
2647 match_item->illegal = 1;
2648 dlinkDelete(&conf->node, *iterator);
2649 }
2650 }
2651 else
2652 delete_conf_item(conf);
2653 }
2654 }
2655 }
2656
2657 /*
2658 * don't delete the class table, rather mark all entries
2659 * for deletion. The table is cleaned up by check_class. - avalon
2660 */
2661 DLINK_FOREACH(ptr, class_items.head)
2662 {
2663 cltmp = map_to_conf(ptr->data);
2664
2665 if (ptr != class_items.tail) /* never mark the "default" class */
2666 cltmp->active = 0;
2667 }
2668
2669 clear_out_address_conf();
2670
2671 /* clean out module paths */
2672 mod_clear_paths();
2673
2674 /* clean out ServerInfo */
2675 MyFree(ServerInfo.description);
2676 ServerInfo.description = NULL;
2677 MyFree(ServerInfo.network_name);
2678 ServerInfo.network_name = NULL;
2679 MyFree(ServerInfo.network_desc);
2680 ServerInfo.network_desc = NULL;
2681 MyFree(ConfigFileEntry.egdpool_path);
2682 ConfigFileEntry.egdpool_path = NULL;
2683 #ifdef HAVE_LIBCRYPTO
2684 if (ServerInfo.rsa_private_key != NULL)
2685 {
2686 RSA_free(ServerInfo.rsa_private_key);
2687 ServerInfo.rsa_private_key = NULL;
2688 }
2689
2690 MyFree(ServerInfo.rsa_private_key_file);
2691 ServerInfo.rsa_private_key_file = NULL;
2692 #endif
2693
2694 /* clean out old resvs from the conf */
2695 clear_conf_resv();
2696
2697 /* clean out AdminInfo */
2698 MyFree(AdminInfo.name);
2699 AdminInfo.name = NULL;
2700 MyFree(AdminInfo.email);
2701 AdminInfo.email = NULL;
2702 MyFree(AdminInfo.description);
2703 AdminInfo.description = NULL;
2704
2705 /* operator{} and class{} blocks are freed above */
2706 /* clean out listeners */
2707 close_listeners();
2708
2709 /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2710 * exempt{} and gecos{} blocks are freed above too
2711 */
2712
2713 /* clean out general */
2714 MyFree(ConfigFileEntry.service_name);
2715 ConfigFileEntry.service_name = NULL;
2716
2717 MyFree(ConfigFileEntry.servlink_path);
2718 ConfigFileEntry.servlink_path = NULL;
2719 #ifdef HAVE_LIBCRYPTO
2720 ConfigFileEntry.default_cipher_preference = NULL;
2721 #endif /* HAVE_LIBCRYPTO */
2722 delete_isupport("INVEX");
2723 delete_isupport("EXCEPTS");
2724 }
2725
2726 /* flush_deleted_I_P()
2727 *
2728 * inputs - none
2729 * output - none
2730 * side effects - This function removes I/P conf items
2731 */
2732 static void
2733 flush_deleted_I_P(void)
2734 {
2735 dlink_node *ptr;
2736 dlink_node *next_ptr;
2737 struct ConfItem *conf;
2738 struct AccessItem *aconf;
2739 dlink_list * free_items [] = {
2740 &server_items, &oconf_items, NULL
2741 };
2742 dlink_list ** iterator = free_items; /* C is dumb */
2743
2744 /* flush out deleted I and P lines
2745 * although still in use.
2746 */
2747 for (; *iterator != NULL; iterator++)
2748 {
2749 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2750 {
2751 conf = ptr->data;
2752 aconf = (struct AccessItem *)map_to_conf(conf);
2753
2754 if (IsConfIllegal(aconf))
2755 {
2756 dlinkDelete(ptr, *iterator);
2757
2758 if (aconf->clients == 0)
2759 delete_conf_item(conf);
2760 }
2761 }
2762 }
2763 }
2764
2765 /* get_conf_name()
2766 *
2767 * inputs - type of conf file to return name of file for
2768 * output - pointer to filename for type of conf
2769 * side effects - none
2770 */
2771 const char *
2772 get_conf_name(ConfType type)
2773 {
2774 switch (type)
2775 {
2776 case CONF_TYPE:
2777 return ConfigFileEntry.configfile;
2778 break;
2779 case KLINE_TYPE:
2780 return ConfigFileEntry.klinefile;
2781 break;
2782 case RKLINE_TYPE:
2783 return ConfigFileEntry.rklinefile;
2784 break;
2785 case DLINE_TYPE:
2786 return ConfigFileEntry.dlinefile;
2787 break;
2788 case XLINE_TYPE:
2789 return ConfigFileEntry.xlinefile;
2790 break;
2791 case RXLINE_TYPE:
2792 return ConfigFileEntry.rxlinefile;
2793 break;
2794 case CRESV_TYPE:
2795 return ConfigFileEntry.cresvfile;
2796 break;
2797 case NRESV_TYPE:
2798 return ConfigFileEntry.nresvfile;
2799 break;
2800 case GLINE_TYPE:
2801 return ConfigFileEntry.glinefile;
2802 break;
2803
2804 default:
2805 return NULL; /* This should NEVER HAPPEN since we call this function
2806 only with the above values, this will cause us to core
2807 at some point if this happens so we know where it was */
2808 }
2809 }
2810
2811 #define BAD_PING (-1)
2812
2813 /* get_conf_ping()
2814 *
2815 * inputs - pointer to struct AccessItem
2816 * - pointer to a variable that receives ping warning time
2817 * output - ping frequency
2818 * side effects - NONE
2819 */
2820 static int
2821 get_conf_ping(struct ConfItem *conf, int *pingwarn)
2822 {
2823 struct ClassItem *aclass;
2824 struct AccessItem *aconf;
2825
2826 if (conf != NULL)
2827 {
2828 aconf = (struct AccessItem *)map_to_conf(conf);
2829 if (aconf->class_ptr != NULL)
2830 {
2831 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2832 *pingwarn = PingWarning(aclass);
2833 return PingFreq(aclass);
2834 }
2835 }
2836
2837 return BAD_PING;
2838 }
2839
2840 /* get_client_class()
2841 *
2842 * inputs - pointer to client struct
2843 * output - pointer to name of class
2844 * side effects - NONE
2845 */
2846 const char *
2847 get_client_class(struct Client *target_p)
2848 {
2849 dlink_node *ptr;
2850 struct ConfItem *conf;
2851 struct AccessItem *aconf;
2852
2853 if (target_p != NULL && !IsMe(target_p) &&
2854 target_p->localClient->confs.head != NULL)
2855 {
2856 DLINK_FOREACH(ptr, target_p->localClient->confs.head)
2857 {
2858 conf = ptr->data;
2859
2860 if (conf->type == CLIENT_TYPE || conf->type == SERVER_TYPE ||
2861 conf->type == OPER_TYPE)
2862 {
2863 aconf = (struct AccessItem *) map_to_conf(conf);
2864 if (aconf->class_ptr != NULL)
2865 return aconf->class_ptr->name;
2866 }
2867 }
2868 }
2869
2870 return "default";
2871 }
2872
2873 /* get_client_ping()
2874 *
2875 * inputs - pointer to client struct
2876 * - pointer to a variable that receives ping warning time
2877 * output - ping frequency
2878 * side effects - NONE
2879 */
2880 int
2881 get_client_ping(struct Client *target_p, int *pingwarn)
2882 {
2883 int ping;
2884 struct ConfItem *conf;
2885 dlink_node *nlink;
2886
2887 if (target_p->localClient->confs.head != NULL)
2888 DLINK_FOREACH(nlink, target_p->localClient->confs.head)
2889 {
2890 conf = nlink->data;
2891
2892 if ((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2893 (conf->type == OPER_TYPE))
2894 {
2895 ping = get_conf_ping(conf, pingwarn);
2896 if (ping > 0)
2897 return ping;
2898 }
2899 }
2900
2901 *pingwarn = 0;
2902 return DEFAULT_PINGFREQUENCY;
2903 }
2904
2905 /* find_class()
2906 *
2907 * inputs - string name of class
2908 * output - corresponding Class pointer
2909 * side effects - NONE
2910 */
2911 struct ConfItem *
2912 find_class(const char *classname)
2913 {
2914 struct ConfItem *conf;
2915
2916 if ((conf = find_exact_name_conf(CLASS_TYPE, classname, NULL, NULL)) != NULL)
2917 return conf;
2918
2919 return class_default;
2920 }
2921
2922 /* check_class()
2923 *
2924 * inputs - NONE
2925 * output - NONE
2926 * side effects -
2927 */
2928 void
2929 check_class(void)
2930 {
2931 dlink_node *ptr = NULL, *next_ptr = NULL;
2932
2933 DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2934 {
2935 struct ClassItem *aclass = map_to_conf(ptr->data);
2936
2937 if (!aclass->active && !CurrUserCount(aclass))
2938 {
2939 destroy_cidr_class(aclass);
2940 delete_conf_item(ptr->data);
2941 }
2942 }
2943 }
2944
2945 /* init_class()
2946 *
2947 * inputs - NONE
2948 * output - NONE
2949 * side effects -
2950 */
2951 void
2952 init_class(void)
2953 {
2954 struct ClassItem *aclass;
2955
2956 class_default = make_conf_item(CLASS_TYPE);
2957
2958 aclass = map_to_conf(class_default);
2959 aclass->active = 1;
2960 DupString(class_default->name, "default");
2961 ConFreq(aclass) = DEFAULT_CONNECTFREQUENCY;
2962 PingFreq(aclass) = DEFAULT_PINGFREQUENCY;
2963 MaxTotal(aclass) = MAXIMUM_LINKS_DEFAULT;
2964 MaxSendq(aclass) = DEFAULT_SENDQ;
2965
2966 client_check_cb = register_callback("check_client", check_client);
2967 }
2968
2969 /* get_sendq()
2970 *
2971 * inputs - pointer to client
2972 * output - sendq for this client as found from its class
2973 * side effects - NONE
2974 */
2975 unsigned int
2976 get_sendq(struct Client *client_p)
2977 {
2978 unsigned int sendq = DEFAULT_SENDQ;
2979 dlink_node *ptr;
2980 struct ConfItem *conf;
2981 struct ConfItem *class_conf;
2982 struct ClassItem *aclass;
2983 struct AccessItem *aconf;
2984
2985 if (client_p && !IsMe(client_p) && (client_p->localClient->confs.head))
2986 {
2987 DLINK_FOREACH(ptr, client_p->localClient->confs.head)
2988 {
2989 conf = ptr->data;
2990 if ((conf->type == SERVER_TYPE) || (conf->type == OPER_TYPE)
2991 || (conf->type == CLIENT_TYPE))
2992 {
2993 aconf = (struct AccessItem *)map_to_conf(conf);
2994 if ((class_conf = aconf->class_ptr) == NULL)
2995 continue;
2996 aclass = (struct ClassItem *)map_to_conf(class_conf);
2997 sendq = MaxSendq(aclass);
2998 return sendq;
2999 }
3000 }
3001 }
3002 /* XXX return a default?
3003 * if here, then there wasn't an attached conf with a sendq
3004 * that is very bad -Dianora
3005 */
3006 return DEFAULT_SENDQ;
3007 }
3008
3009 /* conf_add_class_to_conf()
3010 *
3011 * inputs - pointer to config item
3012 * output - NONE
3013 * side effects - Add a class pointer to a conf
3014 */
3015 void
3016 conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
3017 {
3018 struct AccessItem *aconf = map_to_conf(conf);
3019 struct ClassItem *class = NULL;
3020
3021 if (class_name == NULL)
3022 {
3023 aconf->class_ptr = class_default;
3024
3025 if (conf->type == CLIENT_TYPE)
3026 sendto_realops_flags(UMODE_ALL, L_ALL,
3027 "Warning *** Defaulting to default class for %s@%s",
3028 aconf->user, aconf->host);
3029 else
3030 sendto_realops_flags(UMODE_ALL, L_ALL,
3031 "Warning *** Defaulting to default class for %s",
3032 conf->name);
3033 }
3034 else
3035 aconf->class_ptr = find_class(class_name);
3036
3037 if (aconf->class_ptr)
3038 class = map_to_conf(aconf->class_ptr);
3039
3040 if (aconf->class_ptr == NULL || !class->active)
3041 {
3042 if (conf->type == CLIENT_TYPE)
3043 sendto_realops_flags(UMODE_ALL, L_ALL,
3044 "Warning *** Defaulting to default class for %s@%s",
3045 aconf->user, aconf->host);
3046 else
3047 sendto_realops_flags(UMODE_ALL, L_ALL,
3048 "Warning *** Defaulting to default class for %s",
3049 conf->name);
3050 aconf->class_ptr = class_default;
3051 }
3052 }
3053
3054 /* conf_add_server()
3055 *
3056 * inputs - pointer to config item
3057 * - pointer to link count already on this conf
3058 * output - NONE
3059 * side effects - Add a connect block
3060 */
3061 int
3062 conf_add_server(struct ConfItem *conf, const char *class_name)
3063 {
3064 struct AccessItem *aconf;
3065 struct split_nuh_item nuh;
3066 char conf_user[USERLEN + 1];
3067 char conf_host[HOSTLEN + 1];
3068
3069 aconf = map_to_conf(conf);
3070
3071 conf_add_class_to_conf(conf, class_name);
3072
3073 if (!aconf->host || !conf->name)
3074 {
3075 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
3076 ilog(L_WARN, "Bad connect block");
3077 return -1;
3078 }
3079
3080 if (EmptyString(aconf->passwd) && !IsConfCryptLink(aconf))
3081 {
3082 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
3083 conf->name);
3084 ilog(L_WARN, "Bad connect block, host %s", conf->name);
3085 return -1;
3086 }
3087
3088 nuh.nuhmask = aconf->host;
3089 nuh.nickptr = NULL;
3090 nuh.userptr = conf_user;
3091 nuh.hostptr = conf_host;
3092
3093 nuh.nicksize = 0;
3094 nuh.usersize = sizeof(conf_user);
3095 nuh.hostsize = sizeof(conf_host);
3096
3097 split_nuh(&nuh);
3098
3099 MyFree(aconf->host);
3100 aconf->host = NULL;
3101
3102 DupString(aconf->user, conf_user); /* somehow username checking for servers
3103 got lost in H6/7, will have to be re-added */
3104 DupString(aconf->host, conf_host);
3105
3106 lookup_confhost(conf);
3107
3108 return 0;
3109 }
3110
3111 /* yyerror()
3112 *
3113 * inputs - message from parser
3114 * output - NONE
3115 * side effects - message to opers and log file entry is made
3116 */
3117 void
3118 yyerror(const char *msg)
3119 {
3120 char newlinebuf[IRCD_BUFSIZE];
3121
3122 if (conf_parser_ctx.pass != 1)
3123 return;
3124
3125 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
3126 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
3127 conffilebuf, lineno + 1, msg, newlinebuf);
3128 ilog(L_WARN, "\"%s\", line %u: %s: %s",
3129 conffilebuf, lineno + 1, msg, newlinebuf);
3130 }
3131
3132 int
3133 conf_fbgets(char *lbuf, unsigned int max_size, FBFILE *fb)
3134 {
3135 if (fbgets(lbuf, max_size, fb) == NULL)
3136 return 0;
3137
3138 return strlen(lbuf);
3139 }
3140
3141 int
3142 conf_yy_fatal_error(const char *msg)
3143 {
3144 return 0;
3145 }
3146
3147 /*
3148 * valid_tkline()
3149 *
3150 * inputs - pointer to ascii string to check
3151 * - whether the specified time is in seconds or minutes
3152 * output - -1 not enough parameters
3153 * - 0 if not an integer number, else the number
3154 * side effects - none
3155 * Originally written by Dianora (Diane, db@db.net)
3156 */
3157 time_t
3158 valid_tkline(const char *p, int minutes)
3159 {
3160 time_t result = 0;
3161
3162 for (; *p; ++p)
3163 {
3164 if (!IsDigit(*p))
3165 return 0;
3166
3167 result *= 10;
3168 result += ((*p) & 0xF);
3169 }
3170
3171 /*
3172 * In the degenerate case where oper does a /quote kline 0 user@host :reason
3173 * i.e. they specifically use 0, I am going to return 1 instead
3174 * as a return value of non-zero is used to flag it as a temporary kline
3175 */
3176 if (result == 0)
3177 result = 1;
3178
3179 /*
3180 * If the incoming time is in seconds convert it to minutes for the purpose
3181 * of this calculation
3182 */
3183 if (!minutes)
3184 result = result / (time_t)60;
3185
3186 if (result > MAX_TDKLINE_TIME)
3187 result = MAX_TDKLINE_TIME;
3188
3189 result = result * (time_t)60; /* turn it into seconds */
3190
3191 return result;
3192 }
3193
3194 /* valid_wild_card()
3195 *
3196 * input - pointer to client
3197 * - int flag, 0 for no warning oper 1 for warning oper
3198 * - count of following varargs to check
3199 * output - 0 if not valid, 1 if valid
3200 * side effects - NOTICE is given to source_p if warn is 1
3201 */
3202 int
3203 valid_wild_card(struct Client *source_p, int warn, int count, ...)
3204 {
3205 char *p;
3206 char tmpch;
3207 int nonwild = 0;
3208 va_list args;
3209
3210 /*
3211 * Now we must check the user and host to make sure there
3212 * are at least NONWILDCHARS non-wildcard characters in
3213 * them, otherwise assume they are attempting to kline
3214 * *@* or some variant of that. This code will also catch
3215 * people attempting to kline *@*.tld, as long as NONWILDCHARS
3216 * is greater than 3. In that case, there are only 3 non-wild
3217 * characters (tld), so if NONWILDCHARS is 4, the kline will
3218 * be disallowed.
3219 * -wnder
3220 */
3221
3222 va_start(args, count);
3223
3224 while (count--)
3225 {
3226 p = va_arg(args, char *);
3227 if (p == NULL)
3228 continue;
3229
3230 while ((tmpch = *p++))
3231 {
3232 if (!IsKWildChar(tmpch))
3233 {
3234 /*
3235 * If we find enough non-wild characters, we can
3236 * break - no point in searching further.
3237 */
3238 if (++nonwild >= ConfigFileEntry.min_nonwildcard)
3239 return 1;
3240 }
3241 }
3242 }
3243
3244 if (warn)
3245 sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
3246 me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
3247 return 0;
3248 }
3249
3250 /* XXX should this go into a separate file ? -Dianora */
3251 /* parse_aline
3252 *
3253 * input - pointer to cmd name being used
3254 * - pointer to client using cmd
3255 * - parc parameter count
3256 * - parv[] list of parameters to parse
3257 * - parse_flags bit map of things to test
3258 * - pointer to user or string to parse into
3259 * - pointer to host or NULL to parse into if non NULL
3260 * - pointer to optional tkline time or NULL
3261 * - pointer to target_server to parse into if non NULL
3262 * - pointer to reason to parse into
3263 *
3264 * output - 1 if valid, -1 if not valid
3265 * side effects - A generalised k/d/x etc. line parser,
3266 * "ALINE [time] user@host|string [ON] target :reason"
3267 * will parse returning a parsed user, host if
3268 * h_p pointer is non NULL, string otherwise.
3269 * if tkline_time pointer is non NULL a tk line will be set
3270 * to non zero if found.
3271 * if tkline_time pointer is NULL and tk line is found,
3272 * error is reported.
3273 * if target_server is NULL and an "ON" is found error
3274 * is reported.
3275 * if reason pointer is NULL ignore pointer,
3276 * this allows use of parse_a_line in unkline etc.
3277 *
3278 * - Dianora
3279 */
3280 int
3281 parse_aline(const char *cmd, struct Client *source_p,
3282 int parc, char **parv,
3283 int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
3284 char **target_server, char **reason)
3285 {
3286 int found_tkline_time=0;
3287 static char def_reason[] = "No Reason";
3288 static char user[USERLEN*4+1];
3289 static char host[HOSTLEN*4+1];
3290
3291 parv++;
3292 parc--;
3293
3294 found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3295
3296 if (found_tkline_time != 0)
3297 {
3298 parv++;
3299 parc--;
3300
3301 if (tkline_time != NULL)
3302 *tkline_time = found_tkline_time;
3303 else
3304 {
3305 sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3306 me.name, source_p->name, cmd);
3307 return -1;
3308 }
3309 }
3310
3311 if (parc == 0)
3312 {
3313 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3314 me.name, source_p->name, cmd);
3315 return -1;
3316 }
3317
3318 if (h_p == NULL)
3319 *up_p = *parv;
3320 else
3321 {
3322 if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3323 return -1;
3324
3325 *up_p = user;
3326 *h_p = host;
3327 }
3328
3329 parc--;
3330 parv++;
3331
3332 if (parc != 0)
3333 {
3334 if (irccmp(*parv, "ON") == 0)
3335 {
3336 parc--;
3337 parv++;
3338
3339 if (target_server == NULL)
3340 {
3341 sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3342 me.name, source_p->name, cmd);
3343 return -1;
3344 }
3345
3346 if (!IsOperRemoteBan(source_p))
3347 {
3348 sendto_one(source_p, form_str(ERR_NOPRIVS),
3349 me.name, source_p->name, "remoteban");
3350 return -1;
3351 }
3352
3353 if (parc == 0 || EmptyString(*parv))
3354 {
3355 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3356 me.name, source_p->name, cmd);
3357 return -1;
3358 }
3359
3360 *target_server = *parv;
3361 parc--;
3362 parv++;
3363 }
3364 else
3365 {
3366 /* Make sure target_server *is* NULL if no ON server found
3367 * caller probably NULL'd it first, but no harm to do it again -db
3368 */
3369 if (target_server != NULL)
3370 *target_server = NULL;
3371 }
3372 }
3373
3374 if (h_p != NULL)
3375 {
3376 if (strchr(user, '!') != NULL)
3377 {
3378 sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3379 me.name, source_p->name);
3380 return -1;
3381 }
3382
3383 if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 2, *up_p, *h_p))
3384 return -1;
3385 }
3386 else
3387 if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 1, *up_p))
3388 return -1;
3389
3390 if (reason != NULL)
3391 {
3392 if (parc != 0 && !EmptyString(*parv))
3393 {
3394 *reason = *parv;
3395 if (!valid_comment(source_p, *reason, YES))
3396 return -1;
3397 }
3398 else
3399 *reason = def_reason;
3400 }
3401
3402 return 1;
3403 }
3404
3405 /* find_user_host()
3406 *
3407 * inputs - pointer to client placing kline
3408 * - pointer to user_host_or_nick
3409 * - pointer to user buffer
3410 * - pointer to host buffer
3411 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3412 * side effects -
3413 */
3414 static int
3415 find_user_host(struct Client *source_p, char *user_host_or_nick,
3416 char *luser, char *lhost, unsigned int flags)
3417 {
3418 struct Client *target_p = NULL;
3419 char *hostp = NULL;
3420
3421 if (lhost == NULL)
3422 {
3423 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3424 return 1;
3425 }
3426
3427 if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3428 {
3429 /* Explicit user@host mask given */
3430
3431 if (hostp != NULL) /* I'm a little user@host */
3432 {
3433 *(hostp++) = '\0'; /* short and squat */
3434 if (*user_host_or_nick)
3435 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3436 else
3437 strcpy(luser, "*");
3438 if (*hostp)
3439 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3440 else
3441 strcpy(lhost, "*");
3442 }
3443 else
3444 {
3445 luser[0] = '*'; /* no @ found, assume its *@somehost */
3446 luser[1] = '\0';
3447 strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3448 }
3449
3450 return 1;
3451 }
3452 else if (!(flags & NOUSERLOOKUP))
3453 {
3454 /* Try to find user@host mask from nick */
3455 /* Okay to use source_p as the first param, because source_p == client_p */
3456 if ((target_p =
3457 find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3458 return 0;
3459
3460 if (IsExemptKline(target_p))
3461 {
3462 if (!IsServer(source_p))
3463 sendto_one(source_p,
3464 ":%s NOTICE %s :%s is E-lined",
3465 me.name, source_p->name, target_p->name);
3466 return 0;
3467 }
3468
3469 /*
3470 * turn the "user" bit into "*user", blow away '~'
3471 * if found in original user name (non-idented)
3472 */
3473 strlcpy(luser, target_p->username, USERLEN*4 + 1);
3474
3475 if (target_p->username[0] == '~')
3476 luser[0] = '*';
3477
3478 if (target_p->sockhost[0] == '\0' ||
3479 (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3480 strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3481 else
3482 strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3483 return 1;
3484 }
3485
3486 return 0;
3487 }
3488
3489 /* valid_comment()
3490 *
3491 * inputs - pointer to client
3492 * - pointer to comment
3493 * output - 0 if no valid comment,
3494 * - 1 if valid
3495 * side effects - truncates reason where necessary
3496 */
3497 int
3498 valid_comment(struct Client *source_p, char *comment, int warn)
3499 {
3500 if (strchr(comment, '"'))
3501 {
3502 if (warn)
3503 sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3504 me.name, source_p->name);
3505 return 0;
3506 }
3507
3508 if (strlen(comment) > REASONLEN)
3509 comment[REASONLEN-1] = '\0';
3510
3511 return 1;
3512 }
3513
3514 /* match_conf_password()
3515 *
3516 * inputs - pointer to given password
3517 * - pointer to Conf
3518 * output - 1 or 0 if match
3519 * side effects - none
3520 */
3521 int
3522 match_conf_password(const char *password, const struct AccessItem *aconf)
3523 {
3524 const char *encr = NULL;
3525
3526 if (password == NULL || aconf->passwd == NULL)
3527 return 0;
3528
3529 if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3530 {
3531 /* use first two chars of the password they send in as salt */
3532 /* If the password in the conf is MD5, and ircd is linked
3533 * to scrypt on FreeBSD, or the standard crypt library on
3534 * glibc Linux, then this code will work fine on generating
3535 * the proper encrypted hash for comparison.
3536 */
3537 if (*aconf->passwd)
3538 encr = crypt(password, aconf->passwd);
3539 else
3540 encr = "";
3541 }
3542 else
3543 encr = password;
3544
3545 return !strcmp(encr, aconf->passwd);
3546 }
3547
3548 /*
3549 * cluster_a_line
3550 *
3551 * inputs - client sending the cluster
3552 * - command name "KLINE" "XLINE" etc.
3553 * - capab -- CAP_KLN etc. from s_serv.h
3554 * - cluster type -- CLUSTER_KLINE etc. from s_conf.h
3555 * - pattern and args to send along
3556 * output - none
3557 * side effects - Take source_p send the pattern with args given
3558 * along to all servers that match capab and cluster type
3559 */
3560 void
3561 cluster_a_line(struct Client *source_p, const char *command,
3562 int capab, int cluster_type, const char *pattern, ...)
3563 {
3564 va_list args;
3565 char buffer[IRCD_BUFSIZE];
3566 const dlink_node *ptr = NULL;
3567
3568 va_start(args, pattern);
3569 vsnprintf(buffer, sizeof(buffer), pattern, args);
3570 va_end(args);
3571
3572 DLINK_FOREACH(ptr, cluster_items.head)
3573 {
3574 const struct ConfItem *conf = ptr->data;
3575
3576 if (conf->flags & cluster_type)
3577 sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3578 "%s %s %s", command, conf->name, buffer);
3579 }
3580 }
3581
3582 /*
3583 * split_nuh
3584 *
3585 * inputs - pointer to original mask (modified in place)
3586 * - pointer to pointer where nick should go
3587 * - pointer to pointer where user should go
3588 * - pointer to pointer where host should go
3589 * output - NONE
3590 * side effects - mask is modified in place
3591 * If nick pointer is NULL, ignore writing to it
3592 * this allows us to use this function elsewhere.
3593 *
3594 * mask nick user host
3595 * ---------------------- ------- ------- ------
3596 * Dianora!db@db.net Dianora db db.net
3597 * Dianora Dianora * *
3598 * db.net * * db.net
3599 * OR if nick pointer is NULL
3600 * Dianora - * Dianora
3601 * Dianora! Dianora * *
3602 * Dianora!@ Dianora * *
3603 * Dianora!db Dianora db *
3604 * Dianora!@db.net Dianora * db.net
3605 * db@db.net * db db.net
3606 * !@ * * *
3607 * @ * * *
3608 * ! * * *
3609 */
3610 void
3611 split_nuh(struct split_nuh_item *const iptr)
3612 {
3613 char *p = NULL, *q = NULL;
3614
3615 if (iptr->nickptr)
3616 strlcpy(iptr->nickptr, "*", iptr->nicksize);
3617 if (iptr->userptr)
3618 strlcpy(iptr->userptr, "*", iptr->usersize);
3619 if (iptr->hostptr)
3620 strlcpy(iptr->hostptr, "*", iptr->hostsize);
3621
3622 if ((p = strchr(iptr->nuhmask, '!')))
3623 {
3624 *p = '\0';
3625
3626 if (iptr->nickptr && *iptr->nuhmask != '\0')
3627 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3628
3629 if ((q = strchr(++p, '@'))) {
3630 *q++ = '\0';
3631
3632 if (*p != '\0')
3633 strlcpy(iptr->userptr, p, iptr->usersize);
3634
3635 if (*q != '\0')
3636 strlcpy(iptr->hostptr, q, iptr->hostsize);
3637 }
3638 else
3639 {
3640 if (*p != '\0')
3641 strlcpy(iptr->userptr, p, iptr->usersize);
3642 }
3643 }
3644 else
3645 {
3646 /* No ! found so lets look for a user@host */
3647 if ((p = strchr(iptr->nuhmask, '@')))
3648 {
3649 /* if found a @ */
3650 *p++ = '\0';
3651
3652 if (*iptr->nuhmask != '\0')
3653 strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
3654
3655 if (*p != '\0')
3656 strlcpy(iptr->hostptr, p, iptr->hostsize);
3657 }
3658 else
3659 {
3660 /* no @ found */
3661 if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
3662 strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
3663 else
3664 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3665 }
3666 }
3667 }
3668
3669 /*
3670 * flags_to_ascii
3671 *
3672 * inputs - flags is a bitmask
3673 * - pointer to table of ascii letters corresponding
3674 * to each bit
3675 * - flag 1 for convert ToLower if bit missing
3676 * 0 if ignore.
3677 * output - none
3678 * side effects - string pointed to by p has bitmap chars written to it
3679 */
3680 static void
3681 flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3682 int lowerit)
3683 {
3684 unsigned int mask = 1;
3685 int i = 0;
3686
3687 for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3688 {
3689 if (flags & mask)
3690 *p++ = bit_table[i];
3691 else if (lowerit)
3692 *p++ = ToLower(bit_table[i]);
3693 }
3694 *p = '\0';
3695 }
3696
3697 /*
3698 * cidr_limit_reached
3699 *
3700 * inputs - int flag allowing over_rule of limits
3701 * - pointer to the ip to be added
3702 * - pointer to the class
3703 * output - non zero if limit reached
3704 * 0 if limit not reached
3705 * side effects -
3706 */
3707 static int
3708 cidr_limit_reached(int over_rule,
3709 struct irc_ssaddr *ip, struct ClassItem *aclass)
3710 {
3711 dlink_node *ptr = NULL;
3712 struct CidrItem *cidr;
3713
3714 if (NumberPerCidr(aclass) <= 0)
3715 return 0;
3716
3717 if (ip->ss.ss_family == AF_INET)
3718 {
3719 if (CidrBitlenIPV4(aclass) <= 0)
3720 return 0;
3721
3722 DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3723 {
3724 cidr = ptr->data;
3725 if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3726 {
3727 if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3728 return -1;
3729 cidr->number_on_this_cidr++;
3730 return 0;
3731 }
3732 }
3733 cidr = MyMalloc(sizeof(struct CidrItem));
3734 cidr->number_on_this_cidr = 1;
3735 cidr->mask = *ip;
3736 mask_addr(&cidr->mask, CidrBitlenIPV4(aclass));
3737 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3738 }
3739 #ifdef IPV6
3740 else if (CidrBitlenIPV6(aclass) > 0)
3741 {
3742 DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3743 {
3744 cidr = ptr->data;
3745 if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3746 {
3747 if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3748 return -1;
3749 cidr->number_on_this_cidr++;
3750 return 0;
3751 }
3752 }
3753 cidr = MyMalloc(sizeof(struct CidrItem));
3754 cidr->number_on_this_cidr = 1;
3755 cidr->mask = *ip;
3756 mask_addr(&cidr->mask, CidrBitlenIPV6(aclass));
3757 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3758 }
3759 #endif
3760 return 0;
3761 }
3762
3763 /*
3764 * remove_from_cidr_check
3765 *
3766 * inputs - pointer to the ip to be removed
3767 * - pointer to the class
3768 * output - NONE
3769 * side effects -
3770 */
3771 static void
3772 remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3773 {
3774 dlink_node *ptr = NULL;
3775 dlink_node *next_ptr = NULL;
3776 struct CidrItem *cidr;
3777
3778 if (NumberPerCidr(aclass) == 0)
3779 return;
3780
3781 if (ip->ss.ss_family == AF_INET)
3782 {
3783 if (CidrBitlenIPV4(aclass) <= 0)
3784 return;
3785
3786 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3787 {
3788 cidr = ptr->data;
3789 if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3790 {
3791 cidr->number_on_this_cidr--;
3792 if (cidr->number_on_this_cidr == 0)
3793 {
3794 dlinkDelete(ptr, &aclass->list_ipv4);
3795 MyFree(cidr);
3796 return;
3797 }
3798 }
3799 }
3800 }
3801 #ifdef IPV6
3802 else if (CidrBitlenIPV6(aclass) > 0)
3803 {
3804 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3805 {
3806 cidr = ptr->data;
3807 if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3808 {
3809 cidr->number_on_this_cidr--;
3810 if (cidr->number_on_this_cidr == 0)
3811 {
3812 dlinkDelete(ptr, &aclass->list_ipv6);
3813 MyFree(cidr);
3814 return;
3815 }
3816 }
3817 }
3818 }
3819 #endif
3820 }
3821
3822 static void
3823 rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3824 dlink_list *old_list, dlink_list *new_list, int changed)
3825 {
3826 dlink_node *ptr;
3827 struct Client *client_p;
3828 struct ConfItem *conf;
3829 struct AccessItem *aconf;
3830
3831 if (!changed)
3832 {
3833 *new_list = *old_list;
3834 old_list->head = old_list->tail = NULL;
3835 old_list->length = 0;
3836 return;
3837 }
3838
3839 DLINK_FOREACH(ptr, local_client_list.head)
3840 {
3841 client_p = ptr->data;
3842 if (client_p->localClient->aftype != aftype)
3843 continue;
3844 if (dlink_list_length(&client_p->localClient->confs) == 0)
3845 continue;
3846
3847 conf = client_p->localClient->confs.tail->data;
3848 if (conf->type == CLIENT_TYPE)
3849 {
3850 aconf = map_to_conf(conf);
3851 if (aconf->class_ptr == oldcl)
3852 cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3853 }
3854 }
3855 }
3856
3857 /*
3858 * rebuild_cidr_class
3859 *
3860 * inputs - pointer to old conf
3861 * - pointer to new_class
3862 * output - none
3863 * side effects - rebuilds the class link list of cidr blocks
3864 */
3865 void
3866 rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3867 {
3868 struct ClassItem *old_class = map_to_conf(conf);
3869
3870 if (NumberPerCidr(old_class) > 0 && NumberPerCidr(new_class) > 0)
3871 {
3872 if (CidrBitlenIPV4(old_class) > 0 && CidrBitlenIPV4(new_class) > 0)
3873 rebuild_cidr_list(AF_INET, conf, new_class,
3874 &old_class->list_ipv4, &new_class->list_ipv4,
3875 CidrBitlenIPV4(old_class) != CidrBitlenIPV4(new_class));
3876
3877 #ifdef IPV6
3878 if (CidrBitlenIPV6(old_class) > 0 && CidrBitlenIPV6(new_class) > 0)
3879 rebuild_cidr_list(AF_INET6, conf, new_class,
3880 &old_class->list_ipv6, &new_class->list_ipv6,
3881 CidrBitlenIPV6(old_class) != CidrBitlenIPV6(new_class));
3882 #endif
3883 }
3884
3885 destroy_cidr_class(old_class);
3886 }
3887
3888 /*
3889 * destroy_cidr_list
3890 *
3891 * inputs - pointer to class dlink list of cidr blocks
3892 * output - none
3893 * side effects - completely destroys the class link list of cidr blocks
3894 */
3895 static void
3896 destroy_cidr_list(dlink_list *list)
3897 {
3898 dlink_node *ptr = NULL, *next_ptr = NULL;
3899
3900 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3901 {
3902 dlinkDelete(ptr, list);
3903 MyFree(ptr->data);
3904 }
3905 }
3906
3907 /*
3908 * destroy_cidr_class
3909 *
3910 * inputs - pointer to class
3911 * output - none
3912 * side effects - completely destroys the class link list of cidr blocks
3913 */
3914 static void
3915 destroy_cidr_class(struct ClassItem *aclass)
3916 {
3917 destroy_cidr_list(&aclass->list_ipv4);
3918 destroy_cidr_list(&aclass->list_ipv6);
3919 }

Properties

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