ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/s_conf.c
Revision: 1247
Committed: Sat Oct 1 07:54:24 2011 UTC (12 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 100137 byte(s)
Log Message:
- Rewrite and cleanup half-broken logging subsystem.
  Logfile rotating is not working yet

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

Properties

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