ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1526
Committed: Mon Sep 10 18:06:06 2012 UTC (12 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/conf.c
File size: 92400 byte(s)
Log Message:
- fixed minor compile warnings

File Contents

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

Properties

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