ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.0.x/src/conf.c
Revision: 1822
Committed: Sun Apr 14 12:36:55 2013 UTC (13 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 91663 byte(s)
Log Message:
- Added preliminary support for ISO 3166 alpha-2 two letter country code
  enabled auth{} blocks. Requires libGeoIP.
- Added no_join to auth::flags

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 exit_client(source_p, &me, "You are not authorized to use this server");
802 break;
803
804 case BANNED_CLIENT:
805 exit_client(source_p, &me, "Banned");
806 ++ServerStats.is_ref;
807 break;
808
809 case 0:
810 default:
811 break;
812 }
813
814 return (i < 0 ? NULL : source_p);
815 }
816
817 /* verify_access()
818 *
819 * inputs - pointer to client to verify
820 * - pointer to proposed username
821 * output - 0 if success -'ve if not
822 * side effect - find the first (best) I line to attach.
823 */
824 static int
825 verify_access(struct Client *client_p, const char *username)
826 {
827 struct AccessItem *aconf = NULL, *rkconf = NULL;
828 struct ConfItem *conf = NULL;
829 char non_ident[USERLEN + 1] = { '~', '\0' };
830 const char *uhi[3];
831
832 if (IsGotId(client_p))
833 {
834 aconf = find_address_conf(client_p->host, client_p->username,
835 &client_p->localClient->ip,
836 client_p->localClient->aftype,
837 client_p->localClient->passwd,
838 client_p->localClient->country_id);
839 }
840 else
841 {
842 strlcpy(non_ident+1, username, sizeof(non_ident)-1);
843 aconf = find_address_conf(client_p->host,non_ident,
844 &client_p->localClient->ip,
845 client_p->localClient->aftype,
846 client_p->localClient->passwd,
847 client_p->localClient->country_id);
848 }
849
850 uhi[0] = IsGotId(client_p) ? client_p->username : non_ident;
851 uhi[1] = client_p->host;
852 uhi[2] = client_p->sockhost;
853
854 rkconf = find_regexp_kline(uhi);
855
856 if (aconf != NULL)
857 {
858 if (IsConfClient(aconf) && !rkconf)
859 {
860 conf = unmap_conf_item(aconf);
861
862 if (IsConfRedir(aconf))
863 {
864 sendto_one(client_p, form_str(RPL_REDIR),
865 me.name, client_p->name,
866 conf->name ? conf->name : "",
867 aconf->port);
868 return(NOT_AUTHORIZED);
869 }
870
871 if (IsConfDoIdentd(aconf))
872 SetNeedId(client_p);
873
874 /* Thanks for spoof idea amm */
875 if (IsConfDoSpoofIp(aconf))
876 {
877 conf = unmap_conf_item(aconf);
878
879 if (!ConfigFileEntry.hide_spoof_ips && IsConfSpoofNotice(aconf))
880 sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s spoofing: %s as %s",
881 client_p->name, client_p->host, conf->name);
882 strlcpy(client_p->host, conf->name, sizeof(client_p->host));
883 SetIPSpoof(client_p);
884 }
885
886 return(attach_iline(client_p, conf));
887 }
888 else if (rkconf || IsConfKill(aconf) || (ConfigFileEntry.glines && IsConfGline(aconf)))
889 {
890 /* XXX */
891 aconf = rkconf ? rkconf : aconf;
892 if (IsConfGline(aconf))
893 sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name,
894 client_p->name);
895 sendto_one(client_p, ":%s NOTICE %s :*** Banned: %s",
896 me.name, client_p->name, aconf->reason);
897 return(BANNED_CLIENT);
898 }
899 }
900
901 return(NOT_AUTHORIZED);
902 }
903
904 /* attach_iline()
905 *
906 * inputs - client pointer
907 * - conf pointer
908 * output -
909 * side effects - do actual attach
910 */
911 static int
912 attach_iline(struct Client *client_p, struct ConfItem *conf)
913 {
914 struct AccessItem *aconf;
915 struct ClassItem *aclass;
916 struct ip_entry *ip_found;
917 int a_limit_reached = 0;
918 int local = 0, global = 0, ident = 0;
919
920 ip_found = find_or_add_ip(&client_p->localClient->ip);
921 ip_found->count++;
922 SetIpHash(client_p);
923
924 aconf = map_to_conf(conf);
925 if (aconf->class_ptr == NULL)
926 return NOT_AUTHORIZED; /* If class is missing, this is best */
927
928 aclass = map_to_conf(aconf->class_ptr);
929
930 count_user_host(client_p->username, client_p->host,
931 &global, &local, &ident);
932
933 /* XXX blah. go down checking the various silly limits
934 * setting a_limit_reached if any limit is reached.
935 * - Dianora
936 */
937 if (aclass->max_total != 0 && aclass->curr_user_count >= aclass->max_total)
938 a_limit_reached = 1;
939 else if (aclass->max_perip != 0 && ip_found->count > aclass->max_perip)
940 a_limit_reached = 1;
941 else if (aclass->max_local != 0 && local >= aclass->max_local)
942 a_limit_reached = 1;
943 else if (aclass->max_global != 0 && global >= aclass->max_global)
944 a_limit_reached = 1;
945 else if (aclass->max_ident != 0 && ident >= aclass->max_ident &&
946 client_p->username[0] != '~')
947 a_limit_reached = 1;
948
949 if (a_limit_reached)
950 {
951 if (!IsConfExemptLimits(aconf))
952 return TOO_MANY; /* Already at maximum allowed */
953
954 sendto_one(client_p,
955 ":%s NOTICE %s :*** Your connection class is full, "
956 "but you have exceed_limit = yes;", me.name, client_p->name);
957 }
958
959 return attach_conf(client_p, conf);
960 }
961
962 /* init_ip_hash_table()
963 *
964 * inputs - NONE
965 * output - NONE
966 * side effects - allocate memory for ip_entry(s)
967 * - clear the ip hash table
968 */
969 void
970 init_ip_hash_table(void)
971 {
972 ip_entry_heap = BlockHeapCreate("ip", sizeof(struct ip_entry),
973 2 * hard_fdlimit);
974 memset(ip_hash_table, 0, sizeof(ip_hash_table));
975 }
976
977 /* find_or_add_ip()
978 *
979 * inputs - pointer to struct irc_ssaddr
980 * output - pointer to a struct ip_entry
981 * side effects -
982 *
983 * If the ip # was not found, a new struct ip_entry is created, and the ip
984 * count set to 0.
985 */
986 static struct ip_entry *
987 find_or_add_ip(struct irc_ssaddr *ip_in)
988 {
989 struct ip_entry *ptr, *newptr;
990 int hash_index = hash_ip(ip_in), res;
991 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
992 #ifdef IPV6
993 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
994 #endif
995
996 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
997 {
998 #ifdef IPV6
999 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1000 continue;
1001 if (ip_in->ss.ss_family == AF_INET6)
1002 {
1003 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1004 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1005 }
1006 else
1007 #endif
1008 {
1009 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1010 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1011 }
1012 if (res == 0)
1013 {
1014 /* Found entry already in hash, return it. */
1015 return ptr;
1016 }
1017 }
1018
1019 if (ip_entries_count >= 2 * hard_fdlimit)
1020 garbage_collect_ip_entries();
1021
1022 newptr = BlockHeapAlloc(ip_entry_heap);
1023 ip_entries_count++;
1024 memcpy(&newptr->ip, ip_in, sizeof(struct irc_ssaddr));
1025
1026 newptr->next = ip_hash_table[hash_index];
1027 ip_hash_table[hash_index] = newptr;
1028
1029 return newptr;
1030 }
1031
1032 /* remove_one_ip()
1033 *
1034 * inputs - unsigned long IP address value
1035 * output - NONE
1036 * side effects - The ip address given, is looked up in ip hash table
1037 * and number of ip#'s for that ip decremented.
1038 * If ip # count reaches 0 and has expired,
1039 * the struct ip_entry is returned to the ip_entry_heap
1040 */
1041 void
1042 remove_one_ip(struct irc_ssaddr *ip_in)
1043 {
1044 struct ip_entry *ptr;
1045 struct ip_entry *last_ptr = NULL;
1046 int hash_index = hash_ip(ip_in), res;
1047 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
1048 #ifdef IPV6
1049 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
1050 #endif
1051
1052 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
1053 {
1054 #ifdef IPV6
1055 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1056 continue;
1057 if (ip_in->ss.ss_family == AF_INET6)
1058 {
1059 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1060 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1061 }
1062 else
1063 #endif
1064 {
1065 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1066 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1067 }
1068 if (res)
1069 continue;
1070 if (ptr->count > 0)
1071 ptr->count--;
1072 if (ptr->count == 0 &&
1073 (CurrentTime-ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1074 {
1075 if (last_ptr != NULL)
1076 last_ptr->next = ptr->next;
1077 else
1078 ip_hash_table[hash_index] = ptr->next;
1079
1080 BlockHeapFree(ip_entry_heap, ptr);
1081 ip_entries_count--;
1082 return;
1083 }
1084 last_ptr = ptr;
1085 }
1086 }
1087
1088 /* hash_ip()
1089 *
1090 * input - pointer to an irc_inaddr
1091 * output - integer value used as index into hash table
1092 * side effects - hopefully, none
1093 */
1094 static int
1095 hash_ip(struct irc_ssaddr *addr)
1096 {
1097 if (addr->ss.ss_family == AF_INET)
1098 {
1099 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
1100 int hash;
1101 uint32_t ip;
1102
1103 ip = ntohl(v4->sin_addr.s_addr);
1104 hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1);
1105 return hash;
1106 }
1107 #ifdef IPV6
1108 else
1109 {
1110 int hash;
1111 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
1112 uint32_t *ip = (uint32_t *)&v6->sin6_addr.s6_addr;
1113
1114 hash = ip[0] ^ ip[3];
1115 hash ^= hash >> 16;
1116 hash ^= hash >> 8;
1117 hash = hash & (IP_HASH_SIZE - 1);
1118 return hash;
1119 }
1120 #else
1121 return 0;
1122 #endif
1123 }
1124
1125 /* count_ip_hash()
1126 *
1127 * inputs - pointer to counter of number of ips hashed
1128 * - pointer to memory used for ip hash
1129 * output - returned via pointers input
1130 * side effects - NONE
1131 *
1132 * number of hashed ip #'s is counted up, plus the amount of memory
1133 * used in the hash.
1134 */
1135 void
1136 count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored)
1137 {
1138 struct ip_entry *ptr;
1139 int i;
1140
1141 *number_ips_stored = 0;
1142 *mem_ips_stored = 0;
1143
1144 for (i = 0; i < IP_HASH_SIZE; i++)
1145 {
1146 for (ptr = ip_hash_table[i]; ptr; ptr = ptr->next)
1147 {
1148 *number_ips_stored += 1;
1149 *mem_ips_stored += sizeof(struct ip_entry);
1150 }
1151 }
1152 }
1153
1154 /* garbage_collect_ip_entries()
1155 *
1156 * input - NONE
1157 * output - NONE
1158 * side effects - free up all ip entries with no connections
1159 */
1160 static void
1161 garbage_collect_ip_entries(void)
1162 {
1163 struct ip_entry *ptr;
1164 struct ip_entry *last_ptr;
1165 struct ip_entry *next_ptr;
1166 int i;
1167
1168 for (i = 0; i < IP_HASH_SIZE; i++)
1169 {
1170 last_ptr = NULL;
1171
1172 for (ptr = ip_hash_table[i]; ptr; ptr = next_ptr)
1173 {
1174 next_ptr = ptr->next;
1175
1176 if (ptr->count == 0 &&
1177 (CurrentTime - ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1178 {
1179 if (last_ptr != NULL)
1180 last_ptr->next = ptr->next;
1181 else
1182 ip_hash_table[i] = ptr->next;
1183 BlockHeapFree(ip_entry_heap, ptr);
1184 ip_entries_count--;
1185 }
1186 else
1187 last_ptr = ptr;
1188 }
1189 }
1190 }
1191
1192 /* detach_conf()
1193 *
1194 * inputs - pointer to client to detach
1195 * - type of conf to detach
1196 * output - 0 for success, -1 for failure
1197 * side effects - Disassociate configuration from the client.
1198 * Also removes a class from the list if marked for deleting.
1199 */
1200 int
1201 detach_conf(struct Client *client_p, ConfType type)
1202 {
1203 dlink_node *ptr, *next_ptr;
1204 struct ConfItem *conf;
1205 struct ClassItem *aclass;
1206 struct AccessItem *aconf;
1207 struct ConfItem *aclass_conf;
1208
1209 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->confs.head)
1210 {
1211 conf = ptr->data;
1212
1213 if (type == CONF_TYPE || conf->type == type)
1214 {
1215 dlinkDelete(ptr, &client_p->localClient->confs);
1216 free_dlink_node(ptr);
1217
1218 switch (conf->type)
1219 {
1220 case CLIENT_TYPE:
1221 case OPER_TYPE:
1222 case SERVER_TYPE:
1223 aconf = map_to_conf(conf);
1224
1225 assert(aconf->clients > 0);
1226
1227 if ((aclass_conf = aconf->class_ptr) != NULL)
1228 {
1229 aclass = map_to_conf(aclass_conf);
1230
1231 assert(aclass->curr_user_count > 0);
1232
1233 if (conf->type == CLIENT_TYPE)
1234 remove_from_cidr_check(&client_p->localClient->ip, aclass);
1235 if (--aclass->curr_user_count == 0 && aclass->active == 0)
1236 delete_conf_item(aclass_conf);
1237 }
1238
1239 if (--aconf->clients == 0 && IsConfIllegal(aconf))
1240 delete_conf_item(conf);
1241
1242 break;
1243 default:
1244 break;
1245 }
1246
1247 if (type != CONF_TYPE)
1248 return 0;
1249 }
1250 }
1251
1252 return -1;
1253 }
1254
1255 /* attach_conf()
1256 *
1257 * inputs - client pointer
1258 * - conf pointer
1259 * output -
1260 * side effects - Associate a specific configuration entry to a *local*
1261 * client (this is the one which used in accepting the
1262 * connection). Note, that this automatically changes the
1263 * attachment if there was an old one...
1264 */
1265 int
1266 attach_conf(struct Client *client_p, struct ConfItem *conf)
1267 {
1268 struct AccessItem *aconf = map_to_conf(conf);
1269 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1270
1271 if (dlinkFind(&client_p->localClient->confs, conf) != NULL)
1272 return 1;
1273
1274 if (IsConfIllegal(aconf)) /* TBV: can't happen */
1275 return NOT_AUTHORIZED;
1276
1277 if (conf->type == CLIENT_TYPE)
1278 if (cidr_limit_reached(IsConfExemptLimits(aconf),
1279 &client_p->localClient->ip, aclass))
1280 return TOO_MANY; /* Already at maximum allowed */
1281
1282 aclass->curr_user_count++;
1283 aconf->clients++;
1284
1285 dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs);
1286
1287 return 0;
1288 }
1289
1290 /* attach_connect_block()
1291 *
1292 * inputs - pointer to server to attach
1293 * - name of server
1294 * - hostname of server
1295 * output - true (1) if both are found, otherwise return false (0)
1296 * side effects - find connect block and attach them to connecting client
1297 */
1298 int
1299 attach_connect_block(struct Client *client_p, const char *name,
1300 const char *host)
1301 {
1302 dlink_node *ptr;
1303 struct ConfItem *conf;
1304 struct AccessItem *aconf;
1305
1306 assert(client_p != NULL);
1307 assert(host != NULL);
1308
1309 if (client_p == NULL || host == NULL)
1310 return 0;
1311
1312 DLINK_FOREACH(ptr, server_items.head)
1313 {
1314 conf = ptr->data;
1315 aconf = map_to_conf(conf);
1316
1317 if (match(conf->name, name) == 0 || match(aconf->host, host) == 0)
1318 continue;
1319
1320 attach_conf(client_p, conf);
1321 return -1;
1322 }
1323
1324 return 0;
1325 }
1326
1327 /* find_conf_name()
1328 *
1329 * inputs - pointer to conf link list to search
1330 * - pointer to name to find
1331 * - int mask of type of conf to find
1332 * output - NULL or pointer to conf found
1333 * side effects - find a conf entry which matches the name
1334 * and has the given mask.
1335 */
1336 struct ConfItem *
1337 find_conf_name(dlink_list *list, const char *name, ConfType type)
1338 {
1339 dlink_node *ptr;
1340 struct ConfItem* conf;
1341
1342 DLINK_FOREACH(ptr, list->head)
1343 {
1344 conf = ptr->data;
1345
1346 if (conf->type == type)
1347 {
1348 if (conf->name && (irccmp(conf->name, name) == 0 ||
1349 match(conf->name, name)))
1350 return conf;
1351 }
1352 }
1353
1354 return NULL;
1355 }
1356
1357 /* map_to_list()
1358 *
1359 * inputs - ConfType conf
1360 * output - pointer to dlink_list to use
1361 * side effects - none
1362 */
1363 static dlink_list *
1364 map_to_list(ConfType type)
1365 {
1366 switch(type)
1367 {
1368 case RXLINE_TYPE:
1369 return(&rxconf_items);
1370 break;
1371 case XLINE_TYPE:
1372 return(&xconf_items);
1373 break;
1374 case ULINE_TYPE:
1375 return(&uconf_items);
1376 break;
1377 case NRESV_TYPE:
1378 return(&nresv_items);
1379 break;
1380 case OPER_TYPE:
1381 return(&oconf_items);
1382 break;
1383 case CLASS_TYPE:
1384 return(&class_items);
1385 break;
1386 case SERVER_TYPE:
1387 return(&server_items);
1388 break;
1389 case SERVICE_TYPE:
1390 return(&service_items);
1391 break;
1392 case CLUSTER_TYPE:
1393 return(&cluster_items);
1394 break;
1395 case CONF_TYPE:
1396 case GLINE_TYPE:
1397 case KLINE_TYPE:
1398 case DLINE_TYPE:
1399 case CRESV_TYPE:
1400 default:
1401 return NULL;
1402 }
1403 }
1404
1405 /* find_matching_name_conf()
1406 *
1407 * inputs - type of link list to look in
1408 * - pointer to name string to find
1409 * - pointer to user
1410 * - pointer to host
1411 * - optional action to match on as well
1412 * output - NULL or pointer to found struct MatchItem
1413 * side effects - looks for a match on name field
1414 */
1415 struct ConfItem *
1416 find_matching_name_conf(ConfType type, const char *name, const char *user,
1417 const char *host, int action)
1418 {
1419 dlink_node *ptr=NULL;
1420 struct ConfItem *conf=NULL;
1421 struct AccessItem *aconf=NULL;
1422 struct MatchItem *match_item=NULL;
1423 dlink_list *list_p = map_to_list(type);
1424
1425 switch (type)
1426 {
1427 #ifdef HAVE_LIBPCRE
1428 case RXLINE_TYPE:
1429 DLINK_FOREACH(ptr, list_p->head)
1430 {
1431 conf = ptr->data;
1432 assert(conf->regexpname);
1433
1434 if (!ircd_pcre_exec(conf->regexpname, name))
1435 return conf;
1436 }
1437 break;
1438 #endif
1439 case SERVICE_TYPE:
1440 DLINK_FOREACH(ptr, list_p->head)
1441 {
1442 conf = ptr->data;
1443
1444 if (EmptyString(conf->name))
1445 continue;
1446 if ((name != NULL) && !irccmp(name, conf->name))
1447 return conf;
1448 }
1449 break;
1450
1451 case XLINE_TYPE:
1452 case ULINE_TYPE:
1453 case NRESV_TYPE:
1454 DLINK_FOREACH(ptr, list_p->head)
1455 {
1456 conf = ptr->data;
1457
1458 match_item = map_to_conf(conf);
1459 if (EmptyString(conf->name))
1460 continue;
1461 if ((name != NULL) && match_esc(conf->name, name))
1462 {
1463 if ((user == NULL && (host == NULL)))
1464 return conf;
1465 if ((match_item->action & action) != action)
1466 continue;
1467 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1468 return conf;
1469 if (match(match_item->user, user) && match(match_item->host, host))
1470 return conf;
1471 }
1472 }
1473 break;
1474
1475 case SERVER_TYPE:
1476 DLINK_FOREACH(ptr, list_p->head)
1477 {
1478 conf = ptr->data;
1479 aconf = map_to_conf(conf);
1480
1481 if ((name != NULL) && match_esc(name, conf->name))
1482 return conf;
1483 else if ((host != NULL) && match_esc(host, aconf->host))
1484 return conf;
1485 }
1486 break;
1487
1488 default:
1489 break;
1490 }
1491 return NULL;
1492 }
1493
1494 /* find_exact_name_conf()
1495 *
1496 * inputs - type of link list to look in
1497 * - pointer to name string to find
1498 * - pointer to user
1499 * - pointer to host
1500 * output - NULL or pointer to found struct MatchItem
1501 * side effects - looks for an exact match on name field
1502 */
1503 struct ConfItem *
1504 find_exact_name_conf(ConfType type, const struct Client *who, const char *name,
1505 const char *user, const char *host)
1506 {
1507 dlink_node *ptr = NULL;
1508 struct AccessItem *aconf;
1509 struct ConfItem *conf;
1510 struct MatchItem *match_item;
1511 dlink_list *list_p;
1512
1513 list_p = map_to_list(type);
1514
1515 switch(type)
1516 {
1517 case RXLINE_TYPE:
1518 case XLINE_TYPE:
1519 case ULINE_TYPE:
1520 case NRESV_TYPE:
1521
1522 DLINK_FOREACH(ptr, list_p->head)
1523 {
1524 conf = ptr->data;
1525 match_item = (struct MatchItem *)map_to_conf(conf);
1526 if (EmptyString(conf->name))
1527 continue;
1528
1529 if (irccmp(conf->name, name) == 0)
1530 {
1531 if ((user == NULL && (host == NULL)))
1532 return (conf);
1533 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1534 return (conf);
1535 if (match(match_item->user, user) && match(match_item->host, host))
1536 return (conf);
1537 }
1538 }
1539 break;
1540
1541 case OPER_TYPE:
1542 DLINK_FOREACH(ptr, list_p->head)
1543 {
1544 conf = ptr->data;
1545 aconf = map_to_conf(conf);
1546
1547 if (EmptyString(conf->name))
1548 continue;
1549
1550 if (!irccmp(conf->name, name))
1551 {
1552 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1553
1554 if (!who)
1555 return conf;
1556 if (EmptyString(aconf->user) || EmptyString(aconf->host))
1557 return NULL;
1558 if (match(aconf->user, who->username))
1559 {
1560 switch (aconf->type)
1561 {
1562 case HM_HOST:
1563 if (match(aconf->host, who->host) || match(aconf->host, who->sockhost))
1564 if (!aclass->max_total || aclass->curr_user_count < aclass->max_total)
1565 return conf;
1566 break;
1567 case HM_IPV4:
1568 if (who->localClient->aftype == AF_INET)
1569 if (match_ipv4(&who->localClient->ip, &aconf->addr, aconf->bits))
1570 if (!aclass->max_total || aclass->curr_user_count < aclass->max_total)
1571 return conf;
1572 break;
1573 #ifdef IPV6
1574 case HM_IPV6:
1575 if (who->localClient->aftype == AF_INET6)
1576 if (match_ipv6(&who->localClient->ip, &aconf->addr, aconf->bits))
1577 if (!aclass->max_total || aclass->curr_user_count < aclass->max_total)
1578 return conf;
1579 break;
1580 #endif
1581 default:
1582 assert(0);
1583 }
1584 }
1585 }
1586 }
1587
1588 break;
1589
1590 case SERVER_TYPE:
1591 DLINK_FOREACH(ptr, list_p->head)
1592 {
1593 conf = ptr->data;
1594 aconf = (struct AccessItem *)map_to_conf(conf);
1595 if (EmptyString(conf->name))
1596 continue;
1597
1598 if (name == NULL)
1599 {
1600 if (EmptyString(aconf->host))
1601 continue;
1602 if (irccmp(aconf->host, host) == 0)
1603 return(conf);
1604 }
1605 else if (irccmp(conf->name, name) == 0)
1606 {
1607 return (conf);
1608 }
1609 }
1610 break;
1611
1612 case CLASS_TYPE:
1613 DLINK_FOREACH(ptr, list_p->head)
1614 {
1615 conf = ptr->data;
1616 if (EmptyString(conf->name))
1617 continue;
1618
1619 if (irccmp(conf->name, name) == 0)
1620 return (conf);
1621 }
1622 break;
1623
1624 default:
1625 break;
1626 }
1627 return(NULL);
1628 }
1629
1630 /* rehash()
1631 *
1632 * Actual REHASH service routine. Called with sig == 0 if it has been called
1633 * as a result of an operator issuing this command, else assume it has been
1634 * called as a result of the server receiving a HUP signal.
1635 */
1636 int
1637 rehash(int sig)
1638 {
1639 if (sig != 0)
1640 sendto_realops_flags(UMODE_ALL, L_ALL,
1641 "Got signal SIGHUP, reloading ircd.conf file");
1642
1643 restart_resolver();
1644
1645 /* don't close listeners until we know we can go ahead with the rehash */
1646
1647 /* Check to see if we magically got(or lost) IPv6 support */
1648 check_can_use_v6();
1649
1650 read_conf_files(0);
1651
1652 if (ServerInfo.description != NULL)
1653 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
1654
1655 load_conf_modules();
1656
1657 flush_deleted_I_P();
1658
1659 rehashed_klines = 1;
1660
1661 return(0);
1662 }
1663
1664 /* set_default_conf()
1665 *
1666 * inputs - NONE
1667 * output - NONE
1668 * side effects - Set default values here.
1669 * This is called **PRIOR** to parsing the
1670 * configuration file. If you want to do some validation
1671 * of values later, put them in validate_conf().
1672 */
1673 static void
1674 set_default_conf(void)
1675 {
1676 /* verify init_class() ran, this should be an unnecessary check
1677 * but its not much work.
1678 */
1679 assert(class_default == (struct ConfItem *) class_items.tail->data);
1680
1681 #ifdef HAVE_LIBCRYPTO
1682 ServerInfo.rsa_private_key = NULL;
1683 ServerInfo.rsa_private_key_file = NULL;
1684 #endif
1685
1686 /* ServerInfo.name is not rehashable */
1687 /* ServerInfo.name = ServerInfo.name; */
1688 ServerInfo.description = NULL;
1689 DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
1690 DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
1691
1692 memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
1693 ServerInfo.specific_ipv4_vhost = 0;
1694 memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
1695 ServerInfo.specific_ipv6_vhost = 0;
1696
1697 ServerInfo.max_clients = MAXCLIENTS_MAX;
1698 ServerInfo.max_nick_length = 9;
1699 ServerInfo.max_topic_length = 80;
1700
1701 ServerInfo.hub = 0;
1702 ServerInfo.dns_host.sin_addr.s_addr = 0;
1703 ServerInfo.dns_host.sin_port = 0;
1704 AdminInfo.name = NULL;
1705 AdminInfo.email = NULL;
1706 AdminInfo.description = NULL;
1707
1708 log_del_all();
1709
1710 ConfigLoggingEntry.use_logging = 1;
1711
1712 ConfigChannel.disable_fake_channels = 0;
1713 ConfigChannel.restrict_channels = 0;
1714 ConfigChannel.knock_delay = 300;
1715 ConfigChannel.knock_delay_channel = 60;
1716 ConfigChannel.max_chans_per_user = 25;
1717 ConfigChannel.max_chans_per_oper = 50;
1718 ConfigChannel.quiet_on_ban = 1;
1719 ConfigChannel.max_bans = 25;
1720 ConfigChannel.default_split_user_count = 0;
1721 ConfigChannel.default_split_server_count = 0;
1722 ConfigChannel.no_join_on_split = 0;
1723 ConfigChannel.no_create_on_split = 0;
1724
1725 ConfigServerHide.flatten_links = 0;
1726 ConfigServerHide.links_delay = 300;
1727 ConfigServerHide.hidden = 0;
1728 ConfigServerHide.hide_servers = 0;
1729 DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1730 ConfigServerHide.hide_server_ips = 0;
1731
1732
1733 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1734 ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
1735 ConfigFileEntry.glines = 0;
1736 ConfigFileEntry.gline_time = 12 * 3600;
1737 ConfigFileEntry.gline_request_time = GLINE_REQUEST_EXPIRE_DEFAULT;
1738 ConfigFileEntry.gline_min_cidr = 16;
1739 ConfigFileEntry.gline_min_cidr6 = 48;
1740 ConfigFileEntry.invisible_on_connect = 1;
1741 ConfigFileEntry.tkline_expire_notices = 1;
1742 ConfigFileEntry.hide_spoof_ips = 1;
1743 ConfigFileEntry.ignore_bogus_ts = 0;
1744 ConfigFileEntry.disable_auth = 0;
1745 ConfigFileEntry.disable_remote = 0;
1746 ConfigFileEntry.kill_chase_time_limit = 90;
1747 ConfigFileEntry.default_floodcount = 8;
1748 ConfigFileEntry.failed_oper_notice = 1;
1749 ConfigFileEntry.dots_in_ident = 0;
1750 ConfigFileEntry.min_nonwildcard = 4;
1751 ConfigFileEntry.min_nonwildcard_simple = 3;
1752 ConfigFileEntry.max_accept = 20;
1753 ConfigFileEntry.anti_nick_flood = 0;
1754 ConfigFileEntry.max_nick_time = 20;
1755 ConfigFileEntry.max_nick_changes = 5;
1756 ConfigFileEntry.anti_spam_exit_message_time = 0;
1757 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1758 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1759 ConfigFileEntry.warn_no_nline = 1;
1760 ConfigFileEntry.stats_o_oper_only = 0;
1761 ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1762 ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1763 ConfigFileEntry.stats_P_oper_only = 0;
1764 ConfigFileEntry.caller_id_wait = 60;
1765 ConfigFileEntry.opers_bypass_callerid = 0;
1766 ConfigFileEntry.pace_wait = 10;
1767 ConfigFileEntry.pace_wait_simple = 1;
1768 ConfigFileEntry.short_motd = 0;
1769 ConfigFileEntry.ping_cookie = 0;
1770 ConfigFileEntry.no_oper_flood = 0;
1771 ConfigFileEntry.true_no_oper_flood = 0;
1772 ConfigFileEntry.oper_pass_resv = 1;
1773 ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1774 ConfigFileEntry.oper_only_umodes = UMODE_DEBUG;
1775 ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
1776 UMODE_OPERWALL | UMODE_WALLOP;
1777 ConfigFileEntry.use_egd = 0;
1778 ConfigFileEntry.egdpool_path = NULL;
1779 ConfigFileEntry.throttle_time = 10;
1780 }
1781
1782 static void
1783 validate_conf(void)
1784 {
1785 if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1786 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1787
1788 if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1789 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1790
1791 if (ServerInfo.network_name == NULL)
1792 DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1793
1794 if (ServerInfo.network_desc == NULL)
1795 DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1796
1797 if (ConfigFileEntry.service_name == NULL)
1798 DupString(ConfigFileEntry.service_name, SERVICE_NAME_DEFAULT);
1799
1800 ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
1801 }
1802
1803 /* read_conf()
1804 *
1805 * inputs - file descriptor pointing to config file to use
1806 * output - None
1807 * side effects - Read configuration file.
1808 */
1809 static void
1810 read_conf(FILE *file)
1811 {
1812 lineno = 0;
1813
1814 set_default_conf(); /* Set default values prior to conf parsing */
1815 conf_parser_ctx.pass = 1;
1816 yyparse(); /* pick up the classes first */
1817
1818 rewind(file);
1819
1820 conf_parser_ctx.pass = 2;
1821 yyparse(); /* Load the values from the conf */
1822 validate_conf(); /* Check to make sure some values are still okay. */
1823 /* Some global values are also loaded here. */
1824 check_class(); /* Make sure classes are valid */
1825 }
1826
1827 /* lookup_confhost()
1828 *
1829 * start DNS lookups of all hostnames in the conf
1830 * line and convert an IP addresses in a.b.c.d number for to IP#s.
1831 */
1832 static void
1833 lookup_confhost(struct ConfItem *conf)
1834 {
1835 struct AccessItem *aconf;
1836 struct addrinfo hints, *res;
1837
1838 aconf = map_to_conf(conf);
1839
1840 if (has_wildcards(aconf->host))
1841 {
1842 ilog(LOG_TYPE_IRCD, "Host/server name error: (%s) (%s)",
1843 aconf->host, conf->name);
1844 return;
1845 }
1846
1847 /* Do name lookup now on hostnames given and store the
1848 * ip numbers in conf structure.
1849 */
1850 memset(&hints, 0, sizeof(hints));
1851
1852 hints.ai_family = AF_UNSPEC;
1853 hints.ai_socktype = SOCK_STREAM;
1854
1855 /* Get us ready for a bind() and don't bother doing dns lookup */
1856 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
1857
1858 if (getaddrinfo(aconf->host, NULL, &hints, &res))
1859 {
1860 conf_dns_lookup(aconf);
1861 return;
1862 }
1863
1864 assert(res != NULL);
1865
1866 memcpy(&aconf->addr, res->ai_addr, res->ai_addrlen);
1867 aconf->addr.ss_len = res->ai_addrlen;
1868 aconf->addr.ss.ss_family = res->ai_family;
1869 freeaddrinfo(res);
1870 }
1871
1872 /* conf_connect_allowed()
1873 *
1874 * inputs - pointer to inaddr
1875 * - int type ipv4 or ipv6
1876 * output - BANNED or accepted
1877 * side effects - none
1878 */
1879 int
1880 conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
1881 {
1882 struct ip_entry *ip_found;
1883 struct AccessItem *aconf = find_dline_conf(addr, aftype);
1884
1885 /* DLINE exempt also gets you out of static limits/pacing... */
1886 if (aconf && (aconf->status & CONF_EXEMPTDLINE))
1887 return 0;
1888
1889 if (aconf != NULL)
1890 return BANNED_CLIENT;
1891
1892 ip_found = find_or_add_ip(addr);
1893
1894 if ((CurrentTime - ip_found->last_attempt) <
1895 ConfigFileEntry.throttle_time)
1896 {
1897 ip_found->last_attempt = CurrentTime;
1898 return TOO_FAST;
1899 }
1900
1901 ip_found->last_attempt = CurrentTime;
1902 return 0;
1903 }
1904
1905 static struct AccessItem *
1906 find_regexp_kline(const char *uhi[])
1907 {
1908 #ifdef HAVE_LIBPCRE
1909 const dlink_node *ptr = NULL;
1910
1911 DLINK_FOREACH(ptr, rkconf_items.head)
1912 {
1913 struct AccessItem *aptr = map_to_conf(ptr->data);
1914
1915 assert(aptr->regexuser);
1916 assert(aptr->regexhost);
1917
1918 if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
1919 (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
1920 !ircd_pcre_exec(aptr->regexhost, uhi[2])))
1921 return aptr;
1922 }
1923 #endif
1924 return NULL;
1925 }
1926
1927 /* find_kill()
1928 *
1929 * inputs - pointer to client structure
1930 * output - pointer to struct AccessItem if found
1931 * side effects - See if this user is klined already,
1932 * and if so, return struct AccessItem pointer
1933 */
1934 struct AccessItem *
1935 find_kill(struct Client *client_p)
1936 {
1937 struct AccessItem *aconf = NULL;
1938 const char *uhi[3];
1939
1940 uhi[0] = client_p->username;
1941 uhi[1] = client_p->host;
1942 uhi[2] = client_p->sockhost;
1943
1944 assert(client_p != NULL);
1945
1946 aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
1947 CONF_KLINE, client_p->localClient->aftype,
1948 client_p->username, NULL, 1, 0);
1949 if (aconf == NULL)
1950 aconf = find_regexp_kline(uhi);
1951
1952 return aconf;
1953 }
1954
1955 struct AccessItem *
1956 find_gline(struct Client *client_p)
1957 {
1958 struct AccessItem *aconf;
1959
1960 assert(client_p != NULL);
1961
1962 aconf = find_conf_by_address(client_p->host, &client_p->localClient->ip,
1963 CONF_GLINE, client_p->localClient->aftype,
1964 client_p->username, NULL, 1, 0);
1965 return aconf;
1966 }
1967
1968 /* add_temp_line()
1969 *
1970 * inputs - pointer to struct ConfItem
1971 * output - none
1972 * Side effects - links in given struct ConfItem into
1973 * temporary *line link list
1974 */
1975 void
1976 add_temp_line(struct ConfItem *conf)
1977 {
1978 if (conf->type == XLINE_TYPE)
1979 {
1980 conf->flags |= CONF_FLAGS_TEMPORARY;
1981 dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
1982 }
1983 else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
1984 {
1985 conf->flags |= CONF_FLAGS_TEMPORARY;
1986 dlinkAdd(conf, make_dlink_node(), &temporary_resv);
1987 }
1988 }
1989
1990 /* cleanup_tklines()
1991 *
1992 * inputs - NONE
1993 * output - NONE
1994 * side effects - call function to expire temporary k/d lines
1995 * This is an event started off in ircd.c
1996 */
1997 void
1998 cleanup_tklines(void *notused)
1999 {
2000 hostmask_expire_temporary();
2001 expire_tklines(&temporary_xlines);
2002 expire_tklines(&temporary_resv);
2003 }
2004
2005 /* expire_tklines()
2006 *
2007 * inputs - tkline list pointer
2008 * output - NONE
2009 * side effects - expire tklines
2010 */
2011 static void
2012 expire_tklines(dlink_list *tklist)
2013 {
2014 dlink_node *ptr;
2015 dlink_node *next_ptr;
2016 struct ConfItem *conf;
2017 struct MatchItem *xconf;
2018 struct MatchItem *nconf;
2019 struct ResvChannel *cconf;
2020
2021 DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2022 {
2023 conf = ptr->data;
2024
2025 if (conf->type == XLINE_TYPE)
2026 {
2027 xconf = (struct MatchItem *)map_to_conf(conf);
2028 if (xconf->hold <= CurrentTime)
2029 {
2030 if (ConfigFileEntry.tkline_expire_notices)
2031 sendto_realops_flags(UMODE_ALL, L_ALL,
2032 "Temporary X-line for [%s] expired", conf->name);
2033 dlinkDelete(ptr, tklist);
2034 free_dlink_node(ptr);
2035 delete_conf_item(conf);
2036 }
2037 }
2038 else if (conf->type == NRESV_TYPE)
2039 {
2040 nconf = (struct MatchItem *)map_to_conf(conf);
2041 if (nconf->hold <= CurrentTime)
2042 {
2043 if (ConfigFileEntry.tkline_expire_notices)
2044 sendto_realops_flags(UMODE_ALL, L_ALL,
2045 "Temporary RESV for [%s] expired", conf->name);
2046 dlinkDelete(ptr, tklist);
2047 free_dlink_node(ptr);
2048 delete_conf_item(conf);
2049 }
2050 }
2051 else if (conf->type == CRESV_TYPE)
2052 {
2053 cconf = (struct ResvChannel *)map_to_conf(conf);
2054 if (cconf->hold <= CurrentTime)
2055 {
2056 if (ConfigFileEntry.tkline_expire_notices)
2057 sendto_realops_flags(UMODE_ALL, L_ALL,
2058 "Temporary RESV for [%s] expired", cconf->name);
2059 delete_channel_resv(cconf);
2060 }
2061 }
2062 }
2063 }
2064
2065 /* oper_privs_as_string()
2066 *
2067 * inputs - pointer to client_p
2068 * output - pointer to static string showing oper privs
2069 * side effects - return as string, the oper privs as derived from port
2070 */
2071 static const struct oper_privs
2072 {
2073 const unsigned int oprivs;
2074 const unsigned char c;
2075 } flag_list[] = {
2076 { OPER_FLAG_ADMIN, 'A' },
2077 { OPER_FLAG_REMOTEBAN, 'B' },
2078 { OPER_FLAG_DIE, 'D' },
2079 { OPER_FLAG_GLINE, 'G' },
2080 { OPER_FLAG_REHASH, 'H' },
2081 { OPER_FLAG_K, 'K' },
2082 { OPER_FLAG_OPERWALL, 'L' },
2083 { OPER_FLAG_N, 'N' },
2084 { OPER_FLAG_GLOBAL_KILL, 'O' },
2085 { OPER_FLAG_REMOTE, 'R' },
2086 { OPER_FLAG_OPER_SPY, 'S' },
2087 { OPER_FLAG_UNKLINE, 'U' },
2088 { OPER_FLAG_X, 'X' },
2089 { 0, '\0' }
2090 };
2091
2092 char *
2093 oper_privs_as_string(const unsigned int port)
2094 {
2095 static char privs_out[16];
2096 char *privs_ptr = privs_out;
2097 unsigned int i = 0;
2098
2099 for (; flag_list[i].oprivs; ++i)
2100 {
2101 if (port & flag_list[i].oprivs)
2102 *privs_ptr++ = flag_list[i].c;
2103 else
2104 *privs_ptr++ = ToLowerTab[flag_list[i].c];
2105 }
2106
2107 *privs_ptr = '\0';
2108
2109 return privs_out;
2110 }
2111
2112 /*
2113 * Input: A client to find the active oper{} name for.
2114 * Output: The nick!user@host{oper} of the oper.
2115 * "oper" is server name for remote opers
2116 * Side effects: None.
2117 */
2118 const char *
2119 get_oper_name(const struct Client *client_p)
2120 {
2121 dlink_node *cnode = NULL;
2122 /* +5 for !,@,{,} and null */
2123 static char buffer[NICKLEN + USERLEN + HOSTLEN + HOSTLEN + 5];
2124
2125 if (MyConnect(client_p))
2126 {
2127 if ((cnode = client_p->localClient->confs.head))
2128 {
2129 struct ConfItem *conf = cnode->data;
2130 const struct AccessItem *aconf = map_to_conf(conf);
2131
2132 if (IsConfOperator(aconf))
2133 {
2134 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2135 client_p->username, client_p->host, conf->name);
2136 return buffer;
2137 }
2138 }
2139
2140 /* Probably should assert here for now. If there is an oper out there
2141 * with no oper{} conf attached, it would be good for us to know...
2142 */
2143 assert(0); /* Oper without oper conf! */
2144 }
2145
2146 snprintf(buffer, sizeof(buffer), "%s!%s@%s{%s}", client_p->name,
2147 client_p->username, client_p->host, client_p->servptr->name);
2148 return buffer;
2149 }
2150
2151 /* read_conf_files()
2152 *
2153 * inputs - cold start YES or NO
2154 * output - none
2155 * side effects - read all conf files needed, ircd.conf kline.conf etc.
2156 */
2157 void
2158 read_conf_files(int cold)
2159 {
2160 const char *filename;
2161 char chanmodes[32];
2162 char chanlimit[32];
2163
2164 conf_parser_ctx.boot = cold;
2165 filename = get_conf_name(CONF_TYPE);
2166
2167 /* We need to know the initial filename for the yyerror() to report
2168 FIXME: The full path is in conffilenamebuf first time since we
2169 dont know anything else
2170
2171 - Gozem 2002-07-21
2172 */
2173 strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2174
2175 if ((conf_parser_ctx.conf_file = fopen(filename, "r")) == NULL)
2176 {
2177 if (cold)
2178 {
2179 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2180 filename, strerror(errno));
2181 exit(-1);
2182 }
2183 else
2184 {
2185 sendto_realops_flags(UMODE_ALL, L_ALL,
2186 "Unable to read configuration file '%s': %s",
2187 filename, strerror(errno));
2188 return;
2189 }
2190 }
2191
2192 if (!cold)
2193 clear_out_old_conf();
2194
2195 read_conf(conf_parser_ctx.conf_file);
2196 fclose(conf_parser_ctx.conf_file);
2197
2198 log_reopen_all();
2199
2200 add_isupport("NICKLEN", NULL, ServerInfo.max_nick_length);
2201
2202 add_isupport("NETWORK", ServerInfo.network_name, -1);
2203 snprintf(chanmodes, sizeof(chanmodes), "beI:%d",
2204 ConfigChannel.max_bans);
2205 add_isupport("MAXLIST", chanmodes, -1);
2206 add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2207
2208 add_isupport("CHANTYPES", "#", -1);
2209
2210 snprintf(chanlimit, sizeof(chanlimit), "#:%d",
2211 ConfigChannel.max_chans_per_user);
2212 add_isupport("CHANLIMIT", chanlimit, -1);
2213 snprintf(chanmodes, sizeof(chanmodes), "%s",
2214 "beI,k,l,imnprstORS");
2215 add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
2216 add_isupport("TOPICLEN", NULL, ServerInfo.max_topic_length);
2217
2218 add_isupport("EXCEPTS", "e", -1);
2219 add_isupport("INVEX", "I", -1);
2220 add_isupport("CHANMODES", chanmodes, -1);
2221
2222 /*
2223 * message_locale may have changed. rebuild isupport since it relies
2224 * on strlen(form_str(RPL_ISUPPORT))
2225 */
2226 rebuild_isupport_message_line();
2227
2228 parse_conf_file(KLINE_TYPE, cold);
2229 parse_conf_file(DLINE_TYPE, cold);
2230 parse_conf_file(XLINE_TYPE, cold);
2231 parse_conf_file(NRESV_TYPE, cold);
2232 parse_conf_file(CRESV_TYPE, cold);
2233 }
2234
2235 /* parse_conf_file()
2236 *
2237 * inputs - type of conf file to parse
2238 * output - none
2239 * side effects - conf file for givenconf type is opened and read then parsed
2240 */
2241 static void
2242 parse_conf_file(int type, int cold)
2243 {
2244 FILE *file = NULL;
2245 const char *filename = get_conf_name(type);
2246
2247 if ((file = fopen(filename, "r")) == NULL)
2248 {
2249 if (cold)
2250 ilog(LOG_TYPE_IRCD, "Unable to read configuration file '%s': %s",
2251 filename, strerror(errno));
2252 else
2253 sendto_realops_flags(UMODE_ALL, L_ALL,
2254 "Unable to read configuration file '%s': %s",
2255 filename, strerror(errno));
2256 }
2257 else
2258 {
2259 parse_csv_file(file, type);
2260 fclose(file);
2261 }
2262 }
2263
2264 /* clear_out_old_conf()
2265 *
2266 * inputs - none
2267 * output - none
2268 * side effects - Clear out the old configuration
2269 */
2270 static void
2271 clear_out_old_conf(void)
2272 {
2273 dlink_node *ptr = NULL, *next_ptr = NULL;
2274 struct ConfItem *conf;
2275 struct AccessItem *aconf;
2276 struct ClassItem *cltmp;
2277 dlink_list *free_items [] = {
2278 &server_items, &oconf_items,
2279 &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2280 &nresv_items, &cluster_items, &service_items, NULL
2281 };
2282
2283 dlink_list ** iterator = free_items; /* C is dumb */
2284
2285 /* We only need to free anything allocated by yyparse() here.
2286 * Resetting structs, etc, is taken care of by set_default_conf().
2287 */
2288
2289 for (; *iterator != NULL; iterator++)
2290 {
2291 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2292 {
2293 conf = ptr->data;
2294 /* XXX This is less than pretty */
2295 if (conf->type == SERVER_TYPE)
2296 {
2297 aconf = map_to_conf(conf);
2298
2299 if (aconf->clients != 0)
2300 {
2301 SetConfIllegal(aconf);
2302 dlinkDelete(&conf->node, &server_items);
2303 }
2304 else
2305 {
2306 delete_conf_item(conf);
2307 }
2308 }
2309 else if (conf->type == OPER_TYPE)
2310 {
2311 aconf = map_to_conf(conf);
2312
2313 if (aconf->clients != 0)
2314 {
2315 SetConfIllegal(aconf);
2316 dlinkDelete(&conf->node, &oconf_items);
2317 }
2318 else
2319 {
2320 delete_conf_item(conf);
2321 }
2322 }
2323 else if (conf->type == XLINE_TYPE ||
2324 conf->type == RXLINE_TYPE ||
2325 conf->type == RKLINE_TYPE)
2326 {
2327 /* temporary (r)xlines are also on
2328 * the (r)xconf items list */
2329 if (conf->flags & CONF_FLAGS_TEMPORARY)
2330 continue;
2331
2332 delete_conf_item(conf);
2333 }
2334 else
2335 {
2336 delete_conf_item(conf);
2337 }
2338 }
2339 }
2340
2341 /*
2342 * don't delete the class table, rather mark all entries
2343 * for deletion. The table is cleaned up by check_class. - avalon
2344 */
2345 DLINK_FOREACH(ptr, class_items.head)
2346 {
2347 cltmp = map_to_conf(ptr->data);
2348
2349 if (ptr != class_items.tail) /* never mark the "default" class */
2350 cltmp->active = 0;
2351 }
2352
2353 clear_out_address_conf();
2354
2355 /* clean out module paths */
2356 mod_clear_paths();
2357
2358 /* clean out ServerInfo */
2359 MyFree(ServerInfo.description);
2360 ServerInfo.description = NULL;
2361 MyFree(ServerInfo.network_name);
2362 ServerInfo.network_name = NULL;
2363 MyFree(ServerInfo.network_desc);
2364 ServerInfo.network_desc = NULL;
2365 MyFree(ConfigFileEntry.egdpool_path);
2366 ConfigFileEntry.egdpool_path = NULL;
2367 #ifdef HAVE_LIBCRYPTO
2368 if (ServerInfo.rsa_private_key != NULL)
2369 {
2370 RSA_free(ServerInfo.rsa_private_key);
2371 ServerInfo.rsa_private_key = NULL;
2372 }
2373
2374 MyFree(ServerInfo.rsa_private_key_file);
2375 ServerInfo.rsa_private_key_file = NULL;
2376
2377 if (ServerInfo.server_ctx)
2378 SSL_CTX_set_options(ServerInfo.server_ctx, SSL_OP_NO_SSLv2|
2379 SSL_OP_NO_SSLv3|
2380 SSL_OP_NO_TLSv1);
2381 if (ServerInfo.client_ctx)
2382 SSL_CTX_set_options(ServerInfo.client_ctx, SSL_OP_NO_SSLv2|
2383 SSL_OP_NO_SSLv3|
2384 SSL_OP_NO_TLSv1);
2385 #endif
2386
2387 /* clean out old resvs from the conf */
2388 clear_conf_resv();
2389
2390 /* clean out AdminInfo */
2391 MyFree(AdminInfo.name);
2392 AdminInfo.name = NULL;
2393 MyFree(AdminInfo.email);
2394 AdminInfo.email = NULL;
2395 MyFree(AdminInfo.description);
2396 AdminInfo.description = NULL;
2397
2398 /* operator{} and class{} blocks are freed above */
2399 /* clean out listeners */
2400 close_listeners();
2401
2402 /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2403 * exempt{} and gecos{} blocks are freed above too
2404 */
2405
2406 /* clean out general */
2407 MyFree(ConfigFileEntry.service_name);
2408 ConfigFileEntry.service_name = NULL;
2409
2410 delete_isupport("INVEX");
2411 delete_isupport("EXCEPTS");
2412 }
2413
2414 /* flush_deleted_I_P()
2415 *
2416 * inputs - none
2417 * output - none
2418 * side effects - This function removes I/P conf items
2419 */
2420 static void
2421 flush_deleted_I_P(void)
2422 {
2423 dlink_node *ptr;
2424 dlink_node *next_ptr;
2425 struct ConfItem *conf;
2426 struct AccessItem *aconf;
2427 dlink_list * free_items [] = {
2428 &server_items, &oconf_items, NULL
2429 };
2430 dlink_list ** iterator = free_items; /* C is dumb */
2431
2432 /* flush out deleted I and P lines
2433 * although still in use.
2434 */
2435 for (; *iterator != NULL; iterator++)
2436 {
2437 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2438 {
2439 conf = ptr->data;
2440 aconf = (struct AccessItem *)map_to_conf(conf);
2441
2442 if (IsConfIllegal(aconf))
2443 {
2444 dlinkDelete(ptr, *iterator);
2445
2446 if (aconf->clients == 0)
2447 delete_conf_item(conf);
2448 }
2449 }
2450 }
2451 }
2452
2453 /* get_conf_name()
2454 *
2455 * inputs - type of conf file to return name of file for
2456 * output - pointer to filename for type of conf
2457 * side effects - none
2458 */
2459 const char *
2460 get_conf_name(ConfType type)
2461 {
2462 switch (type)
2463 {
2464 case CONF_TYPE:
2465 return ConfigFileEntry.configfile;
2466 break;
2467 case KLINE_TYPE:
2468 return ConfigFileEntry.klinefile;
2469 break;
2470 case DLINE_TYPE:
2471 return ConfigFileEntry.dlinefile;
2472 break;
2473 case XLINE_TYPE:
2474 return ConfigFileEntry.xlinefile;
2475 break;
2476 case CRESV_TYPE:
2477 return ConfigFileEntry.cresvfile;
2478 break;
2479 case NRESV_TYPE:
2480 return ConfigFileEntry.nresvfile;
2481 break;
2482 default:
2483 return NULL; /* This should NEVER HAPPEN since we call this function
2484 only with the above values, this will cause us to core
2485 at some point if this happens so we know where it was */
2486 }
2487 }
2488
2489 #define BAD_PING (-1)
2490
2491 /* get_conf_ping()
2492 *
2493 * inputs - pointer to struct AccessItem
2494 * - pointer to a variable that receives ping warning time
2495 * output - ping frequency
2496 * side effects - NONE
2497 */
2498 static int
2499 get_conf_ping(struct ConfItem *conf, int *pingwarn)
2500 {
2501 struct ClassItem *aclass;
2502 struct AccessItem *aconf;
2503
2504 if (conf != NULL)
2505 {
2506 aconf = (struct AccessItem *)map_to_conf(conf);
2507 if (aconf->class_ptr != NULL)
2508 {
2509 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2510 *pingwarn = aclass->ping_warning;
2511 return aclass->ping_freq;
2512 }
2513 }
2514
2515 return BAD_PING;
2516 }
2517
2518 struct ClassItem *
2519 get_client_class_ptr(struct Client *target_p)
2520 {
2521 dlink_node *cnode = NULL;
2522 struct AccessItem *aconf = NULL;
2523
2524 assert(!IsMe(target_p));
2525
2526 if ((cnode = target_p->localClient->confs.head))
2527 {
2528 struct ConfItem *conf = cnode->data;
2529
2530 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2531 (conf->type == OPER_TYPE));
2532
2533 aconf = map_to_conf(conf);
2534 if (aconf->class_ptr != NULL)
2535 return map_to_conf(aconf->class_ptr);
2536 }
2537
2538 return NULL;
2539 }
2540
2541 /* get_client_class()
2542 *
2543 * inputs - pointer to client struct
2544 * output - pointer to name of class
2545 * side effects - NONE
2546 */
2547 const char *
2548 get_client_class(struct Client *target_p)
2549 {
2550 dlink_node *cnode = NULL;
2551 struct AccessItem *aconf = NULL;
2552
2553 assert(!IsMe(target_p));
2554
2555 if ((cnode = target_p->localClient->confs.head))
2556 {
2557 struct ConfItem *conf = cnode->data;
2558
2559 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2560 (conf->type == OPER_TYPE));
2561
2562 aconf = map_to_conf(conf);
2563 if (aconf->class_ptr != NULL)
2564 return aconf->class_ptr->name;
2565 }
2566
2567 return "default";
2568 }
2569
2570 /* get_client_ping()
2571 *
2572 * inputs - pointer to client struct
2573 * - pointer to a variable that receives ping warning time
2574 * output - ping frequency
2575 * side effects - NONE
2576 */
2577 int
2578 get_client_ping(struct Client *target_p, int *pingwarn)
2579 {
2580 int ping = 0;
2581 dlink_node *cnode = NULL;
2582
2583 if ((cnode = target_p->localClient->confs.head))
2584 {
2585 struct ConfItem *conf = cnode->data;
2586
2587 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2588 (conf->type == OPER_TYPE));
2589
2590 ping = get_conf_ping(conf, pingwarn);
2591 if (ping > 0)
2592 return ping;
2593 }
2594
2595 *pingwarn = 0;
2596 return DEFAULT_PINGFREQUENCY;
2597 }
2598
2599 /* find_class()
2600 *
2601 * inputs - string name of class
2602 * output - corresponding Class pointer
2603 * side effects - NONE
2604 */
2605 struct ConfItem *
2606 find_class(const char *classname)
2607 {
2608 struct ConfItem *conf;
2609
2610 if ((conf = find_exact_name_conf(CLASS_TYPE, NULL, classname, NULL, NULL)) != NULL)
2611 return conf;
2612
2613 return class_default;
2614 }
2615
2616 /* check_class()
2617 *
2618 * inputs - NONE
2619 * output - NONE
2620 * side effects -
2621 */
2622 void
2623 check_class(void)
2624 {
2625 dlink_node *ptr = NULL, *next_ptr = NULL;
2626
2627 DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2628 {
2629 struct ClassItem *aclass = map_to_conf(ptr->data);
2630
2631 if (!aclass->active && !aclass->curr_user_count)
2632 {
2633 destroy_cidr_class(aclass);
2634 delete_conf_item(ptr->data);
2635 }
2636 }
2637 }
2638
2639 /* init_class()
2640 *
2641 * inputs - NONE
2642 * output - NONE
2643 * side effects -
2644 */
2645 void
2646 init_class(void)
2647 {
2648 struct ClassItem *aclass;
2649
2650 class_default = make_conf_item(CLASS_TYPE);
2651
2652 aclass = map_to_conf(class_default);
2653 aclass->active = 1;
2654 DupString(class_default->name, "default");
2655 aclass->con_freq = DEFAULT_CONNECTFREQUENCY;
2656 aclass->ping_freq = DEFAULT_PINGFREQUENCY;
2657 aclass->max_total = MAXIMUM_LINKS_DEFAULT;
2658 aclass->max_sendq = DEFAULT_SENDQ;
2659 aclass->max_recvq = DEFAULT_RECVQ;
2660
2661 client_check_cb = register_callback("check_client", check_client);
2662 }
2663
2664 /* get_sendq()
2665 *
2666 * inputs - pointer to client
2667 * output - sendq for this client as found from its class
2668 * side effects - NONE
2669 */
2670 unsigned int
2671 get_sendq(struct Client *client_p)
2672 {
2673 unsigned int sendq = DEFAULT_SENDQ;
2674 dlink_node *cnode;
2675 struct ConfItem *class_conf;
2676 struct ClassItem *aclass;
2677 struct AccessItem *aconf;
2678
2679 assert(!IsMe(client_p));
2680
2681 if ((cnode = client_p->localClient->confs.head))
2682 {
2683 struct ConfItem *conf = cnode->data;
2684
2685 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2686 (conf->type == OPER_TYPE));
2687
2688 aconf = map_to_conf(conf);
2689
2690 if ((class_conf = aconf->class_ptr) == NULL)
2691 return DEFAULT_SENDQ; /* TBV: shouldn't be possible at all */
2692
2693 aclass = map_to_conf(class_conf);
2694 sendq = aclass->max_sendq;
2695 return sendq;
2696 }
2697
2698 /* XXX return a default?
2699 * if here, then there wasn't an attached conf with a sendq
2700 * that is very bad -Dianora
2701 */
2702 return DEFAULT_SENDQ;
2703 }
2704
2705 unsigned int
2706 get_recvq(struct Client *client_p)
2707 {
2708 unsigned int recvq = DEFAULT_RECVQ;
2709 dlink_node *cnode;
2710 struct ConfItem *class_conf;
2711 struct ClassItem *aclass;
2712 struct AccessItem *aconf;
2713
2714 assert(!IsMe(client_p));
2715
2716 if ((cnode = client_p->localClient->confs.head))
2717 {
2718 struct ConfItem *conf = cnode->data;
2719
2720 assert((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2721 (conf->type == OPER_TYPE));
2722
2723 aconf = map_to_conf(conf);
2724
2725 if ((class_conf = aconf->class_ptr) == NULL)
2726 return DEFAULT_RECVQ; /* TBV: shouldn't be possible at all */
2727
2728 aclass = map_to_conf(class_conf);
2729 recvq = aclass->max_recvq;
2730 return recvq;
2731 }
2732
2733 /* XXX return a default?
2734 * if here, then there wasn't an attached conf with a recvq
2735 * that is very bad -Dianora
2736 */
2737 return DEFAULT_RECVQ;
2738 }
2739
2740 /* conf_add_class_to_conf()
2741 *
2742 * inputs - pointer to config item
2743 * output - NONE
2744 * side effects - Add a class pointer to a conf
2745 */
2746 void
2747 conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
2748 {
2749 struct AccessItem *aconf = map_to_conf(conf);
2750 struct ClassItem *class = NULL;
2751
2752 if (class_name == NULL)
2753 {
2754 aconf->class_ptr = class_default;
2755
2756 if (conf->type == CLIENT_TYPE)
2757 sendto_realops_flags(UMODE_ALL, L_ALL,
2758 "Warning *** Defaulting to default class for %s@%s",
2759 aconf->user, aconf->host);
2760 else
2761 sendto_realops_flags(UMODE_ALL, L_ALL,
2762 "Warning *** Defaulting to default class for %s",
2763 conf->name);
2764 }
2765 else
2766 aconf->class_ptr = find_class(class_name);
2767
2768 if (aconf->class_ptr)
2769 class = map_to_conf(aconf->class_ptr);
2770
2771 if (aconf->class_ptr == NULL || !class->active)
2772 {
2773 if (conf->type == CLIENT_TYPE)
2774 sendto_realops_flags(UMODE_ALL, L_ALL,
2775 "Warning *** Defaulting to default class for %s@%s",
2776 aconf->user, aconf->host);
2777 else
2778 sendto_realops_flags(UMODE_ALL, L_ALL,
2779 "Warning *** Defaulting to default class for %s",
2780 conf->name);
2781 aconf->class_ptr = class_default;
2782 }
2783 }
2784
2785 /* conf_add_server()
2786 *
2787 * inputs - pointer to config item
2788 * - pointer to link count already on this conf
2789 * output - NONE
2790 * side effects - Add a connect block
2791 */
2792 int
2793 conf_add_server(struct ConfItem *conf, const char *class_name)
2794 {
2795 struct AccessItem *aconf = map_to_conf(conf);
2796
2797 conf_add_class_to_conf(conf, class_name);
2798
2799 if (!aconf->host || !conf->name)
2800 {
2801 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
2802 ilog(LOG_TYPE_IRCD, "Bad connect block");
2803 return -1;
2804 }
2805
2806 if (EmptyString(aconf->passwd))
2807 {
2808 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
2809 conf->name);
2810 ilog(LOG_TYPE_IRCD, "Bad connect block, host %s", conf->name);
2811 return -1;
2812 }
2813
2814 lookup_confhost(conf);
2815
2816 return 0;
2817 }
2818
2819 /* yyerror()
2820 *
2821 * inputs - message from parser
2822 * output - NONE
2823 * side effects - message to opers and log file entry is made
2824 */
2825 void
2826 yyerror(const char *msg)
2827 {
2828 char newlinebuf[IRCD_BUFSIZE];
2829
2830 if (conf_parser_ctx.pass != 1)
2831 return;
2832
2833 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
2834 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
2835 conffilebuf, lineno + 1, msg, newlinebuf);
2836 ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s",
2837 conffilebuf, lineno + 1, msg, newlinebuf);
2838 }
2839
2840 void
2841 conf_error_report(const char *msg)
2842 {
2843 char newlinebuf[IRCD_BUFSIZE];
2844
2845 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
2846 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
2847 conffilebuf, lineno + 1, msg, newlinebuf);
2848 ilog(LOG_TYPE_IRCD, "\"%s\", line %u: %s: %s",
2849 conffilebuf, lineno + 1, msg, newlinebuf);
2850 }
2851
2852 /*
2853 * valid_tkline()
2854 *
2855 * inputs - pointer to ascii string to check
2856 * - whether the specified time is in seconds or minutes
2857 * output - -1 not enough parameters
2858 * - 0 if not an integer number, else the number
2859 * side effects - none
2860 * Originally written by Dianora (Diane, db@db.net)
2861 */
2862 time_t
2863 valid_tkline(const char *p, int minutes)
2864 {
2865 time_t result = 0;
2866
2867 for (; *p; ++p)
2868 {
2869 if (!IsDigit(*p))
2870 return 0;
2871
2872 result *= 10;
2873 result += ((*p) & 0xF);
2874 }
2875
2876 /*
2877 * In the degenerate case where oper does a /quote kline 0 user@host :reason
2878 * i.e. they specifically use 0, I am going to return 1 instead
2879 * as a return value of non-zero is used to flag it as a temporary kline
2880 */
2881 if (result == 0)
2882 result = 1;
2883
2884 /*
2885 * If the incoming time is in seconds convert it to minutes for the purpose
2886 * of this calculation
2887 */
2888 if (!minutes)
2889 result = result / (time_t)60;
2890
2891 if (result > MAX_TDKLINE_TIME)
2892 result = MAX_TDKLINE_TIME;
2893
2894 result = result * (time_t)60; /* turn it into seconds */
2895
2896 return result;
2897 }
2898
2899 /* valid_wild_card()
2900 *
2901 * input - pointer to client
2902 * - int flag, 0 for no warning oper 1 for warning oper
2903 * - count of following varargs to check
2904 * output - 0 if not valid, 1 if valid
2905 * side effects - NOTICE is given to source_p if warn is 1
2906 */
2907 int
2908 valid_wild_card(struct Client *source_p, int warn, int count, ...)
2909 {
2910 char *p;
2911 char tmpch;
2912 int nonwild = 0;
2913 va_list args;
2914
2915 /*
2916 * Now we must check the user and host to make sure there
2917 * are at least NONWILDCHARS non-wildcard characters in
2918 * them, otherwise assume they are attempting to kline
2919 * *@* or some variant of that. This code will also catch
2920 * people attempting to kline *@*.tld, as long as NONWILDCHARS
2921 * is greater than 3. In that case, there are only 3 non-wild
2922 * characters (tld), so if NONWILDCHARS is 4, the kline will
2923 * be disallowed.
2924 * -wnder
2925 */
2926
2927 va_start(args, count);
2928
2929 while (count--)
2930 {
2931 p = va_arg(args, char *);
2932 if (p == NULL)
2933 continue;
2934
2935 while ((tmpch = *p++))
2936 {
2937 if (!IsKWildChar(tmpch))
2938 {
2939 /*
2940 * If we find enough non-wild characters, we can
2941 * break - no point in searching further.
2942 */
2943 if (++nonwild >= ConfigFileEntry.min_nonwildcard)
2944 return 1;
2945 }
2946 }
2947 }
2948
2949 if (warn)
2950 sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
2951 me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
2952 return 0;
2953 }
2954
2955 /* XXX should this go into a separate file ? -Dianora */
2956 /* parse_aline
2957 *
2958 * input - pointer to cmd name being used
2959 * - pointer to client using cmd
2960 * - parc parameter count
2961 * - parv[] list of parameters to parse
2962 * - parse_flags bit map of things to test
2963 * - pointer to user or string to parse into
2964 * - pointer to host or NULL to parse into if non NULL
2965 * - pointer to optional tkline time or NULL
2966 * - pointer to target_server to parse into if non NULL
2967 * - pointer to reason to parse into
2968 *
2969 * output - 1 if valid, -1 if not valid
2970 * side effects - A generalised k/d/x etc. line parser,
2971 * "ALINE [time] user@host|string [ON] target :reason"
2972 * will parse returning a parsed user, host if
2973 * h_p pointer is non NULL, string otherwise.
2974 * if tkline_time pointer is non NULL a tk line will be set
2975 * to non zero if found.
2976 * if tkline_time pointer is NULL and tk line is found,
2977 * error is reported.
2978 * if target_server is NULL and an "ON" is found error
2979 * is reported.
2980 * if reason pointer is NULL ignore pointer,
2981 * this allows use of parse_a_line in unkline etc.
2982 *
2983 * - Dianora
2984 */
2985 int
2986 parse_aline(const char *cmd, struct Client *source_p,
2987 int parc, char **parv,
2988 int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
2989 char **target_server, char **reason)
2990 {
2991 int found_tkline_time=0;
2992 static char def_reason[] = CONF_NOREASON;
2993 static char user[USERLEN*4+1];
2994 static char host[HOSTLEN*4+1];
2995
2996 parv++;
2997 parc--;
2998
2999 found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3000
3001 if (found_tkline_time != 0)
3002 {
3003 parv++;
3004 parc--;
3005
3006 if (tkline_time != NULL)
3007 *tkline_time = found_tkline_time;
3008 else
3009 {
3010 sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3011 me.name, source_p->name, cmd);
3012 return -1;
3013 }
3014 }
3015
3016 if (parc == 0)
3017 {
3018 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3019 me.name, source_p->name, cmd);
3020 return -1;
3021 }
3022
3023 if (h_p == NULL)
3024 *up_p = *parv;
3025 else
3026 {
3027 if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3028 return -1;
3029
3030 *up_p = user;
3031 *h_p = host;
3032 }
3033
3034 parc--;
3035 parv++;
3036
3037 if (parc != 0)
3038 {
3039 if (irccmp(*parv, "ON") == 0)
3040 {
3041 parc--;
3042 parv++;
3043
3044 if (target_server == NULL)
3045 {
3046 sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3047 me.name, source_p->name, cmd);
3048 return -1;
3049 }
3050
3051 if (!HasOFlag(source_p, OPER_FLAG_REMOTEBAN))
3052 {
3053 sendto_one(source_p, form_str(ERR_NOPRIVS),
3054 me.name, source_p->name, "remoteban");
3055 return -1;
3056 }
3057
3058 if (parc == 0 || EmptyString(*parv))
3059 {
3060 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3061 me.name, source_p->name, cmd);
3062 return -1;
3063 }
3064
3065 *target_server = *parv;
3066 parc--;
3067 parv++;
3068 }
3069 else
3070 {
3071 /* Make sure target_server *is* NULL if no ON server found
3072 * caller probably NULL'd it first, but no harm to do it again -db
3073 */
3074 if (target_server != NULL)
3075 *target_server = NULL;
3076 }
3077 }
3078
3079 if (h_p != NULL)
3080 {
3081 if (strchr(user, '!') != NULL)
3082 {
3083 sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3084 me.name, source_p->name);
3085 return -1;
3086 }
3087
3088 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 2, *up_p, *h_p))
3089 return -1;
3090 }
3091 else
3092 if ((parse_flags & AWILD) && !valid_wild_card(source_p, 1, 1, *up_p))
3093 return -1;
3094
3095 if (reason != NULL)
3096 {
3097 if (parc != 0 && !EmptyString(*parv))
3098 {
3099 *reason = *parv;
3100 if (!valid_comment(source_p, *reason, 1))
3101 return -1;
3102 }
3103 else
3104 *reason = def_reason;
3105 }
3106
3107 return 1;
3108 }
3109
3110 /* find_user_host()
3111 *
3112 * inputs - pointer to client placing kline
3113 * - pointer to user_host_or_nick
3114 * - pointer to user buffer
3115 * - pointer to host buffer
3116 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3117 * side effects -
3118 */
3119 static int
3120 find_user_host(struct Client *source_p, char *user_host_or_nick,
3121 char *luser, char *lhost, unsigned int flags)
3122 {
3123 struct Client *target_p = NULL;
3124 char *hostp = NULL;
3125
3126 if (lhost == NULL)
3127 {
3128 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3129 return 1;
3130 }
3131
3132 if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3133 {
3134 /* Explicit user@host mask given */
3135
3136 if (hostp != NULL) /* I'm a little user@host */
3137 {
3138 *(hostp++) = '\0'; /* short and squat */
3139 if (*user_host_or_nick)
3140 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3141 else
3142 strcpy(luser, "*");
3143 if (*hostp)
3144 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3145 else
3146 strcpy(lhost, "*");
3147 }
3148 else
3149 {
3150 luser[0] = '*'; /* no @ found, assume its *@somehost */
3151 luser[1] = '\0';
3152 strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3153 }
3154
3155 return 1;
3156 }
3157 else
3158 {
3159 /* Try to find user@host mask from nick */
3160 /* Okay to use source_p as the first param, because source_p == client_p */
3161 if ((target_p =
3162 find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3163 return 0;
3164
3165 if (IsExemptKline(target_p))
3166 {
3167 if (!IsServer(source_p))
3168 sendto_one(source_p,
3169 ":%s NOTICE %s :%s is E-lined",
3170 me.name, source_p->name, target_p->name);
3171 return 0;
3172 }
3173
3174 /*
3175 * turn the "user" bit into "*user", blow away '~'
3176 * if found in original user name (non-idented)
3177 */
3178 strlcpy(luser, target_p->username, USERLEN*4 + 1);
3179
3180 if (target_p->username[0] == '~')
3181 luser[0] = '*';
3182
3183 if (target_p->sockhost[0] == '\0' ||
3184 (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3185 strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3186 else
3187 strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3188 return 1;
3189 }
3190
3191 return 0;
3192 }
3193
3194 /* valid_comment()
3195 *
3196 * inputs - pointer to client
3197 * - pointer to comment
3198 * output - 0 if no valid comment,
3199 * - 1 if valid
3200 * side effects - truncates reason where necessary
3201 */
3202 int
3203 valid_comment(struct Client *source_p, char *comment, int warn)
3204 {
3205 if (strchr(comment, '"'))
3206 {
3207 if (warn)
3208 sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3209 me.name, source_p->name);
3210 return 0;
3211 }
3212
3213 if (strlen(comment) > REASONLEN)
3214 comment[REASONLEN-1] = '\0';
3215
3216 return 1;
3217 }
3218
3219 /* match_conf_password()
3220 *
3221 * inputs - pointer to given password
3222 * - pointer to Conf
3223 * output - 1 or 0 if match
3224 * side effects - none
3225 */
3226 int
3227 match_conf_password(const char *password, const struct AccessItem *aconf)
3228 {
3229 const char *encr = NULL;
3230
3231 if (EmptyString(password) || EmptyString(aconf->passwd))
3232 return 0;
3233
3234 if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3235 encr = crypt(password, aconf->passwd);
3236 else
3237 encr = password;
3238
3239 return !strcmp(encr, aconf->passwd);
3240 }
3241
3242 /*
3243 * cluster_a_line
3244 *
3245 * inputs - client sending the cluster
3246 * - command name "KLINE" "XLINE" etc.
3247 * - capab -- CAP_KLN etc. from s_serv.h
3248 * - cluster type -- CLUSTER_KLINE etc. from conf.h
3249 * - pattern and args to send along
3250 * output - none
3251 * side effects - Take source_p send the pattern with args given
3252 * along to all servers that match capab and cluster type
3253 */
3254 void
3255 cluster_a_line(struct Client *source_p, const char *command,
3256 int capab, int cluster_type, const char *pattern, ...)
3257 {
3258 va_list args;
3259 char buffer[IRCD_BUFSIZE];
3260 const dlink_node *ptr = NULL;
3261
3262 va_start(args, pattern);
3263 vsnprintf(buffer, sizeof(buffer), pattern, args);
3264 va_end(args);
3265
3266 DLINK_FOREACH(ptr, cluster_items.head)
3267 {
3268 const struct ConfItem *conf = ptr->data;
3269
3270 if (conf->flags & cluster_type)
3271 sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3272 "%s %s %s", command, conf->name, buffer);
3273 }
3274 }
3275
3276 /*
3277 * split_nuh
3278 *
3279 * inputs - pointer to original mask (modified in place)
3280 * - pointer to pointer where nick should go
3281 * - pointer to pointer where user should go
3282 * - pointer to pointer where host should go
3283 * output - NONE
3284 * side effects - mask is modified in place
3285 * If nick pointer is NULL, ignore writing to it
3286 * this allows us to use this function elsewhere.
3287 *
3288 * mask nick user host
3289 * ---------------------- ------- ------- ------
3290 * Dianora!db@db.net Dianora db db.net
3291 * Dianora Dianora * *
3292 * db.net * * db.net
3293 * OR if nick pointer is NULL
3294 * Dianora - * Dianora
3295 * Dianora! Dianora * *
3296 * Dianora!@ Dianora * *
3297 * Dianora!db Dianora db *
3298 * Dianora!@db.net Dianora * db.net
3299 * db@db.net * db db.net
3300 * !@ * * *
3301 * @ * * *
3302 * ! * * *
3303 */
3304 void
3305 split_nuh(struct split_nuh_item *const iptr)
3306 {
3307 char *p = NULL, *q = NULL;
3308
3309 if (iptr->nickptr)
3310 strlcpy(iptr->nickptr, "*", iptr->nicksize);
3311 if (iptr->userptr)
3312 strlcpy(iptr->userptr, "*", iptr->usersize);
3313 if (iptr->hostptr)
3314 strlcpy(iptr->hostptr, "*", iptr->hostsize);
3315
3316 if ((p = strchr(iptr->nuhmask, '!')))
3317 {
3318 *p = '\0';
3319
3320 if (iptr->nickptr && *iptr->nuhmask != '\0')
3321 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3322
3323 if ((q = strchr(++p, '@'))) {
3324 *q++ = '\0';
3325
3326 if (*p != '\0')
3327 strlcpy(iptr->userptr, p, iptr->usersize);
3328
3329 if (*q != '\0')
3330 strlcpy(iptr->hostptr, q, iptr->hostsize);
3331 }
3332 else
3333 {
3334 if (*p != '\0')
3335 strlcpy(iptr->userptr, p, iptr->usersize);
3336 }
3337 }
3338 else
3339 {
3340 /* No ! found so lets look for a user@host */
3341 if ((p = strchr(iptr->nuhmask, '@')))
3342 {
3343 /* if found a @ */
3344 *p++ = '\0';
3345
3346 if (*iptr->nuhmask != '\0')
3347 strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
3348
3349 if (*p != '\0')
3350 strlcpy(iptr->hostptr, p, iptr->hostsize);
3351 }
3352 else
3353 {
3354 /* no @ found */
3355 if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
3356 strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
3357 else
3358 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3359 }
3360 }
3361 }
3362
3363 /*
3364 * flags_to_ascii
3365 *
3366 * inputs - flags is a bitmask
3367 * - pointer to table of ascii letters corresponding
3368 * to each bit
3369 * - flag 1 for convert ToLower if bit missing
3370 * 0 if ignore.
3371 * output - none
3372 * side effects - string pointed to by p has bitmap chars written to it
3373 */
3374 static void
3375 flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3376 int lowerit)
3377 {
3378 unsigned int mask = 1;
3379 int i = 0;
3380
3381 for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3382 {
3383 if (flags & mask)
3384 *p++ = bit_table[i];
3385 else if (lowerit)
3386 *p++ = ToLower(bit_table[i]);
3387 }
3388 *p = '\0';
3389 }
3390
3391 /*
3392 * cidr_limit_reached
3393 *
3394 * inputs - int flag allowing over_rule of limits
3395 * - pointer to the ip to be added
3396 * - pointer to the class
3397 * output - non zero if limit reached
3398 * 0 if limit not reached
3399 * side effects -
3400 */
3401 static int
3402 cidr_limit_reached(int over_rule,
3403 struct irc_ssaddr *ip, struct ClassItem *aclass)
3404 {
3405 dlink_node *ptr = NULL;
3406 struct CidrItem *cidr;
3407
3408 if (aclass->number_per_cidr <= 0)
3409 return 0;
3410
3411 if (ip->ss.ss_family == AF_INET)
3412 {
3413 if (aclass->cidr_bitlen_ipv4 <= 0)
3414 return 0;
3415
3416 DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3417 {
3418 cidr = ptr->data;
3419 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3420 {
3421 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3422 return -1;
3423 cidr->number_on_this_cidr++;
3424 return 0;
3425 }
3426 }
3427 cidr = MyMalloc(sizeof(struct CidrItem));
3428 cidr->number_on_this_cidr = 1;
3429 cidr->mask = *ip;
3430 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv4);
3431 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3432 }
3433 #ifdef IPV6
3434 else if (aclass->cidr_bitlen_ipv6 > 0)
3435 {
3436 DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3437 {
3438 cidr = ptr->data;
3439 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3440 {
3441 if (!over_rule && (cidr->number_on_this_cidr >= aclass->number_per_cidr))
3442 return -1;
3443 cidr->number_on_this_cidr++;
3444 return 0;
3445 }
3446 }
3447 cidr = MyMalloc(sizeof(struct CidrItem));
3448 cidr->number_on_this_cidr = 1;
3449 cidr->mask = *ip;
3450 mask_addr(&cidr->mask, aclass->cidr_bitlen_ipv6);
3451 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3452 }
3453 #endif
3454 return 0;
3455 }
3456
3457 /*
3458 * remove_from_cidr_check
3459 *
3460 * inputs - pointer to the ip to be removed
3461 * - pointer to the class
3462 * output - NONE
3463 * side effects -
3464 */
3465 static void
3466 remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3467 {
3468 dlink_node *ptr = NULL;
3469 dlink_node *next_ptr = NULL;
3470 struct CidrItem *cidr;
3471
3472 if (aclass->number_per_cidr == 0)
3473 return;
3474
3475 if (ip->ss.ss_family == AF_INET)
3476 {
3477 if (aclass->cidr_bitlen_ipv4 <= 0)
3478 return;
3479
3480 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3481 {
3482 cidr = ptr->data;
3483 if (match_ipv4(ip, &cidr->mask, aclass->cidr_bitlen_ipv4))
3484 {
3485 cidr->number_on_this_cidr--;
3486 if (cidr->number_on_this_cidr == 0)
3487 {
3488 dlinkDelete(ptr, &aclass->list_ipv4);
3489 MyFree(cidr);
3490 return;
3491 }
3492 }
3493 }
3494 }
3495 #ifdef IPV6
3496 else if (aclass->cidr_bitlen_ipv6 > 0)
3497 {
3498 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3499 {
3500 cidr = ptr->data;
3501 if (match_ipv6(ip, &cidr->mask, aclass->cidr_bitlen_ipv6))
3502 {
3503 cidr->number_on_this_cidr--;
3504 if (cidr->number_on_this_cidr == 0)
3505 {
3506 dlinkDelete(ptr, &aclass->list_ipv6);
3507 MyFree(cidr);
3508 return;
3509 }
3510 }
3511 }
3512 }
3513 #endif
3514 }
3515
3516 static void
3517 rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3518 dlink_list *old_list, dlink_list *new_list, int changed)
3519 {
3520 dlink_node *ptr;
3521 struct Client *client_p;
3522 struct ConfItem *conf;
3523 struct AccessItem *aconf;
3524
3525 if (!changed)
3526 {
3527 *new_list = *old_list;
3528 old_list->head = old_list->tail = NULL;
3529 old_list->length = 0;
3530 return;
3531 }
3532
3533 DLINK_FOREACH(ptr, local_client_list.head)
3534 {
3535 client_p = ptr->data;
3536 if (client_p->localClient->aftype != aftype)
3537 continue;
3538 if (dlink_list_length(&client_p->localClient->confs) == 0)
3539 continue;
3540
3541 conf = client_p->localClient->confs.tail->data;
3542 if (conf->type == CLIENT_TYPE)
3543 {
3544 aconf = map_to_conf(conf);
3545 if (aconf->class_ptr == oldcl)
3546 cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3547 }
3548 }
3549 }
3550
3551 /*
3552 * rebuild_cidr_class
3553 *
3554 * inputs - pointer to old conf
3555 * - pointer to new_class
3556 * output - none
3557 * side effects - rebuilds the class link list of cidr blocks
3558 */
3559 void
3560 rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3561 {
3562 struct ClassItem *old_class = map_to_conf(conf);
3563
3564 if (old_class->number_per_cidr > 0 && new_class->number_per_cidr > 0)
3565 {
3566 if (old_class->cidr_bitlen_ipv4 > 0 && new_class->cidr_bitlen_ipv4 > 0)
3567 rebuild_cidr_list(AF_INET, conf, new_class,
3568 &old_class->list_ipv4, &new_class->list_ipv4,
3569 old_class->cidr_bitlen_ipv4 != new_class->cidr_bitlen_ipv4);
3570
3571 #ifdef IPV6
3572 if (old_class->cidr_bitlen_ipv6 > 0 && new_class->cidr_bitlen_ipv6 > 0)
3573 rebuild_cidr_list(AF_INET6, conf, new_class,
3574 &old_class->list_ipv6, &new_class->list_ipv6,
3575 old_class->cidr_bitlen_ipv6 != new_class->cidr_bitlen_ipv6);
3576 #endif
3577 }
3578
3579 destroy_cidr_class(old_class);
3580 }
3581
3582 /*
3583 * destroy_cidr_list
3584 *
3585 * inputs - pointer to class dlink list of cidr blocks
3586 * output - none
3587 * side effects - completely destroys the class link list of cidr blocks
3588 */
3589 static void
3590 destroy_cidr_list(dlink_list *list)
3591 {
3592 dlink_node *ptr = NULL, *next_ptr = NULL;
3593
3594 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3595 {
3596 dlinkDelete(ptr, list);
3597 MyFree(ptr->data);
3598 }
3599 }
3600
3601 /*
3602 * destroy_cidr_class
3603 *
3604 * inputs - pointer to class
3605 * output - none
3606 * side effects - completely destroys the class link list of cidr blocks
3607 */
3608 static void
3609 destroy_cidr_class(struct ClassItem *aclass)
3610 {
3611 destroy_cidr_list(&aclass->list_ipv4);
3612 destroy_cidr_list(&aclass->list_ipv6);
3613 }

Properties

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