ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 956
Committed: Mon Jul 27 00:34:48 2009 UTC (16 years, 1 month ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100546 byte(s)
Log Message:
- removed LL leftover in set_default_conf(). now ServerInfo.hub
  properly initializes on /rehash

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 "channel.h"
32 #include "client.h"
33 #include "common.h"
34 #include "event.h"
35 #include "hash.h"
36 #include "hook.h"
37 #include "irc_string.h"
38 #include "sprintf_irc.h"
39 #include "s_bsd.h"
40 #include "irc_getaddrinfo.h"
41 #include "ircd.h"
42 #include "list.h"
43 #include "listener.h"
44 #include "hostmask.h"
45 #include "modules.h"
46 #include "numeric.h"
47 #include "fdlist.h"
48 #include "s_log.h"
49 #include "send.h"
50 #include "s_gline.h"
51 #include "fileio.h"
52 #include "memory.h"
53 #include "irc_res.h"
54 #include "userhost.h"
55 #include "s_user.h"
56 #include "channel_mode.h"
57
58 struct Callback *client_check_cb = NULL;
59 struct config_server_hide ConfigServerHide;
60
61 /* general conf items link list root, other than k lines etc. */
62 dlink_list server_items = { NULL, NULL, 0 };
63 dlink_list cluster_items = { NULL, NULL, 0 };
64 dlink_list hub_items = { NULL, NULL, 0 };
65 dlink_list leaf_items = { NULL, NULL, 0 };
66 dlink_list oconf_items = { NULL, NULL, 0 };
67 dlink_list uconf_items = { NULL, NULL, 0 };
68 dlink_list xconf_items = { NULL, NULL, 0 };
69 dlink_list rxconf_items = { NULL, NULL, 0 };
70 dlink_list rkconf_items = { NULL, NULL, 0 };
71 dlink_list nresv_items = { NULL, NULL, 0 };
72 dlink_list class_items = { NULL, NULL, 0 };
73 dlink_list gdeny_items = { NULL, NULL, 0 };
74
75 dlink_list temporary_klines = { NULL, NULL, 0 };
76 dlink_list temporary_dlines = { NULL, NULL, 0 };
77 dlink_list temporary_xlines = { NULL, NULL, 0 };
78 dlink_list temporary_rklines = { NULL, NULL, 0 };
79 dlink_list temporary_glines = { NULL, NULL, 0 };
80 dlink_list temporary_rxlines = { NULL, NULL, 0 };
81 dlink_list temporary_resv = { NULL, NULL, 0 };
82
83 extern unsigned int lineno;
84 extern char linebuf[];
85 extern char conffilebuf[IRCD_BUFSIZE];
86 extern char yytext[];
87 extern int yyparse(); /* defined in y.tab.c */
88 int ypass = 1; /* used by yyparse() */
89
90 /* internally defined functions */
91 static void lookup_confhost(struct ConfItem *);
92 static void set_default_conf(void);
93 static void validate_conf(void);
94 static void read_conf(FBFILE *);
95 static void clear_out_old_conf(void);
96 static void flush_deleted_I_P(void);
97 static void expire_tklines(dlink_list *);
98 static void garbage_collect_ip_entries(void);
99 static int hash_ip(struct irc_ssaddr *);
100 static int verify_access(struct Client *, const char *);
101 static int attach_iline(struct Client *, struct ConfItem *);
102 static struct ip_entry *find_or_add_ip(struct irc_ssaddr *);
103 static void parse_conf_file(int, int);
104 static dlink_list *map_to_list(ConfType);
105 static struct AccessItem *find_regexp_kline(const char *[]);
106 static int find_user_host(struct Client *, char *, char *, char *, unsigned int);
107
108 /*
109 * bit_len
110 */
111 static int cidr_limit_reached(int, struct irc_ssaddr *, struct ClassItem *);
112 static void remove_from_cidr_check(struct irc_ssaddr *, struct ClassItem *);
113 static void destroy_cidr_class(struct ClassItem *);
114
115 static void flags_to_ascii(unsigned int, const unsigned int[], char *, int);
116
117 FBFILE *conf_fbfile_in = NULL;
118
119 /* address of default class conf */
120 static struct ConfItem *class_default;
121
122 /* usually, with hash tables, you use a prime number...
123 * but in this case I am dealing with ip addresses,
124 * not ascii strings.
125 */
126 #define IP_HASH_SIZE 0x1000
127
128 struct ip_entry
129 {
130 struct irc_ssaddr ip;
131 int count;
132 time_t last_attempt;
133 struct ip_entry *next;
134 };
135
136 static struct ip_entry *ip_hash_table[IP_HASH_SIZE];
137 static BlockHeap *ip_entry_heap = NULL;
138 static int ip_entries_count = 0;
139
140
141 inline void *
142 map_to_conf(struct ConfItem *aconf)
143 {
144 void *conf;
145 conf = (void *)((unsigned long)aconf +
146 (unsigned long)sizeof(struct ConfItem));
147 return(conf);
148 }
149
150 inline struct ConfItem *
151 unmap_conf_item(void *aconf)
152 {
153 struct ConfItem *conf;
154
155 conf = (struct ConfItem *)((unsigned long)aconf -
156 (unsigned long)sizeof(struct ConfItem));
157 return(conf);
158 }
159
160 /* conf_dns_callback()
161 *
162 * inputs - pointer to struct AccessItem
163 * - pointer to DNSReply reply
164 * output - none
165 * side effects - called when resolver query finishes
166 * if the query resulted in a successful search, hp will contain
167 * a non-null pointer, otherwise hp will be null.
168 * if successful save hp in the conf item it was called with
169 */
170 static void
171 conf_dns_callback(void *vptr, struct DNSReply *reply)
172 {
173 struct AccessItem *aconf = (struct AccessItem *)vptr;
174 struct ConfItem *conf;
175
176 MyFree(aconf->dns_query);
177 aconf->dns_query = NULL;
178
179 if (reply != NULL)
180 memcpy(&aconf->ipnum, &reply->addr, sizeof(reply->addr));
181 else {
182 ilog(L_NOTICE, "Host not found: %s, ignoring connect{} block",
183 aconf->host);
184 conf = unmap_conf_item(aconf);
185 sendto_realops_flags(UMODE_ALL, L_ALL,
186 "Ignoring connect{} block for %s - host not found",
187 conf->name);
188 delete_conf_item(conf);
189 }
190 }
191
192 /* conf_dns_lookup()
193 *
194 * do a nameserver lookup of the conf host
195 * if the conf entry is currently doing a ns lookup do nothing, otherwise
196 * allocate a dns_query and start ns lookup.
197 */
198 static void
199 conf_dns_lookup(struct AccessItem *aconf)
200 {
201 if (aconf->dns_query == NULL)
202 {
203 aconf->dns_query = MyMalloc(sizeof(struct DNSQuery));
204 aconf->dns_query->ptr = aconf;
205 aconf->dns_query->callback = conf_dns_callback;
206 gethost_byname(aconf->host, aconf->dns_query);
207 }
208 }
209
210 /* make_conf_item()
211 *
212 * inputs - type of item
213 * output - pointer to new conf entry
214 * side effects - none
215 */
216 struct ConfItem *
217 make_conf_item(ConfType type)
218 {
219 struct ConfItem *conf = NULL;
220 struct AccessItem *aconf = NULL;
221 struct ClassItem *aclass = NULL;
222 int status = 0;
223
224 switch (type)
225 {
226 case DLINE_TYPE:
227 case EXEMPTDLINE_TYPE:
228 case GLINE_TYPE:
229 case KLINE_TYPE:
230 case CLIENT_TYPE:
231 case OPER_TYPE:
232 case SERVER_TYPE:
233 conf = MyMalloc(sizeof(struct ConfItem) +
234 sizeof(struct AccessItem));
235 aconf = map_to_conf(conf);
236 aconf->aftype = AF_INET;
237
238 /* Yes, sigh. switch on type again */
239 switch (type)
240 {
241 case EXEMPTDLINE_TYPE:
242 status = CONF_EXEMPTDLINE;
243 break;
244
245 case DLINE_TYPE:
246 status = CONF_DLINE;
247 break;
248
249 case KLINE_TYPE:
250 status = CONF_KLINE;
251 break;
252
253 case GLINE_TYPE:
254 status = CONF_GLINE;
255 break;
256
257 case CLIENT_TYPE:
258 status = CONF_CLIENT;
259 break;
260
261 case OPER_TYPE:
262 status = CONF_OPERATOR;
263 dlinkAdd(conf, &conf->node, &oconf_items);
264 break;
265
266 case SERVER_TYPE:
267 status = CONF_SERVER;
268 dlinkAdd(conf, &conf->node, &server_items);
269 break;
270
271 default:
272 break;
273 }
274 aconf->status = status;
275 break;
276
277 case LEAF_TYPE:
278 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
279 sizeof(struct MatchItem));
280 dlinkAdd(conf, &conf->node, &leaf_items);
281 break;
282
283 case HUB_TYPE:
284 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
285 sizeof(struct MatchItem));
286 dlinkAdd(conf, &conf->node, &hub_items);
287 break;
288
289 case ULINE_TYPE:
290 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
291 sizeof(struct MatchItem));
292 dlinkAdd(conf, &conf->node, &uconf_items);
293 break;
294
295 case GDENY_TYPE:
296 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
297 sizeof(struct AccessItem));
298 dlinkAdd(conf, &conf->node, &gdeny_items);
299 break;
300
301 case XLINE_TYPE:
302 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
303 sizeof(struct MatchItem));
304 dlinkAdd(conf, &conf->node, &xconf_items);
305 break;
306
307 case RXLINE_TYPE:
308 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
309 sizeof(struct MatchItem));
310 dlinkAdd(conf, &conf->node, &rxconf_items);
311 break;
312
313 case RKLINE_TYPE:
314 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
315 sizeof(struct AccessItem));
316 aconf = map_to_conf(conf);
317 aconf->status = CONF_KLINE;
318 dlinkAdd(conf, &conf->node, &rkconf_items);
319 break;
320
321 case CLUSTER_TYPE:
322 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem));
323 dlinkAdd(conf, &conf->node, &cluster_items);
324 break;
325
326 case CRESV_TYPE:
327 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
328 sizeof(struct ResvChannel));
329 break;
330
331 case NRESV_TYPE:
332 conf = (struct ConfItem *)MyMalloc(sizeof(struct ConfItem) +
333 sizeof(struct MatchItem));
334 dlinkAdd(conf, &conf->node, &nresv_items);
335 break;
336
337 case CLASS_TYPE:
338 conf = MyMalloc(sizeof(struct ConfItem) +
339 sizeof(struct ClassItem));
340 dlinkAdd(conf, &conf->node, &class_items);
341
342 aclass = map_to_conf(conf);
343 aclass->active = 1;
344 ConFreq(aclass) = DEFAULT_CONNECTFREQUENCY;
345 PingFreq(aclass) = DEFAULT_PINGFREQUENCY;
346 MaxTotal(aclass) = MAXIMUM_LINKS_DEFAULT;
347 MaxSendq(aclass) = DEFAULT_SENDQ;
348
349 break;
350
351 default:
352 conf = NULL;
353 break;
354 }
355
356 /* XXX Yes, this will core if default is hit. I want it to for now - db */
357 conf->type = type;
358
359 return conf;
360 }
361
362 void
363 delete_conf_item(struct ConfItem *conf)
364 {
365 dlink_node *m = NULL;
366 struct MatchItem *match_item;
367 struct AccessItem *aconf;
368 ConfType type = conf->type;
369
370 MyFree(conf->name);
371 conf->name = NULL;
372
373 switch(type)
374 {
375 case DLINE_TYPE:
376 case EXEMPTDLINE_TYPE:
377 case GLINE_TYPE:
378 case KLINE_TYPE:
379 case CLIENT_TYPE:
380 case OPER_TYPE:
381 case SERVER_TYPE:
382 aconf = map_to_conf(conf);
383
384 if (aconf->dns_query != NULL)
385 {
386 delete_resolver_queries(aconf->dns_query);
387 MyFree(aconf->dns_query);
388 }
389 if (aconf->passwd != NULL)
390 memset(aconf->passwd, 0, strlen(aconf->passwd));
391 if (aconf->spasswd != NULL)
392 memset(aconf->spasswd, 0, strlen(aconf->spasswd));
393 aconf->class_ptr = NULL;
394
395 MyFree(aconf->passwd);
396 MyFree(aconf->spasswd);
397 MyFree(aconf->reason);
398 MyFree(aconf->oper_reason);
399 MyFree(aconf->user);
400 MyFree(aconf->host);
401 MyFree(aconf->fakename);
402 #ifdef HAVE_LIBCRYPTO
403 if (aconf->rsa_public_key)
404 RSA_free(aconf->rsa_public_key);
405 MyFree(aconf->rsa_public_key_file);
406 #endif
407
408 /* Yes, sigh. switch on type again */
409 switch(type)
410 {
411 case EXEMPTDLINE_TYPE:
412 case DLINE_TYPE:
413 case GLINE_TYPE:
414 case KLINE_TYPE:
415 case CLIENT_TYPE:
416 MyFree(conf);
417 break;
418
419 case OPER_TYPE:
420 aconf = map_to_conf(conf);
421 if (!IsConfIllegal(aconf))
422 dlinkDelete(&conf->node, &oconf_items);
423 MyFree(conf);
424 break;
425
426 case SERVER_TYPE:
427 aconf = map_to_conf(conf);
428 if (!IsConfIllegal(aconf))
429 dlinkDelete(&conf->node, &server_items);
430 MyFree(conf);
431 break;
432
433 default:
434 break;
435 }
436 break;
437
438 case HUB_TYPE:
439 match_item = map_to_conf(conf);
440 MyFree(match_item->user);
441 MyFree(match_item->host);
442 MyFree(match_item->reason);
443 MyFree(match_item->oper_reason);
444 /* If marked illegal, its already been pulled off of the hub_items list */
445 if (!match_item->illegal)
446 dlinkDelete(&conf->node, &hub_items);
447 MyFree(conf);
448 break;
449
450 case LEAF_TYPE:
451 match_item = map_to_conf(conf);
452 MyFree(match_item->user);
453 MyFree(match_item->host);
454 MyFree(match_item->reason);
455 MyFree(match_item->oper_reason);
456 /* If marked illegal, its already been pulled off of the leaf_items list */
457 if (!match_item->illegal)
458 dlinkDelete(&conf->node, &leaf_items);
459 MyFree(conf);
460 break;
461
462 case ULINE_TYPE:
463 match_item = map_to_conf(conf);
464 MyFree(match_item->user);
465 MyFree(match_item->host);
466 MyFree(match_item->reason);
467 MyFree(match_item->oper_reason);
468 dlinkDelete(&conf->node, &uconf_items);
469 MyFree(conf);
470 break;
471
472 case XLINE_TYPE:
473 match_item = map_to_conf(conf);
474 MyFree(match_item->user);
475 MyFree(match_item->host);
476 MyFree(match_item->reason);
477 MyFree(match_item->oper_reason);
478 dlinkDelete(&conf->node, &xconf_items);
479 MyFree(conf);
480 break;
481
482 case RKLINE_TYPE:
483 aconf = map_to_conf(conf);
484 MyFree(aconf->regexuser);
485 MyFree(aconf->regexhost);
486 MyFree(aconf->user);
487 MyFree(aconf->host);
488 MyFree(aconf->reason);
489 MyFree(aconf->oper_reason);
490 dlinkDelete(&conf->node, &rkconf_items);
491 MyFree(conf);
492 break;
493
494 case RXLINE_TYPE:
495 MyFree(conf->regexpname);
496 match_item = map_to_conf(conf);
497 MyFree(match_item->user);
498 MyFree(match_item->host);
499 MyFree(match_item->reason);
500 MyFree(match_item->oper_reason);
501 dlinkDelete(&conf->node, &rxconf_items);
502 MyFree(conf);
503 break;
504
505 case NRESV_TYPE:
506 match_item = map_to_conf(conf);
507 MyFree(match_item->user);
508 MyFree(match_item->host);
509 MyFree(match_item->reason);
510 MyFree(match_item->oper_reason);
511 dlinkDelete(&conf->node, &nresv_items);
512
513 if (conf->flags & CONF_FLAGS_TEMPORARY)
514 if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
515 free_dlink_node(m);
516
517 MyFree(conf);
518 break;
519
520 case GDENY_TYPE:
521 aconf = map_to_conf(conf);
522 MyFree(aconf->user);
523 MyFree(aconf->host);
524 dlinkDelete(&conf->node, &gdeny_items);
525 MyFree(conf);
526 break;
527
528 case CLUSTER_TYPE:
529 dlinkDelete(&conf->node, &cluster_items);
530 MyFree(conf);
531 break;
532
533 case CRESV_TYPE:
534 if (conf->flags & CONF_FLAGS_TEMPORARY)
535 if ((m = dlinkFindDelete(&temporary_resv, conf)) != NULL)
536 free_dlink_node(m);
537
538 MyFree(conf);
539 break;
540
541 case CLASS_TYPE:
542 dlinkDelete(&conf->node, &class_items);
543 MyFree(conf);
544 break;
545
546 default:
547 break;
548 }
549 }
550
551 /* free_access_item()
552 *
553 * inputs - pointer to conf to free
554 * output - none
555 * side effects - crucial password fields are zeroed, conf is freed
556 */
557 void
558 free_access_item(struct AccessItem *aconf)
559 {
560 struct ConfItem *conf;
561
562 if (aconf == NULL)
563 return;
564 conf = unmap_conf_item(aconf);
565 delete_conf_item(conf);
566 }
567
568 static const unsigned int shared_bit_table[] =
569 { 'K', 'k', 'U', 'X', 'x', 'Y', 'Q', 'q', 'R', 'L', 0};
570
571 /* report_confitem_types()
572 *
573 * inputs - pointer to client requesting confitem report
574 * - ConfType to report
575 * output - none
576 * side effects -
577 */
578 void
579 report_confitem_types(struct Client *source_p, ConfType type, int temp)
580 {
581 dlink_node *ptr = NULL;
582 struct ConfItem *conf = NULL;
583 struct AccessItem *aconf = NULL;
584 struct MatchItem *matchitem = NULL;
585 struct ClassItem *classitem = NULL;
586 char buf[12];
587 char *p = NULL;
588 const char *pfx = NULL;
589
590 switch (type)
591 {
592 case GDENY_TYPE:
593 DLINK_FOREACH(ptr, gdeny_items.head)
594 {
595 conf = ptr->data;
596 aconf = map_to_conf(conf);
597
598 p = buf;
599
600 if (aconf->flags & GDENY_BLOCK)
601 *p++ = 'B';
602 else
603 *p++ = 'b';
604
605 if (aconf->flags & GDENY_REJECT)
606 *p++ = 'R';
607 else
608 *p++ = 'r';
609
610 *p = '\0';
611
612 sendto_one(source_p, ":%s %d %s V %s@%s %s %s",
613 me.name, RPL_STATSDEBUG, source_p->name,
614 aconf->user, aconf->host, conf->name, buf);
615 }
616 break;
617
618 case XLINE_TYPE:
619 DLINK_FOREACH(ptr, xconf_items.head)
620 {
621 conf = ptr->data;
622 matchitem = map_to_conf(conf);
623
624 sendto_one(source_p, form_str(RPL_STATSXLINE),
625 me.name, source_p->name,
626 matchitem->hold ? "x": "X", matchitem->count,
627 conf->name, matchitem->reason);
628 }
629 break;
630
631 case RXLINE_TYPE:
632 DLINK_FOREACH(ptr, rxconf_items.head)
633 {
634 conf = ptr->data;
635 matchitem = map_to_conf(conf);
636
637 sendto_one(source_p, form_str(RPL_STATSXLINE),
638 me.name, source_p->name,
639 matchitem->hold ? "xR": "XR", matchitem->count,
640 conf->name, matchitem->reason);
641 }
642 break;
643
644 case RKLINE_TYPE:
645 pfx = temp ? "kR" : "KR";
646
647 DLINK_FOREACH(ptr, rkconf_items.head)
648 {
649 aconf = map_to_conf((conf = ptr->data));
650
651 if (temp && !(conf->flags & CONF_FLAGS_TEMPORARY))
652 continue;
653
654 sendto_one(source_p, form_str(RPL_STATSKLINE), me.name,
655 source_p->name, pfx, aconf->host, aconf->user,
656 aconf->reason, aconf->oper_reason ? aconf->oper_reason : "");
657 }
658 break;
659
660 case ULINE_TYPE:
661 DLINK_FOREACH(ptr, uconf_items.head)
662 {
663 conf = ptr->data;
664 matchitem = map_to_conf(conf);
665
666 p = buf;
667
668 /* some of these are redundant for the sake of
669 * consistency with cluster{} flags
670 */
671 *p++ = 'c';
672 flags_to_ascii(matchitem->action, shared_bit_table, p, 0);
673
674 sendto_one(source_p, form_str(RPL_STATSULINE),
675 me.name, source_p->name, conf->name,
676 matchitem->user?matchitem->user: "*",
677 matchitem->host?matchitem->host: "*", buf);
678 }
679
680 DLINK_FOREACH(ptr, cluster_items.head)
681 {
682 conf = ptr->data;
683
684 p = buf;
685
686 *p++ = 'C';
687 flags_to_ascii(conf->flags, shared_bit_table, p, 0);
688
689 sendto_one(source_p, form_str(RPL_STATSULINE),
690 me.name, source_p->name, conf->name,
691 "*", "*", buf);
692 }
693
694 break;
695
696 case OPER_TYPE:
697 DLINK_FOREACH(ptr, oconf_items.head)
698 {
699 conf = ptr->data;
700 aconf = map_to_conf(conf);
701
702 /* Don't allow non opers to see oper privs */
703 if (IsOper(source_p))
704 sendto_one(source_p, form_str(RPL_STATSOLINE),
705 me.name, source_p->name, 'O', aconf->user, aconf->host,
706 conf->name, oper_privs_as_string(aconf->port),
707 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
708 else
709 sendto_one(source_p, form_str(RPL_STATSOLINE),
710 me.name, source_p->name, 'O', aconf->user, aconf->host,
711 conf->name, "0",
712 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
713 }
714 break;
715
716 case CLASS_TYPE:
717 DLINK_FOREACH(ptr, class_items.head)
718 {
719 conf = ptr->data;
720 classitem = map_to_conf(conf);
721 sendto_one(source_p, form_str(RPL_STATSYLINE),
722 me.name, source_p->name, 'Y',
723 conf->name, PingFreq(classitem),
724 ConFreq(classitem),
725 MaxTotal(classitem), MaxSendq(classitem),
726 CurrUserCount(classitem),
727 classitem->active ? "active" : "disabled");
728 }
729 break;
730
731 case CONF_TYPE:
732 case CLIENT_TYPE:
733 break;
734
735 case SERVER_TYPE:
736 DLINK_FOREACH(ptr, server_items.head)
737 {
738 p = buf;
739
740 conf = ptr->data;
741 aconf = map_to_conf(conf);
742
743 buf[0] = '\0';
744
745 if (IsConfAllowAutoConn(aconf))
746 *p++ = 'A';
747 if (IsConfCryptLink(aconf))
748 *p++ = 'C';
749 if (aconf->fakename)
750 *p++ = 'M';
751 if (IsConfTopicBurst(aconf))
752 *p++ = 'T';
753 if (IsConfCompressed(aconf))
754 *p++ = 'Z';
755 if (buf[0] == '\0')
756 *p++ = '*';
757
758 *p = '\0';
759
760 /*
761 * Allow admins to see actual ips unless hide_server_ips is enabled
762 */
763 if (!ConfigServerHide.hide_server_ips && IsAdmin(source_p))
764 sendto_one(source_p, form_str(RPL_STATSCLINE),
765 me.name, source_p->name, 'C', aconf->host,
766 buf, conf->name, aconf->port,
767 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
768 else
769 sendto_one(source_p, form_str(RPL_STATSCLINE),
770 me.name, source_p->name, 'C',
771 "*@127.0.0.1", buf, conf->name, aconf->port,
772 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
773 }
774 break;
775
776 case HUB_TYPE:
777 DLINK_FOREACH(ptr, hub_items.head)
778 {
779 conf = ptr->data;
780 matchitem = map_to_conf(conf);
781 sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
782 source_p->name, 'H', matchitem->host, conf->name, 0, "*");
783 }
784 break;
785
786 case LEAF_TYPE:
787 DLINK_FOREACH(ptr, leaf_items.head)
788 {
789 conf = ptr->data;
790 matchitem = map_to_conf(conf);
791 sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
792 source_p->name, 'L', matchitem->host, conf->name, 0, "*");
793 }
794 break;
795
796 case GLINE_TYPE:
797 case KLINE_TYPE:
798 case DLINE_TYPE:
799 case EXEMPTDLINE_TYPE:
800 case CRESV_TYPE:
801 case NRESV_TYPE:
802 case CLUSTER_TYPE:
803 break;
804 }
805 }
806
807 /* check_client()
808 *
809 * inputs - pointer to client
810 * output - 0 = Success
811 * NOT_AUTHORIZED (-1) = Access denied (no I line match)
812 * IRCD_SOCKET_ERROR (-2) = Bad socket.
813 * I_LINE_FULL (-3) = I-line is full
814 * TOO_MANY (-4) = Too many connections from hostname
815 * BANNED_CLIENT (-5) = K-lined
816 * side effects - Ordinary client access check.
817 * Look for conf lines which have the same
818 * status as the flags passed.
819 */
820 static void *
821 check_client(va_list args)
822 {
823 struct Client *source_p = va_arg(args, struct Client *);
824 const char *username = va_arg(args, const char *);
825 int i;
826
827 /* I'm already in big trouble if source_p->localClient is NULL -db */
828 if ((i = verify_access(source_p, username)))
829 ilog(L_INFO, "Access denied: %s[%s]",
830 source_p->name, source_p->sockhost);
831
832 switch (i)
833 {
834 case TOO_MANY:
835 sendto_realops_flags(UMODE_FULL, L_ALL,
836 "Too many on IP for %s (%s).",
837 get_client_name(source_p, SHOW_IP),
838 source_p->sockhost);
839 ilog(L_INFO,"Too many connections on IP from %s.",
840 get_client_name(source_p, SHOW_IP));
841 ++ServerStats.is_ref;
842 exit_client(source_p, &me, "No more connections allowed on that IP");
843 break;
844
845 case I_LINE_FULL:
846 sendto_realops_flags(UMODE_FULL, L_ALL,
847 "I-line is full for %s (%s).",
848 get_client_name(source_p, SHOW_IP),
849 source_p->sockhost);
850 ilog(L_INFO,"Too many connections from %s.",
851 get_client_name(source_p, SHOW_IP));
852 ++ServerStats.is_ref;
853 exit_client(source_p, &me,
854 "No more connections allowed in your connection class");
855 break;
856
857 case NOT_AUTHORIZED:
858 ++ServerStats.is_ref;
859 /* jdc - lists server name & port connections are on */
860 /* a purely cosmetical change */
861 sendto_realops_flags(UMODE_UNAUTH, L_ALL,
862 "Unauthorized client connection from %s [%s] on [%s/%u].",
863 get_client_name(source_p, SHOW_IP),
864 source_p->sockhost,
865 source_p->localClient->listener->name,
866 source_p->localClient->listener->port);
867 ilog(L_INFO,
868 "Unauthorized client connection from %s on [%s/%u].",
869 get_client_name(source_p, SHOW_IP),
870 source_p->localClient->listener->name,
871 source_p->localClient->listener->port);
872
873 /* XXX It is prolematical whether it is better to use the
874 * capture reject code here or rely on the connecting too fast code.
875 * - Dianora
876 */
877 if (REJECT_HOLD_TIME > 0)
878 {
879 sendto_one(source_p, ":%s NOTICE %s :You are not authorized to use this server",
880 me.name, source_p->name);
881 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
882 SetCaptured(source_p);
883 }
884 else
885 exit_client(source_p, &me, "You are not authorized to use this server");
886 break;
887
888 case BANNED_CLIENT:
889 /*
890 * Don't exit them immediately, play with them a bit.
891 * - Dianora
892 */
893 if (REJECT_HOLD_TIME > 0)
894 {
895 source_p->localClient->reject_delay = CurrentTime + REJECT_HOLD_TIME;
896 SetCaptured(source_p);
897 }
898 else
899 exit_client(source_p, &me, "Banned");
900 ++ServerStats.is_ref;
901 break;
902
903 case 0:
904 default:
905 break;
906 }
907
908 return (i < 0 ? NULL : source_p);
909 }
910
911 /* verify_access()
912 *
913 * inputs - pointer to client to verify
914 * - pointer to proposed username
915 * output - 0 if success -'ve if not
916 * side effect - find the first (best) I line to attach.
917 */
918 static int
919 verify_access(struct Client *client_p, const char *username)
920 {
921 struct AccessItem *aconf = NULL, *rkconf = NULL;
922 struct ConfItem *conf = NULL;
923 char non_ident[USERLEN + 1] = { '~', '\0' };
924 const char *uhi[3];
925
926 if (IsGotId(client_p))
927 {
928 aconf = find_address_conf(client_p->host, client_p->username,
929 &client_p->localClient->ip,
930 client_p->localClient->aftype,
931 client_p->localClient->passwd);
932 }
933 else
934 {
935 strlcpy(non_ident+1, username, sizeof(non_ident)-1);
936 aconf = find_address_conf(client_p->host,non_ident,
937 &client_p->localClient->ip,
938 client_p->localClient->aftype,
939 client_p->localClient->passwd);
940 }
941
942 uhi[0] = IsGotId(client_p) ? client_p->username : non_ident;
943 uhi[1] = client_p->host;
944 uhi[2] = client_p->sockhost;
945
946 rkconf = find_regexp_kline(uhi);
947
948 if (aconf != NULL)
949 {
950 if (IsConfClient(aconf) && !rkconf)
951 {
952 conf = unmap_conf_item(aconf);
953
954 if (IsConfRedir(aconf))
955 {
956 sendto_one(client_p, form_str(RPL_REDIR),
957 me.name, client_p->name,
958 conf->name ? conf->name : "",
959 aconf->port);
960 return(NOT_AUTHORIZED);
961 }
962
963 if (IsConfDoIdentd(aconf))
964 SetNeedId(client_p);
965
966 /* Thanks for spoof idea amm */
967 if (IsConfDoSpoofIp(aconf))
968 {
969 conf = unmap_conf_item(aconf);
970
971 if (!ConfigFileEntry.hide_spoof_ips && IsConfSpoofNotice(aconf))
972 sendto_realops_flags(UMODE_ALL, L_ADMIN, "%s spoofing: %s as %s",
973 client_p->name, client_p->host, conf->name);
974 strlcpy(client_p->host, conf->name, sizeof(client_p->host));
975 SetIPSpoof(client_p);
976 }
977
978 return(attach_iline(client_p, conf));
979 }
980 else if (rkconf || IsConfKill(aconf) || (ConfigFileEntry.glines && IsConfGline(aconf)))
981 {
982 /* XXX */
983 aconf = rkconf ? rkconf : aconf;
984 if (IsConfGline(aconf))
985 sendto_one(client_p, ":%s NOTICE %s :*** G-lined", me.name,
986 client_p->name);
987 if (ConfigFileEntry.kline_with_reason)
988 sendto_one(client_p, ":%s NOTICE %s :*** Banned %s",
989 me.name, client_p->name, aconf->reason);
990 return(BANNED_CLIENT);
991 }
992 }
993
994 return(NOT_AUTHORIZED);
995 }
996
997 /* attach_iline()
998 *
999 * inputs - client pointer
1000 * - conf pointer
1001 * output -
1002 * side effects - do actual attach
1003 */
1004 static int
1005 attach_iline(struct Client *client_p, struct ConfItem *conf)
1006 {
1007 struct AccessItem *aconf;
1008 struct ClassItem *aclass;
1009 struct ip_entry *ip_found;
1010 int a_limit_reached = 0;
1011 int local = 0, global = 0, ident = 0;
1012
1013 ip_found = find_or_add_ip(&client_p->localClient->ip);
1014 ip_found->count++;
1015 SetIpHash(client_p);
1016
1017 aconf = map_to_conf(conf);
1018 if (aconf->class_ptr == NULL)
1019 return NOT_AUTHORIZED; /* If class is missing, this is best */
1020
1021 aclass = map_to_conf(aconf->class_ptr);
1022
1023 count_user_host(client_p->username, client_p->host,
1024 &global, &local, &ident);
1025
1026 /* XXX blah. go down checking the various silly limits
1027 * setting a_limit_reached if any limit is reached.
1028 * - Dianora
1029 */
1030 if (MaxTotal(aclass) != 0 && CurrUserCount(aclass) >= MaxTotal(aclass))
1031 a_limit_reached = 1;
1032 else if (MaxPerIp(aclass) != 0 && ip_found->count > MaxPerIp(aclass))
1033 a_limit_reached = 1;
1034 else if (MaxLocal(aclass) != 0 && local >= MaxLocal(aclass))
1035 a_limit_reached = 1;
1036 else if (MaxGlobal(aclass) != 0 && global >= MaxGlobal(aclass))
1037 a_limit_reached = 1;
1038 else if (MaxIdent(aclass) != 0 && ident >= MaxIdent(aclass) &&
1039 client_p->username[0] != '~')
1040 a_limit_reached = 1;
1041
1042 if (a_limit_reached)
1043 {
1044 if (!IsConfExemptLimits(aconf))
1045 return TOO_MANY; /* Already at maximum allowed */
1046
1047 sendto_one(client_p,
1048 ":%s NOTICE %s :*** Your connection class is full, "
1049 "but you have exceed_limit = yes;", me.name, client_p->name);
1050 }
1051
1052 return attach_conf(client_p, conf);
1053 }
1054
1055 /* init_ip_hash_table()
1056 *
1057 * inputs - NONE
1058 * output - NONE
1059 * side effects - allocate memory for ip_entry(s)
1060 * - clear the ip hash table
1061 */
1062 void
1063 init_ip_hash_table(void)
1064 {
1065 ip_entry_heap = BlockHeapCreate("ip", sizeof(struct ip_entry),
1066 2 * hard_fdlimit);
1067 memset(ip_hash_table, 0, sizeof(ip_hash_table));
1068 }
1069
1070 /* find_or_add_ip()
1071 *
1072 * inputs - pointer to struct irc_ssaddr
1073 * output - pointer to a struct ip_entry
1074 * side effects -
1075 *
1076 * If the ip # was not found, a new struct ip_entry is created, and the ip
1077 * count set to 0.
1078 */
1079 static struct ip_entry *
1080 find_or_add_ip(struct irc_ssaddr *ip_in)
1081 {
1082 struct ip_entry *ptr, *newptr;
1083 int hash_index = hash_ip(ip_in), res;
1084 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
1085 #ifdef IPV6
1086 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
1087 #endif
1088
1089 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
1090 {
1091 #ifdef IPV6
1092 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1093 continue;
1094 if (ip_in->ss.ss_family == AF_INET6)
1095 {
1096 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1097 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1098 }
1099 else
1100 #endif
1101 {
1102 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1103 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1104 }
1105 if (res == 0)
1106 {
1107 /* Found entry already in hash, return it. */
1108 return ptr;
1109 }
1110 }
1111
1112 if (ip_entries_count >= 2 * hard_fdlimit)
1113 garbage_collect_ip_entries();
1114
1115 newptr = BlockHeapAlloc(ip_entry_heap);
1116 ip_entries_count++;
1117 memcpy(&newptr->ip, ip_in, sizeof(struct irc_ssaddr));
1118
1119 newptr->next = ip_hash_table[hash_index];
1120 ip_hash_table[hash_index] = newptr;
1121
1122 return newptr;
1123 }
1124
1125 /* remove_one_ip()
1126 *
1127 * inputs - unsigned long IP address value
1128 * output - NONE
1129 * side effects - The ip address given, is looked up in ip hash table
1130 * and number of ip#'s for that ip decremented.
1131 * If ip # count reaches 0 and has expired,
1132 * the struct ip_entry is returned to the ip_entry_heap
1133 */
1134 void
1135 remove_one_ip(struct irc_ssaddr *ip_in)
1136 {
1137 struct ip_entry *ptr;
1138 struct ip_entry *last_ptr = NULL;
1139 int hash_index = hash_ip(ip_in), res;
1140 struct sockaddr_in *v4 = (struct sockaddr_in *)ip_in, *ptr_v4;
1141 #ifdef IPV6
1142 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)ip_in, *ptr_v6;
1143 #endif
1144
1145 for (ptr = ip_hash_table[hash_index]; ptr; ptr = ptr->next)
1146 {
1147 #ifdef IPV6
1148 if (ptr->ip.ss.ss_family != ip_in->ss.ss_family)
1149 continue;
1150 if (ip_in->ss.ss_family == AF_INET6)
1151 {
1152 ptr_v6 = (struct sockaddr_in6 *)&ptr->ip;
1153 res = memcmp(&v6->sin6_addr, &ptr_v6->sin6_addr, sizeof(struct in6_addr));
1154 }
1155 else
1156 #endif
1157 {
1158 ptr_v4 = (struct sockaddr_in *)&ptr->ip;
1159 res = memcmp(&v4->sin_addr, &ptr_v4->sin_addr, sizeof(struct in_addr));
1160 }
1161 if (res)
1162 continue;
1163 if (ptr->count > 0)
1164 ptr->count--;
1165 if (ptr->count == 0 &&
1166 (CurrentTime-ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1167 {
1168 if (last_ptr != NULL)
1169 last_ptr->next = ptr->next;
1170 else
1171 ip_hash_table[hash_index] = ptr->next;
1172
1173 BlockHeapFree(ip_entry_heap, ptr);
1174 ip_entries_count--;
1175 return;
1176 }
1177 last_ptr = ptr;
1178 }
1179 }
1180
1181 /* hash_ip()
1182 *
1183 * input - pointer to an irc_inaddr
1184 * output - integer value used as index into hash table
1185 * side effects - hopefully, none
1186 */
1187 static int
1188 hash_ip(struct irc_ssaddr *addr)
1189 {
1190 if (addr->ss.ss_family == AF_INET)
1191 {
1192 struct sockaddr_in *v4 = (struct sockaddr_in *)addr;
1193 int hash;
1194 u_int32_t ip;
1195
1196 ip = ntohl(v4->sin_addr.s_addr);
1197 hash = ((ip >> 12) + ip) & (IP_HASH_SIZE-1);
1198 return hash;
1199 }
1200 #ifdef IPV6
1201 else
1202 {
1203 int hash;
1204 struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)addr;
1205 u_int32_t *ip = (u_int32_t *)&v6->sin6_addr.s6_addr;
1206
1207 hash = ip[0] ^ ip[3];
1208 hash ^= hash >> 16;
1209 hash ^= hash >> 8;
1210 hash = hash & (IP_HASH_SIZE - 1);
1211 return hash;
1212 }
1213 #else
1214 return 0;
1215 #endif
1216 }
1217
1218 /* count_ip_hash()
1219 *
1220 * inputs - pointer to counter of number of ips hashed
1221 * - pointer to memory used for ip hash
1222 * output - returned via pointers input
1223 * side effects - NONE
1224 *
1225 * number of hashed ip #'s is counted up, plus the amount of memory
1226 * used in the hash.
1227 */
1228 void
1229 count_ip_hash(unsigned int *number_ips_stored, uint64_t *mem_ips_stored)
1230 {
1231 struct ip_entry *ptr;
1232 int i;
1233
1234 *number_ips_stored = 0;
1235 *mem_ips_stored = 0;
1236
1237 for (i = 0; i < IP_HASH_SIZE; i++)
1238 {
1239 for (ptr = ip_hash_table[i]; ptr; ptr = ptr->next)
1240 {
1241 *number_ips_stored += 1;
1242 *mem_ips_stored += sizeof(struct ip_entry);
1243 }
1244 }
1245 }
1246
1247 /* garbage_collect_ip_entries()
1248 *
1249 * input - NONE
1250 * output - NONE
1251 * side effects - free up all ip entries with no connections
1252 */
1253 static void
1254 garbage_collect_ip_entries(void)
1255 {
1256 struct ip_entry *ptr;
1257 struct ip_entry *last_ptr;
1258 struct ip_entry *next_ptr;
1259 int i;
1260
1261 for (i = 0; i < IP_HASH_SIZE; i++)
1262 {
1263 last_ptr = NULL;
1264
1265 for (ptr = ip_hash_table[i]; ptr; ptr = next_ptr)
1266 {
1267 next_ptr = ptr->next;
1268
1269 if (ptr->count == 0 &&
1270 (CurrentTime - ptr->last_attempt) >= ConfigFileEntry.throttle_time)
1271 {
1272 if (last_ptr != NULL)
1273 last_ptr->next = ptr->next;
1274 else
1275 ip_hash_table[i] = ptr->next;
1276 BlockHeapFree(ip_entry_heap, ptr);
1277 ip_entries_count--;
1278 }
1279 else
1280 last_ptr = ptr;
1281 }
1282 }
1283 }
1284
1285 /* detach_conf()
1286 *
1287 * inputs - pointer to client to detach
1288 * - type of conf to detach
1289 * output - 0 for success, -1 for failure
1290 * side effects - Disassociate configuration from the client.
1291 * Also removes a class from the list if marked for deleting.
1292 */
1293 int
1294 detach_conf(struct Client *client_p, ConfType type)
1295 {
1296 dlink_node *ptr, *next_ptr;
1297 struct ConfItem *conf;
1298 struct ClassItem *aclass;
1299 struct AccessItem *aconf;
1300 struct ConfItem *aclass_conf;
1301 struct MatchItem *match_item;
1302
1303 DLINK_FOREACH_SAFE(ptr, next_ptr, client_p->localClient->confs.head)
1304 {
1305 conf = ptr->data;
1306
1307 if (type == CONF_TYPE || conf->type == type)
1308 {
1309 dlinkDelete(ptr, &client_p->localClient->confs);
1310 free_dlink_node(ptr);
1311
1312 switch (conf->type)
1313 {
1314 case CLIENT_TYPE:
1315 case OPER_TYPE:
1316 case SERVER_TYPE:
1317 aconf = map_to_conf(conf);
1318
1319 assert(aconf->clients > 0);
1320
1321 if ((aclass_conf = ClassPtr(aconf)) != NULL)
1322 {
1323 aclass = map_to_conf(aclass_conf);
1324
1325 assert(aclass->curr_user_count > 0);
1326
1327 if (conf->type == CLIENT_TYPE)
1328 remove_from_cidr_check(&client_p->localClient->ip, aclass);
1329 if (--aclass->curr_user_count == 0 && aclass->active == 0)
1330 delete_conf_item(aclass_conf);
1331 }
1332
1333 if (--aconf->clients == 0 && IsConfIllegal(aconf))
1334 delete_conf_item(conf);
1335
1336 break;
1337
1338 case LEAF_TYPE:
1339 case HUB_TYPE:
1340 match_item = map_to_conf(conf);
1341 if (match_item->ref_count == 0 && match_item->illegal)
1342 delete_conf_item(conf);
1343 break;
1344 default:
1345 break;
1346 }
1347
1348 if (type != CONF_TYPE)
1349 return 0;
1350 }
1351 }
1352
1353 return -1;
1354 }
1355
1356 /* attach_conf()
1357 *
1358 * inputs - client pointer
1359 * - conf pointer
1360 * output -
1361 * side effects - Associate a specific configuration entry to a *local*
1362 * client (this is the one which used in accepting the
1363 * connection). Note, that this automatically changes the
1364 * attachment if there was an old one...
1365 */
1366 int
1367 attach_conf(struct Client *client_p, struct ConfItem *conf)
1368 {
1369 if (dlinkFind(&client_p->localClient->confs, conf) != NULL)
1370 return 1;
1371
1372 if (conf->type == CLIENT_TYPE ||
1373 conf->type == SERVER_TYPE ||
1374 conf->type == OPER_TYPE)
1375 {
1376 struct AccessItem *aconf = map_to_conf(conf);
1377 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1378
1379 if (IsConfIllegal(aconf))
1380 return NOT_AUTHORIZED;
1381
1382 if (conf->type == CLIENT_TYPE)
1383 if (cidr_limit_reached(IsConfExemptLimits(aconf),
1384 &client_p->localClient->ip, aclass))
1385 return TOO_MANY; /* Already at maximum allowed */
1386
1387 CurrUserCount(aclass)++;
1388 aconf->clients++;
1389 }
1390 else if (conf->type == HUB_TYPE || conf->type == LEAF_TYPE)
1391 {
1392 struct MatchItem *match_item = map_to_conf(conf);
1393 match_item->ref_count++;
1394 }
1395
1396 dlinkAdd(conf, make_dlink_node(), &client_p->localClient->confs);
1397
1398 return 0;
1399 }
1400
1401 /* attach_connect_block()
1402 *
1403 * inputs - pointer to server to attach
1404 * - name of server
1405 * - hostname of server
1406 * output - true (1) if both are found, otherwise return false (0)
1407 * side effects - find connect block and attach them to connecting client
1408 */
1409 int
1410 attach_connect_block(struct Client *client_p, const char *name,
1411 const char *host)
1412 {
1413 dlink_node *ptr;
1414 struct ConfItem *conf;
1415 struct AccessItem *aconf;
1416
1417 assert(client_p != NULL);
1418 assert(host != NULL);
1419
1420 if (client_p == NULL || host == NULL)
1421 return 0;
1422
1423 DLINK_FOREACH(ptr, server_items.head)
1424 {
1425 conf = ptr->data;
1426 aconf = map_to_conf(conf);
1427
1428 if (match(conf->name, name) == 0 || match(aconf->host, host) == 0)
1429 continue;
1430
1431 attach_conf(client_p, conf);
1432 return -1;
1433 }
1434
1435 return 0;
1436 }
1437
1438 /* find_conf_exact()
1439 *
1440 * inputs - type of ConfItem
1441 * - pointer to name to find
1442 * - pointer to username to find
1443 * - pointer to host to find
1444 * output - NULL or pointer to conf found
1445 * side effects - find a conf entry which matches the hostname
1446 * and has the same name.
1447 */
1448 struct ConfItem *
1449 find_conf_exact(ConfType type, const char *name, const char *user,
1450 const char *host)
1451 {
1452 dlink_node *ptr;
1453 dlink_list *list_p;
1454 struct ConfItem *conf = NULL;
1455 struct AccessItem *aconf;
1456
1457 /* Only valid for OPER_TYPE and ...? */
1458 list_p = map_to_list(type);
1459
1460 DLINK_FOREACH(ptr, (*list_p).head)
1461 {
1462 conf = ptr->data;
1463
1464 if (conf->name == NULL)
1465 continue;
1466 aconf = map_to_conf(conf);
1467 if (aconf->host == NULL)
1468 continue;
1469 if (irccmp(conf->name, name) != 0)
1470 continue;
1471
1472 /*
1473 ** Accept if the *real* hostname (usually sockethost)
1474 ** socket host) matches *either* host or name field
1475 ** of the configuration.
1476 */
1477 if (!match(aconf->host, host) || !match(aconf->user, user))
1478 continue;
1479 if (type == OPER_TYPE)
1480 {
1481 struct ClassItem *aclass = map_to_conf(aconf->class_ptr);
1482
1483 if (aconf->clients >= MaxTotal(aclass))
1484 continue;
1485 }
1486
1487 return conf;
1488 }
1489
1490 return NULL;
1491 }
1492
1493 /* find_conf_name()
1494 *
1495 * inputs - pointer to conf link list to search
1496 * - pointer to name to find
1497 * - int mask of type of conf to find
1498 * output - NULL or pointer to conf found
1499 * side effects - find a conf entry which matches the name
1500 * and has the given mask.
1501 */
1502 struct ConfItem *
1503 find_conf_name(dlink_list *list, const char *name, ConfType type)
1504 {
1505 dlink_node *ptr;
1506 struct ConfItem* conf;
1507
1508 DLINK_FOREACH(ptr, list->head)
1509 {
1510 conf = ptr->data;
1511
1512 if (conf->type == type)
1513 {
1514 if (conf->name && (irccmp(conf->name, name) == 0 ||
1515 match(conf->name, name)))
1516 return conf;
1517 }
1518 }
1519
1520 return NULL;
1521 }
1522
1523 /* map_to_list()
1524 *
1525 * inputs - ConfType conf
1526 * output - pointer to dlink_list to use
1527 * side effects - none
1528 */
1529 static dlink_list *
1530 map_to_list(ConfType type)
1531 {
1532 switch(type)
1533 {
1534 case RXLINE_TYPE:
1535 return(&rxconf_items);
1536 break;
1537 case XLINE_TYPE:
1538 return(&xconf_items);
1539 break;
1540 case ULINE_TYPE:
1541 return(&uconf_items);
1542 break;
1543 case NRESV_TYPE:
1544 return(&nresv_items);
1545 break;
1546 case OPER_TYPE:
1547 return(&oconf_items);
1548 break;
1549 case CLASS_TYPE:
1550 return(&class_items);
1551 break;
1552 case SERVER_TYPE:
1553 return(&server_items);
1554 break;
1555 case CLUSTER_TYPE:
1556 return(&cluster_items);
1557 break;
1558 case CONF_TYPE:
1559 case GLINE_TYPE:
1560 case KLINE_TYPE:
1561 case DLINE_TYPE:
1562 case CRESV_TYPE:
1563 default:
1564 return NULL;
1565 }
1566 }
1567
1568 /* find_matching_name_conf()
1569 *
1570 * inputs - type of link list to look in
1571 * - pointer to name string to find
1572 * - pointer to user
1573 * - pointer to host
1574 * - optional action to match on as well
1575 * output - NULL or pointer to found struct MatchItem
1576 * side effects - looks for a match on name field
1577 */
1578 struct ConfItem *
1579 find_matching_name_conf(ConfType type, const char *name, const char *user,
1580 const char *host, int action)
1581 {
1582 dlink_node *ptr=NULL;
1583 struct ConfItem *conf=NULL;
1584 struct AccessItem *aconf=NULL;
1585 struct MatchItem *match_item=NULL;
1586 dlink_list *list_p = map_to_list(type);
1587
1588 switch (type)
1589 {
1590 case RXLINE_TYPE:
1591 DLINK_FOREACH(ptr, list_p->head)
1592 {
1593 conf = ptr->data;
1594 assert(conf->regexpname);
1595
1596 if (!ircd_pcre_exec(conf->regexpname, name))
1597 return conf;
1598 }
1599 break;
1600
1601 case XLINE_TYPE:
1602 case ULINE_TYPE:
1603 case NRESV_TYPE:
1604 DLINK_FOREACH(ptr, list_p->head)
1605 {
1606 conf = ptr->data;
1607
1608 match_item = map_to_conf(conf);
1609 if (EmptyString(conf->name))
1610 continue;
1611 if ((name != NULL) && match_esc(conf->name, name))
1612 {
1613 if ((user == NULL && (host == NULL)))
1614 return conf;
1615 if ((match_item->action & action) != action)
1616 continue;
1617 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1618 return conf;
1619 if (match(match_item->user, user) && match(match_item->host, host))
1620 return conf;
1621 }
1622 }
1623 break;
1624
1625 case SERVER_TYPE:
1626 DLINK_FOREACH(ptr, list_p->head)
1627 {
1628 conf = ptr->data;
1629 aconf = map_to_conf(conf);
1630
1631 if ((name != NULL) && match_esc(name, conf->name))
1632 return conf;
1633 else if ((host != NULL) && match_esc(host, aconf->host))
1634 return conf;
1635 }
1636 break;
1637
1638 default:
1639 break;
1640 }
1641 return NULL;
1642 }
1643
1644 /* find_exact_name_conf()
1645 *
1646 * inputs - type of link list to look in
1647 * - pointer to name string to find
1648 * - pointer to user
1649 * - pointer to host
1650 * output - NULL or pointer to found struct MatchItem
1651 * side effects - looks for an exact match on name field
1652 */
1653 struct ConfItem *
1654 find_exact_name_conf(ConfType type, const char *name,
1655 const char *user, const char *host)
1656 {
1657 dlink_node *ptr = NULL;
1658 struct AccessItem *aconf;
1659 struct ConfItem *conf;
1660 struct MatchItem *match_item;
1661 dlink_list *list_p;
1662
1663 list_p = map_to_list(type);
1664
1665 switch(type)
1666 {
1667 case RXLINE_TYPE:
1668 case XLINE_TYPE:
1669 case ULINE_TYPE:
1670 case NRESV_TYPE:
1671
1672 DLINK_FOREACH(ptr, list_p->head)
1673 {
1674 conf = ptr->data;
1675 match_item = (struct MatchItem *)map_to_conf(conf);
1676 if (EmptyString(conf->name))
1677 continue;
1678
1679 if (irccmp(conf->name, name) == 0)
1680 {
1681 if ((user == NULL && (host == NULL)))
1682 return (conf);
1683 if (EmptyString(match_item->user) || EmptyString(match_item->host))
1684 return (conf);
1685 if (match(match_item->user, user) && match(match_item->host, host))
1686 return (conf);
1687 }
1688 }
1689 break;
1690
1691 case OPER_TYPE:
1692 DLINK_FOREACH(ptr, list_p->head)
1693 {
1694 conf = ptr->data;
1695 aconf = (struct AccessItem *)map_to_conf(conf);
1696 if (EmptyString(conf->name))
1697 continue;
1698
1699 if (irccmp(conf->name, name) == 0)
1700 {
1701 if ((user == NULL && (host == NULL)))
1702 return (conf);
1703 if (EmptyString(aconf->user) || EmptyString(aconf->host))
1704 return (conf);
1705 if (match(aconf->user, user) && match(aconf->host, host))
1706 return (conf);
1707 }
1708 }
1709 break;
1710
1711 case SERVER_TYPE:
1712 DLINK_FOREACH(ptr, list_p->head)
1713 {
1714 conf = ptr->data;
1715 aconf = (struct AccessItem *)map_to_conf(conf);
1716 if (EmptyString(conf->name))
1717 continue;
1718
1719 if (name == NULL)
1720 {
1721 if (EmptyString(aconf->host))
1722 continue;
1723 if (irccmp(aconf->host, host) == 0)
1724 return(conf);
1725 }
1726 else if (irccmp(conf->name, name) == 0)
1727 {
1728 return (conf);
1729 }
1730 }
1731 break;
1732
1733 case CLASS_TYPE:
1734 DLINK_FOREACH(ptr, list_p->head)
1735 {
1736 conf = ptr->data;
1737 if (EmptyString(conf->name))
1738 continue;
1739
1740 if (irccmp(conf->name, name) == 0)
1741 return (conf);
1742 }
1743 break;
1744
1745 default:
1746 break;
1747 }
1748 return(NULL);
1749 }
1750
1751 /* rehash()
1752 *
1753 * Actual REHASH service routine. Called with sig == 0 if it has been called
1754 * as a result of an operator issuing this command, else assume it has been
1755 * called as a result of the server receiving a HUP signal.
1756 */
1757 int
1758 rehash(int sig)
1759 {
1760 if (sig != 0)
1761 sendto_realops_flags(UMODE_ALL, L_ALL,
1762 "Got signal SIGHUP, reloading ircd.conf file");
1763
1764 #ifndef _WIN32
1765 restart_resolver();
1766 #endif
1767 /* don't close listeners until we know we can go ahead with the rehash */
1768
1769 /* Check to see if we magically got(or lost) IPv6 support */
1770 check_can_use_v6();
1771
1772 read_conf_files(0);
1773
1774 if (ServerInfo.description != NULL)
1775 strlcpy(me.info, ServerInfo.description, sizeof(me.info));
1776
1777 #ifndef STATIC_MODULES
1778 load_conf_modules();
1779 #endif
1780
1781 flush_deleted_I_P();
1782
1783 rehashed_klines = 1;
1784
1785 if (ConfigLoggingEntry.use_logging)
1786 reopen_log(logFileName);
1787
1788 return(0);
1789 }
1790
1791 /* set_default_conf()
1792 *
1793 * inputs - NONE
1794 * output - NONE
1795 * side effects - Set default values here.
1796 * This is called **PRIOR** to parsing the
1797 * configuration file. If you want to do some validation
1798 * of values later, put them in validate_conf().
1799 */
1800 static void
1801 set_default_conf(void)
1802 {
1803 /* verify init_class() ran, this should be an unnecessary check
1804 * but its not much work.
1805 */
1806 assert(class_default == (struct ConfItem *) class_items.tail->data);
1807
1808 #ifdef HAVE_LIBCRYPTO
1809 ServerInfo.rsa_private_key = NULL;
1810 ServerInfo.rsa_private_key_file = NULL;
1811 #endif
1812
1813 /* ServerInfo.name is not rehashable */
1814 /* ServerInfo.name = ServerInfo.name; */
1815 ServerInfo.description = NULL;
1816 DupString(ServerInfo.network_name, NETWORK_NAME_DEFAULT);
1817 DupString(ServerInfo.network_desc, NETWORK_DESC_DEFAULT);
1818
1819 memset(&ServerInfo.ip, 0, sizeof(ServerInfo.ip));
1820 ServerInfo.specific_ipv4_vhost = 0;
1821 memset(&ServerInfo.ip6, 0, sizeof(ServerInfo.ip6));
1822 ServerInfo.specific_ipv6_vhost = 0;
1823
1824 ServerInfo.max_clients = MAXCLIENTS_MAX;
1825
1826 ServerInfo.hub = 0;
1827 delete_capability("HUB");
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 int
2948 get_sendq(struct Client *client_p)
2949 {
2950 unsigned int 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 use 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