ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1243
Committed: Fri Sep 30 10:47:53 2011 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_conf.c
File size: 100370 byte(s)
Log Message:
- move content of msg.h, ircd_handler.h and handlers.h into parse.h and
  remove headers accordingly
- killed common.h
- remove m_killhost.c and m_flags.c from contrib/
- sort out unused header includes here and there

File Contents

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

Properties

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