ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/conf.c
Revision: 891
Committed: Thu Nov 1 13:44:50 2007 UTC (17 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100603 byte(s)
Log Message:
- Avoid useless irc_getnameinfo calls in several places

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

Properties

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