/[svn]/ircd-hybrid-7.2/src/s_conf.c
ViewVC logotype

Contents of /ircd-hybrid-7.2/src/s_conf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1011 - (show annotations)
Fri Sep 18 10:14:09 2009 UTC (10 years, 1 month ago) by michael
File MIME type: text/x-chdr
File size: 99606 byte(s)
- move list manipulation routines from tools.c to list.c
- mem_frob() goes to memory.c
- sort out redundant/unneeded header includes

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