ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.3/src/s_conf.c
Revision: 948
Committed: Tue Jul 21 17:34:06 2009 UTC (14 years, 8 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100578 byte(s)
Log Message:
- lp64\llp64\ilp32 portability fixes

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 /* Don't reset hub, as that will break lazylinks */
1826 /* ServerInfo.hub = NO; */
1827 ServerInfo.dns_host.sin_addr.s_addr = 0;
1828 ServerInfo.dns_host.sin_port = 0;
1829 AdminInfo.name = NULL;
1830 AdminInfo.email = NULL;
1831 AdminInfo.description = NULL;
1832
1833 set_log_level(L_NOTICE);
1834 ConfigLoggingEntry.use_logging = 1;
1835 ConfigLoggingEntry.operlog[0] = '\0';
1836 ConfigLoggingEntry.userlog[0] = '\0';
1837 ConfigLoggingEntry.klinelog[0] = '\0';
1838 ConfigLoggingEntry.glinelog[0] = '\0';
1839 ConfigLoggingEntry.killlog[0] = '\0';
1840 ConfigLoggingEntry.operspylog[0] = '\0';
1841 ConfigLoggingEntry.ioerrlog[0] = '\0';
1842 ConfigLoggingEntry.failed_operlog[0] = '\0';
1843
1844 ConfigChannel.disable_fake_channels = NO;
1845 ConfigChannel.restrict_channels = NO;
1846 ConfigChannel.disable_local_channels = NO;
1847 ConfigChannel.use_invex = YES;
1848 ConfigChannel.use_except = YES;
1849 ConfigChannel.use_knock = YES;
1850 ConfigChannel.knock_delay = 300;
1851 ConfigChannel.knock_delay_channel = 60;
1852 ConfigChannel.max_chans_per_user = 15;
1853 ConfigChannel.quiet_on_ban = YES;
1854 ConfigChannel.max_bans = 25;
1855 ConfigChannel.default_split_user_count = 0;
1856 ConfigChannel.default_split_server_count = 0;
1857 ConfigChannel.no_join_on_split = NO;
1858 ConfigChannel.no_create_on_split = NO;
1859 ConfigChannel.burst_topicwho = YES;
1860
1861 ConfigServerHide.flatten_links = NO;
1862 ConfigServerHide.links_delay = 300;
1863 ConfigServerHide.hidden = NO;
1864 ConfigServerHide.disable_hidden = NO;
1865 ConfigServerHide.hide_servers = NO;
1866 DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1867 ConfigServerHide.hide_server_ips = NO;
1868
1869
1870 ConfigFileEntry.max_watch = WATCHSIZE_DEFAULT;
1871 ConfigFileEntry.gline_min_cidr = 16;
1872 ConfigFileEntry.gline_min_cidr6 = 48;
1873 ConfigFileEntry.invisible_on_connect = YES;
1874 ConfigFileEntry.burst_away = NO;
1875 ConfigFileEntry.use_whois_actually = YES;
1876 ConfigFileEntry.tkline_expire_notices = YES;
1877 ConfigFileEntry.hide_spoof_ips = YES;
1878 ConfigFileEntry.ignore_bogus_ts = NO;
1879 ConfigFileEntry.disable_auth = NO;
1880 ConfigFileEntry.disable_remote = NO;
1881 ConfigFileEntry.kill_chase_time_limit = 90;
1882 ConfigFileEntry.default_floodcount = 8; /* XXX */
1883 ConfigFileEntry.failed_oper_notice = YES;
1884 ConfigFileEntry.dots_in_ident = 0; /* XXX */
1885 ConfigFileEntry.dot_in_ip6_addr = YES;
1886 ConfigFileEntry.min_nonwildcard = 4;
1887 ConfigFileEntry.min_nonwildcard_simple = 3;
1888 ConfigFileEntry.max_accept = 20;
1889 ConfigFileEntry.anti_nick_flood = NO; /* XXX */
1890 ConfigFileEntry.max_nick_time = 20;
1891 ConfigFileEntry.max_nick_changes = 5;
1892 ConfigFileEntry.anti_spam_exit_message_time = 0; /* XXX */
1893 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1894 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT; /* XXX */
1895 ConfigFileEntry.kline_with_reason = YES;
1896 ConfigFileEntry.kline_reason = NULL;
1897 ConfigFileEntry.warn_no_nline = YES;
1898 ConfigFileEntry.stats_o_oper_only = NO; /* XXX */
1899 ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1900 ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1901 ConfigFileEntry.stats_P_oper_only = NO;
1902 ConfigFileEntry.caller_id_wait = 60;
1903 ConfigFileEntry.opers_bypass_callerid = NO;
1904 ConfigFileEntry.pace_wait = 10;
1905 ConfigFileEntry.pace_wait_simple = 1;
1906 ConfigFileEntry.short_motd = NO;
1907 ConfigFileEntry.ping_cookie = NO;
1908 ConfigFileEntry.no_oper_flood = NO; /* XXX */
1909 ConfigFileEntry.true_no_oper_flood = NO; /* XXX */
1910 ConfigFileEntry.oper_pass_resv = YES;
1911 ConfigFileEntry.glines = NO; /* XXX */
1912 ConfigFileEntry.gline_time = 12 * 3600; /* XXX */
1913 ConfigFileEntry.idletime = 0;
1914 ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1915 ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
1916 ConfigFileEntry.oper_only_umodes = UMODE_DEBUG; /* XXX */
1917 ConfigFileEntry.oper_umodes = UMODE_BOTS | UMODE_LOCOPS | UMODE_SERVNOTICE |
1918 UMODE_OPERWALL | UMODE_WALLOP; /* XXX */
1919 DupString(ConfigFileEntry.servlink_path, SLPATH);
1920 #ifdef HAVE_LIBCRYPTO
1921 /* jdc -- This is our default value for a cipher. According to the
1922 * CRYPTLINK document (doc/cryptlink.txt), BF/128 must be supported
1923 * under all circumstances if cryptlinks are enabled. So,
1924 * this will be our default.
1925 *
1926 * NOTE: I apologise for the hard-coded value of "1" (BF/128).
1927 * This should be moved into a find_cipher() routine.
1928 */
1929 ConfigFileEntry.default_cipher_preference = &CipherTable[1];
1930 #endif
1931 ConfigFileEntry.use_egd = NO;
1932 ConfigFileEntry.egdpool_path = NULL;
1933 #ifdef HAVE_LIBZ
1934 ConfigFileEntry.compression_level = 0;
1935 #endif
1936 ConfigFileEntry.throttle_time = 10;
1937 }
1938
1939 /* read_conf()
1940 *
1941 * inputs - file descriptor pointing to config file to use
1942 * output - None
1943 * side effects - Read configuration file.
1944 */
1945 static void
1946 read_conf(FBFILE *file)
1947 {
1948 lineno = 0;
1949
1950 set_default_conf(); /* Set default values prior to conf parsing */
1951 ypass = 1;
1952 yyparse(); /* pick up the classes first */
1953
1954 fbrewind(file);
1955
1956 ypass = 2;
1957 yyparse(); /* Load the values from the conf */
1958 validate_conf(); /* Check to make sure some values are still okay. */
1959 /* Some global values are also loaded here. */
1960 check_class(); /* Make sure classes are valid */
1961 }
1962
1963 static void
1964 validate_conf(void)
1965 {
1966 if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1967 ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1968
1969 if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1970 ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1971
1972 if (ConfigFileEntry.servlink_path == NULL)
1973 DupString(ConfigFileEntry.servlink_path, SLPATH);
1974
1975 if (ServerInfo.network_name == NULL)
1976 DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1977
1978 if (ServerInfo.network_desc == NULL)
1979 DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1980
1981 if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
1982 (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
1983 ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
1984
1985 ConfigFileEntry.max_watch = IRCD_MAX(ConfigFileEntry.max_watch, WATCHSIZE_MIN);
1986 }
1987
1988 /* lookup_confhost()
1989 *
1990 * start DNS lookups of all hostnames in the conf
1991 * line and convert an IP addresses in a.b.c.d number for to IP#s.
1992 */
1993 static void
1994 lookup_confhost(struct ConfItem *conf)
1995 {
1996 struct AccessItem *aconf;
1997 struct addrinfo hints, *res;
1998
1999 aconf = map_to_conf(conf);
2000
2001 if (EmptyString(aconf->host) ||
2002 EmptyString(aconf->user))
2003 {
2004 ilog(L_ERROR, "Host/server name error: (%s) (%s)",
2005 aconf->host, conf->name);
2006 return;
2007 }
2008
2009 if (strchr(aconf->host, '*') ||
2010 strchr(aconf->host, '?'))
2011 return;
2012
2013 /* Do name lookup now on hostnames given and store the
2014 * ip numbers in conf structure.
2015 */
2016 memset(&hints, 0, sizeof(hints));
2017
2018 hints.ai_family = AF_UNSPEC;
2019 hints.ai_socktype = SOCK_STREAM;
2020
2021 /* Get us ready for a bind() and don't bother doing dns lookup */
2022 hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2023
2024 if (irc_getaddrinfo(aconf->host, NULL, &hints, &res))
2025 {
2026 conf_dns_lookup(aconf);
2027 return;
2028 }
2029
2030 assert(res != NULL);
2031
2032 memcpy(&aconf->ipnum, res->ai_addr, res->ai_addrlen);
2033 aconf->ipnum.ss_len = res->ai_addrlen;
2034 aconf->ipnum.ss.ss_family = res->ai_family;
2035 irc_freeaddrinfo(res);
2036 }
2037
2038 /* conf_connect_allowed()
2039 *
2040 * inputs - pointer to inaddr
2041 * - int type ipv4 or ipv6
2042 * output - BANNED or accepted
2043 * side effects - none
2044 */
2045 int
2046 conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
2047 {
2048 struct ip_entry *ip_found;
2049 struct AccessItem *aconf = find_dline_conf(addr, aftype);
2050
2051 /* DLINE exempt also gets you out of static limits/pacing... */
2052 if (aconf && (aconf->status & CONF_EXEMPTDLINE))
2053 return 0;
2054
2055 if (aconf != NULL)
2056 return BANNED_CLIENT;
2057
2058 ip_found = find_or_add_ip(addr);
2059
2060 if ((CurrentTime - ip_found->last_attempt) <
2061 ConfigFileEntry.throttle_time)
2062 {
2063 ip_found->last_attempt = CurrentTime;
2064 return TOO_FAST;
2065 }
2066
2067 ip_found->last_attempt = CurrentTime;
2068 return 0;
2069 }
2070
2071 static struct AccessItem *
2072 find_regexp_kline(const char *uhi[])
2073 {
2074 const dlink_node *ptr = NULL;
2075
2076 DLINK_FOREACH(ptr, rkconf_items.head)
2077 {
2078 struct AccessItem *aptr = map_to_conf(ptr->data);
2079
2080 assert(aptr->regexuser);
2081 assert(aptr->regexhost);
2082
2083 if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
2084 (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
2085 !ircd_pcre_exec(aptr->regexhost, uhi[2])))
2086 return aptr;
2087 }
2088
2089 return NULL;
2090 }
2091
2092 /* find_kill()
2093 *
2094 * inputs - pointer to client structure
2095 * output - pointer to struct AccessItem if found
2096 * side effects - See if this user is klined already,
2097 * and if so, return struct AccessItem pointer
2098 */
2099 struct AccessItem *
2100 find_kill(struct Client *client_p)
2101 {
2102 struct AccessItem *aconf = NULL;
2103 const char *uhi[3];
2104
2105 uhi[0] = client_p->username;
2106 uhi[1] = client_p->host;
2107 uhi[2] = client_p->sockhost;
2108
2109 assert(client_p != NULL);
2110
2111 aconf = find_kline_conf(client_p->host, client_p->username,
2112 &client_p->localClient->ip,
2113 client_p->localClient->aftype);
2114 if (aconf == NULL)
2115 aconf = find_regexp_kline(uhi);
2116
2117 if (aconf && (aconf->status & CONF_KLINE))
2118 return aconf;
2119
2120 return NULL;
2121 }
2122
2123 struct AccessItem *
2124 find_gline(struct Client *client_p)
2125 {
2126 struct AccessItem *aconf;
2127
2128 assert(client_p != NULL);
2129
2130 aconf = find_gline_conf(client_p->host, client_p->username,
2131 &client_p->localClient->ip,
2132 client_p->localClient->aftype);
2133
2134 if (aconf && (aconf->status & CONF_GLINE))
2135 return aconf;
2136
2137 return NULL;
2138 }
2139
2140 /* add_temp_line()
2141 *
2142 * inputs - pointer to struct ConfItem
2143 * output - none
2144 * Side effects - links in given struct ConfItem into
2145 * temporary *line link list
2146 */
2147 void
2148 add_temp_line(struct ConfItem *conf)
2149 {
2150 struct AccessItem *aconf;
2151
2152 if (conf->type == DLINE_TYPE)
2153 {
2154 aconf = map_to_conf(conf);
2155 SetConfTemporary(aconf);
2156 dlinkAdd(conf, &conf->node, &temporary_dlines);
2157 MyFree(aconf->user);
2158 aconf->user = NULL;
2159 add_conf_by_address(CONF_DLINE, aconf);
2160 }
2161 else if (conf->type == KLINE_TYPE)
2162 {
2163 aconf = map_to_conf(conf);
2164 SetConfTemporary(aconf);
2165 dlinkAdd(conf, &conf->node, &temporary_klines);
2166 add_conf_by_address(CONF_KILL, aconf);
2167 }
2168 else if (conf->type == GLINE_TYPE)
2169 {
2170 aconf = map_to_conf(conf);
2171 SetConfTemporary(aconf);
2172 dlinkAdd(conf, &conf->node, &temporary_glines);
2173 add_conf_by_address(CONF_GLINE, aconf);
2174 }
2175 else if (conf->type == XLINE_TYPE)
2176 {
2177 conf->flags |= CONF_FLAGS_TEMPORARY;
2178 dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
2179 }
2180 else if (conf->type == RXLINE_TYPE)
2181 {
2182 conf->flags |= CONF_FLAGS_TEMPORARY;
2183 dlinkAdd(conf, make_dlink_node(), &temporary_rxlines);
2184 }
2185 else if (conf->type == RKLINE_TYPE)
2186 {
2187 conf->flags |= CONF_FLAGS_TEMPORARY;
2188 dlinkAdd(conf, make_dlink_node(), &temporary_rklines);
2189 }
2190 else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
2191 {
2192 conf->flags |= CONF_FLAGS_TEMPORARY;
2193 dlinkAdd(conf, make_dlink_node(), &temporary_resv);
2194 }
2195 }
2196
2197 /* cleanup_tklines()
2198 *
2199 * inputs - NONE
2200 * output - NONE
2201 * side effects - call function to expire temporary k/d lines
2202 * This is an event started off in ircd.c
2203 */
2204 void
2205 cleanup_tklines(void *notused)
2206 {
2207 expire_tklines(&temporary_glines);
2208 expire_tklines(&temporary_klines);
2209 expire_tklines(&temporary_dlines);
2210 expire_tklines(&temporary_xlines);
2211 expire_tklines(&temporary_rxlines);
2212 expire_tklines(&temporary_rklines);
2213 expire_tklines(&temporary_resv);
2214 }
2215
2216 /* expire_tklines()
2217 *
2218 * inputs - tkline list pointer
2219 * output - NONE
2220 * side effects - expire tklines
2221 */
2222 static void
2223 expire_tklines(dlink_list *tklist)
2224 {
2225 dlink_node *ptr;
2226 dlink_node *next_ptr;
2227 struct ConfItem *conf;
2228 struct MatchItem *xconf;
2229 struct MatchItem *nconf;
2230 struct AccessItem *aconf;
2231 struct ResvChannel *cconf;
2232
2233 DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2234 {
2235 conf = ptr->data;
2236 if (conf->type == GLINE_TYPE ||
2237 conf->type == KLINE_TYPE ||
2238 conf->type == DLINE_TYPE)
2239 {
2240 aconf = (struct AccessItem *)map_to_conf(conf);
2241 if (aconf->hold <= CurrentTime)
2242 {
2243 /* XXX - Do we want GLINE expiry notices?? */
2244 /* Alert opers that a TKline expired - Hwy */
2245 if (ConfigFileEntry.tkline_expire_notices)
2246 {
2247 if (aconf->status & CONF_KILL)
2248 {
2249 sendto_realops_flags(UMODE_ALL, L_ALL,
2250 "Temporary K-line for [%s@%s] expired",
2251 (aconf->user) ? aconf->user : "*",
2252 (aconf->host) ? aconf->host : "*");
2253 }
2254 else if (conf->type == DLINE_TYPE)
2255 {
2256 sendto_realops_flags(UMODE_ALL, L_ALL,
2257 "Temporary D-line for [%s] expired",
2258 (aconf->host) ? aconf->host : "*");
2259 }
2260 }
2261
2262 dlinkDelete(ptr, tklist);
2263 delete_one_address_conf(aconf->host, aconf);
2264 }
2265 }
2266 else if (conf->type == XLINE_TYPE ||
2267 conf->type == RXLINE_TYPE)
2268 {
2269 xconf = (struct MatchItem *)map_to_conf(conf);
2270 if (xconf->hold <= CurrentTime)
2271 {
2272 if (ConfigFileEntry.tkline_expire_notices)
2273 sendto_realops_flags(UMODE_ALL, L_ALL,
2274 "Temporary X-line for [%s] %sexpired", conf->name,
2275 conf->type == RXLINE_TYPE ? "(REGEX) " : "");
2276 dlinkDelete(ptr, tklist);
2277 free_dlink_node(ptr);
2278 delete_conf_item(conf);
2279 }
2280 }
2281 else if (conf->type == RKLINE_TYPE)
2282 {
2283 aconf = map_to_conf(conf);
2284 if (aconf->hold <= CurrentTime)
2285 {
2286 if (ConfigFileEntry.tkline_expire_notices)
2287 sendto_realops_flags(UMODE_ALL, L_ALL,
2288 "Temporary K-line for [%s@%s] (REGEX) expired",
2289 (aconf->user) ? aconf->user : "*",
2290 (aconf->host) ? aconf->host : "*");
2291 dlinkDelete(ptr, tklist);
2292 free_dlink_node(ptr);
2293 delete_conf_item(conf);
2294 }
2295 }
2296 else if (conf->type == NRESV_TYPE)
2297 {
2298 nconf = (struct MatchItem *)map_to_conf(conf);
2299 if (nconf->hold <= CurrentTime)
2300 {
2301 if (ConfigFileEntry.tkline_expire_notices)
2302 sendto_realops_flags(UMODE_ALL, L_ALL,
2303 "Temporary RESV for [%s] expired", conf->name);
2304 dlinkDelete(ptr, tklist);
2305 free_dlink_node(ptr);
2306 delete_conf_item(conf);
2307 }
2308 }
2309 else if (conf->type == CRESV_TYPE)
2310 {
2311 cconf = (struct ResvChannel *)map_to_conf(conf);
2312 if (cconf->hold <= CurrentTime)
2313 {
2314 if (ConfigFileEntry.tkline_expire_notices)
2315 sendto_realops_flags(UMODE_ALL, L_ALL,
2316 "Temporary RESV for [%s] expired", cconf->name);
2317 delete_channel_resv(cconf);
2318 }
2319 }
2320 }
2321 }
2322
2323 /* oper_privs_as_string()
2324 *
2325 * inputs - pointer to client_p
2326 * output - pointer to static string showing oper privs
2327 * side effects - return as string, the oper privs as derived from port
2328 */
2329 static const struct oper_privs
2330 {
2331 const unsigned int oprivs;
2332 const unsigned int hidden;
2333 const unsigned char c;
2334 } flag_list[] = {
2335 { OPER_FLAG_ADMIN, OPER_FLAG_HIDDEN_ADMIN, 'A' },
2336 { OPER_FLAG_REMOTEBAN, 0, 'B' },
2337 { OPER_FLAG_DIE, 0, 'D' },
2338 { OPER_FLAG_GLINE, 0, 'G' },
2339 { OPER_FLAG_REHASH, 0, 'H' },
2340 { OPER_FLAG_K, 0, 'K' },
2341 { OPER_FLAG_OPERWALL, 0, 'L' },
2342 { OPER_FLAG_N, 0, 'N' },
2343 { OPER_FLAG_GLOBAL_KILL, 0, 'O' },
2344 { OPER_FLAG_REMOTE, 0, 'R' },
2345 { OPER_FLAG_OPER_SPY, 0, 'S' },
2346 { OPER_FLAG_UNKLINE, 0, 'U' },
2347 { OPER_FLAG_X, 0, 'X' },
2348 { 0, 0, '\0' }
2349 };
2350
2351 char *
2352 oper_privs_as_string(const unsigned int port)
2353 {
2354 static char privs_out[16];
2355 char *privs_ptr = privs_out;
2356 unsigned int i = 0;
2357
2358 for (; flag_list[i].oprivs; ++i)
2359 {
2360 if ((port & flag_list[i].oprivs) &&
2361 (port & flag_list[i].hidden) == 0)
2362 *privs_ptr++ = flag_list[i].c;
2363 else
2364 *privs_ptr++ = ToLowerTab[flag_list[i].c];
2365 }
2366
2367 *privs_ptr = '\0';
2368
2369 return privs_out;
2370 }
2371
2372 /*
2373 * Input: A client to find the active oper{} name for.
2374 * Output: The nick!user@host{oper} of the oper.
2375 * "oper" is server name for remote opers
2376 * Side effects: None.
2377 */
2378 char *
2379 get_oper_name(const struct Client *client_p)
2380 {
2381 dlink_node *cnode;
2382 struct ConfItem *conf;
2383 struct AccessItem *aconf;
2384
2385 /* +5 for !,@,{,} and null */
2386 static char buffer[NICKLEN+USERLEN+HOSTLEN+HOSTLEN+5];
2387
2388 if (MyConnect(client_p))
2389 {
2390 DLINK_FOREACH(cnode, client_p->localClient->confs.head)
2391 {
2392 conf = cnode->data;
2393 aconf = map_to_conf(conf);
2394
2395 if (IsConfOperator(aconf))
2396 {
2397 ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
2398 client_p->username, client_p->host,
2399 conf->name);
2400 return buffer;
2401 }
2402 }
2403
2404 /* Probably should assert here for now. If there is an oper out there
2405 * with no oper{} conf attached, it would be good for us to know...
2406 */
2407 assert(0); /* Oper without oper conf! */
2408 }
2409
2410 ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
2411 client_p->username, client_p->host, client_p->servptr->name);
2412 return buffer;
2413 }
2414
2415 /* read_conf_files()
2416 *
2417 * inputs - cold start YES or NO
2418 * output - none
2419 * side effects - read all conf files needed, ircd.conf kline.conf etc.
2420 */
2421 void
2422 read_conf_files(int cold)
2423 {
2424 const char *filename;
2425 char chanmodes[32];
2426 char chanlimit[32];
2427
2428 filename = get_conf_name(CONF_TYPE);
2429
2430 /* We need to know the initial filename for the yyerror() to report
2431 FIXME: The full path is in conffilenamebuf first time since we
2432 dont know anything else
2433
2434 - Gozem 2002-07-21
2435 */
2436 strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2437
2438 if ((conf_fbfile_in = fbopen(filename, "r")) == NULL)
2439 {
2440 if (cold)
2441 {
2442 ilog(L_CRIT, "Unable to read configuration file '%s': %s",
2443 filename, strerror(errno));
2444 exit(-1);
2445 }
2446 else
2447 {
2448 sendto_realops_flags(UMODE_ALL, L_ALL,
2449 "Unable to read configuration file '%s': %s",
2450 filename, strerror(errno));
2451 return;
2452 }
2453 }
2454
2455 if (!cold)
2456 clear_out_old_conf();
2457
2458 read_conf(conf_fbfile_in);
2459 fbclose(conf_fbfile_in);
2460
2461 add_isupport("NETWORK", ServerInfo.network_name, -1);
2462 ircsprintf(chanmodes, "b%s%s:%d", ConfigChannel.use_except ? "e" : "",
2463 ConfigChannel.use_invex ? "I" : "", ConfigChannel.max_bans);
2464 add_isupport("MAXLIST", chanmodes, -1);
2465 add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2466 if (ConfigChannel.disable_local_channels)
2467 add_isupport("CHANTYPES", "#", -1);
2468 else
2469 add_isupport("CHANTYPES", "#&", -1);
2470 ircsprintf(chanlimit, "%s:%d", ConfigChannel.disable_local_channels ? "#" : "#&",
2471 ConfigChannel.max_chans_per_user);
2472 add_isupport("CHANLIMIT", chanlimit, -1);
2473 ircsprintf(chanmodes, "%s%s%s", ConfigChannel.use_except ? "e" : "",
2474 ConfigChannel.use_invex ? "I" : "", "b,k,l,imnpst");
2475 add_isupport("CHANNELLEN", NULL, LOCAL_CHANNELLEN);
2476 if (ConfigChannel.use_except)
2477 add_isupport("EXCEPTS", "e", -1);
2478 if (ConfigChannel.use_invex)
2479 add_isupport("INVEX", "I", -1);
2480 add_isupport("CHANMODES", chanmodes, -1);
2481
2482 /*
2483 * message_locale may have changed. rebuild isupport since it relies
2484 * on strlen(form_str(RPL_ISUPPORT))
2485 */
2486 rebuild_isupport_message_line();
2487
2488 parse_conf_file(KLINE_TYPE, cold);
2489 parse_conf_file(RKLINE_TYPE, cold);
2490 parse_conf_file(DLINE_TYPE, cold);
2491 parse_conf_file(XLINE_TYPE, cold);
2492 parse_conf_file(RXLINE_TYPE, cold);
2493 parse_conf_file(NRESV_TYPE, cold);
2494 parse_conf_file(CRESV_TYPE, cold);
2495 }
2496
2497 /* parse_conf_file()
2498 *
2499 * inputs - type of conf file to parse
2500 * output - none
2501 * side effects - conf file for givenconf type is opened and read then parsed
2502 */
2503 static void
2504 parse_conf_file(int type, int cold)
2505 {
2506 FBFILE *file = NULL;
2507 const char *filename = get_conf_name(type);
2508
2509 if ((file = fbopen(filename, "r")) == NULL)
2510 {
2511 if (cold)
2512 ilog(L_ERROR, "Unable to read configuration file '%s': %s",
2513 filename, strerror(errno));
2514 else
2515 sendto_realops_flags(UMODE_ALL, L_ALL,
2516 "Unable to read configuration file '%s': %s",
2517 filename, strerror(errno));
2518 }
2519 else
2520 {
2521 parse_csv_file(file, type);
2522 fbclose(file);
2523 }
2524 }
2525
2526 /* clear_out_old_conf()
2527 *
2528 * inputs - none
2529 * output - none
2530 * side effects - Clear out the old configuration
2531 */
2532 static void
2533 clear_out_old_conf(void)
2534 {
2535 dlink_node *ptr = NULL, *next_ptr = NULL;
2536 struct ConfItem *conf;
2537 struct AccessItem *aconf;
2538 struct ClassItem *cltmp;
2539 struct MatchItem *match_item;
2540 dlink_list *free_items [] = {
2541 &server_items, &oconf_items, &hub_items, &leaf_items,
2542 &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2543 &nresv_items, &cluster_items, &gdeny_items, NULL
2544 };
2545
2546 dlink_list ** iterator = free_items; /* C is dumb */
2547
2548 /* We only need to free anything allocated by yyparse() here.
2549 * Resetting structs, etc, is taken care of by set_default_conf().
2550 */
2551
2552 for (; *iterator != NULL; iterator++)
2553 {
2554 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2555 {
2556 conf = ptr->data;
2557 /* XXX This is less than pretty */
2558 if (conf->type == SERVER_TYPE)
2559 {
2560 aconf = map_to_conf(conf);
2561
2562 if (aconf->clients != 0)
2563 {
2564 SetConfIllegal(aconf);
2565 dlinkDelete(&conf->node, &server_items);
2566 }
2567 else
2568 {
2569 delete_conf_item(conf);
2570 }
2571 }
2572 else if (conf->type == OPER_TYPE)
2573 {
2574 aconf = map_to_conf(conf);
2575
2576 if (aconf->clients != 0)
2577 {
2578 SetConfIllegal(aconf);
2579 dlinkDelete(&conf->node, &oconf_items);
2580 }
2581 else
2582 {
2583 delete_conf_item(conf);
2584 }
2585 }
2586 else if (conf->type == CLIENT_TYPE)
2587 {
2588 aconf = map_to_conf(conf);
2589
2590 if (aconf->clients != 0)
2591 {
2592 SetConfIllegal(aconf);
2593 }
2594 else
2595 {
2596 delete_conf_item(conf);
2597 }
2598 }
2599 else if (conf->type == XLINE_TYPE ||
2600 conf->type == RXLINE_TYPE ||
2601 conf->type == RKLINE_TYPE)
2602 {
2603 /* temporary (r)xlines are also on
2604 * the (r)xconf items list */
2605 if (conf->flags & CONF_FLAGS_TEMPORARY)
2606 continue;
2607
2608 delete_conf_item(conf);
2609 }
2610 else
2611 {
2612 if ((conf->type == LEAF_TYPE) || (conf->type == HUB_TYPE))
2613 {
2614 match_item = map_to_conf(conf);
2615 if (match_item->ref_count <= 0)
2616 delete_conf_item(conf);
2617 else
2618 {
2619 match_item->illegal = 1;
2620 dlinkDelete(&conf->node, *iterator);
2621 }
2622 }
2623 else
2624 delete_conf_item(conf);
2625 }
2626 }
2627 }
2628
2629 /*
2630 * don't delete the class table, rather mark all entries
2631 * for deletion. The table is cleaned up by check_class. - avalon
2632 */
2633 DLINK_FOREACH(ptr, class_items.head)
2634 {
2635 cltmp = map_to_conf(ptr->data);
2636
2637 if (ptr != class_items.tail) /* never mark the "default" class */
2638 cltmp->active = 0;
2639 }
2640
2641 clear_out_address_conf();
2642
2643 /* clean out module paths */
2644 #ifndef STATIC_MODULES
2645 mod_clear_paths();
2646 #endif
2647
2648 /* clean out ServerInfo */
2649 MyFree(ServerInfo.description);
2650 ServerInfo.description = NULL;
2651 MyFree(ServerInfo.network_name);
2652 ServerInfo.network_name = NULL;
2653 MyFree(ServerInfo.network_desc);
2654 ServerInfo.network_desc = NULL;
2655 MyFree(ConfigFileEntry.egdpool_path);
2656 ConfigFileEntry.egdpool_path = NULL;
2657 #ifdef HAVE_LIBCRYPTO
2658 if (ServerInfo.rsa_private_key != NULL)
2659 {
2660 RSA_free(ServerInfo.rsa_private_key);
2661 ServerInfo.rsa_private_key = NULL;
2662 }
2663
2664 MyFree(ServerInfo.rsa_private_key_file);
2665 ServerInfo.rsa_private_key_file = NULL;
2666 #endif
2667
2668 /* clean out old resvs from the conf */
2669 clear_conf_resv();
2670
2671 /* clean out AdminInfo */
2672 MyFree(AdminInfo.name);
2673 AdminInfo.name = NULL;
2674 MyFree(AdminInfo.email);
2675 AdminInfo.email = NULL;
2676 MyFree(AdminInfo.description);
2677 AdminInfo.description = NULL;
2678
2679 /* operator{} and class{} blocks are freed above */
2680 /* clean out listeners */
2681 close_listeners();
2682
2683 /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2684 * exempt{} and gecos{} blocks are freed above too
2685 */
2686
2687 /* clean out general */
2688 MyFree(ConfigFileEntry.servlink_path);
2689 ConfigFileEntry.servlink_path = NULL;
2690 #ifdef HAVE_LIBCRYPTO
2691 ConfigFileEntry.default_cipher_preference = NULL;
2692 #endif /* HAVE_LIBCRYPTO */
2693 delete_isupport("INVEX");
2694 delete_isupport("EXCEPTS");
2695 }
2696
2697 /* flush_deleted_I_P()
2698 *
2699 * inputs - none
2700 * output - none
2701 * side effects - This function removes I/P conf items
2702 */
2703 static void
2704 flush_deleted_I_P(void)
2705 {
2706 dlink_node *ptr;
2707 dlink_node *next_ptr;
2708 struct ConfItem *conf;
2709 struct AccessItem *aconf;
2710 dlink_list * free_items [] = {
2711 &server_items, &oconf_items, NULL
2712 };
2713 dlink_list ** iterator = free_items; /* C is dumb */
2714
2715 /* flush out deleted I and P lines
2716 * although still in use.
2717 */
2718 for (; *iterator != NULL; iterator++)
2719 {
2720 DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2721 {
2722 conf = ptr->data;
2723 aconf = (struct AccessItem *)map_to_conf(conf);
2724
2725 if (IsConfIllegal(aconf))
2726 {
2727 dlinkDelete(ptr, *iterator);
2728
2729 if (aconf->clients == 0)
2730 delete_conf_item(conf);
2731 }
2732 }
2733 }
2734 }
2735
2736 /* get_conf_name()
2737 *
2738 * inputs - type of conf file to return name of file for
2739 * output - pointer to filename for type of conf
2740 * side effects - none
2741 */
2742 const char *
2743 get_conf_name(ConfType type)
2744 {
2745 switch (type)
2746 {
2747 case CONF_TYPE:
2748 return ConfigFileEntry.configfile;
2749 break;
2750 case KLINE_TYPE:
2751 return ConfigFileEntry.klinefile;
2752 break;
2753 case RKLINE_TYPE:
2754 return ConfigFileEntry.rklinefile;
2755 break;
2756 case DLINE_TYPE:
2757 return ConfigFileEntry.dlinefile;
2758 break;
2759 case XLINE_TYPE:
2760 return ConfigFileEntry.xlinefile;
2761 break;
2762 case RXLINE_TYPE:
2763 return ConfigFileEntry.rxlinefile;
2764 break;
2765 case CRESV_TYPE:
2766 return ConfigFileEntry.cresvfile;
2767 break;
2768 case NRESV_TYPE:
2769 return ConfigFileEntry.nresvfile;
2770 break;
2771 case GLINE_TYPE:
2772 return ConfigFileEntry.glinefile;
2773 break;
2774
2775 default:
2776 return NULL; /* This should NEVER HAPPEN since we call this function
2777 only with the above values, this will cause us to core
2778 at some point if this happens so we know where it was */
2779 }
2780 }
2781
2782 #define BAD_PING (-1)
2783
2784 /* get_conf_ping()
2785 *
2786 * inputs - pointer to struct AccessItem
2787 * - pointer to a variable that receives ping warning time
2788 * output - ping frequency
2789 * side effects - NONE
2790 */
2791 static int
2792 get_conf_ping(struct ConfItem *conf, int *pingwarn)
2793 {
2794 struct ClassItem *aclass;
2795 struct AccessItem *aconf;
2796
2797 if (conf != NULL)
2798 {
2799 aconf = (struct AccessItem *)map_to_conf(conf);
2800 if (aconf->class_ptr != NULL)
2801 {
2802 aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2803 *pingwarn = PingWarning(aclass);
2804 return PingFreq(aclass);
2805 }
2806 }
2807
2808 return BAD_PING;
2809 }
2810
2811 /* get_client_class()
2812 *
2813 * inputs - pointer to client struct
2814 * output - pointer to name of class
2815 * side effects - NONE
2816 */
2817 const char *
2818 get_client_class(struct Client *target_p)
2819 {
2820 dlink_node *ptr;
2821 struct ConfItem *conf;
2822 struct AccessItem *aconf;
2823
2824 if (target_p != NULL && !IsMe(target_p) &&
2825 target_p->localClient->confs.head != NULL)
2826 {
2827 DLINK_FOREACH(ptr, target_p->localClient->confs.head)
2828 {
2829 conf = ptr->data;
2830
2831 if (conf->type == CLIENT_TYPE || conf->type == SERVER_TYPE ||
2832 conf->type == OPER_TYPE)
2833 {
2834 aconf = (struct AccessItem *) map_to_conf(conf);
2835 if (aconf->class_ptr != NULL)
2836 return aconf->class_ptr->name;
2837 }
2838 }
2839 }
2840
2841 return "default";
2842 }
2843
2844 /* get_client_ping()
2845 *
2846 * inputs - pointer to client struct
2847 * - pointer to a variable that receives ping warning time
2848 * output - ping frequency
2849 * side effects - NONE
2850 */
2851 int
2852 get_client_ping(struct Client *target_p, int *pingwarn)
2853 {
2854 int ping;
2855 struct ConfItem *conf;
2856 dlink_node *nlink;
2857
2858 if (target_p->localClient->confs.head != NULL)
2859 DLINK_FOREACH(nlink, target_p->localClient->confs.head)
2860 {
2861 conf = nlink->data;
2862
2863 if ((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2864 (conf->type == OPER_TYPE))
2865 {
2866 ping = get_conf_ping(conf, pingwarn);
2867 if (ping > 0)
2868 return ping;
2869 }
2870 }
2871
2872 *pingwarn = 0;
2873 return DEFAULT_PINGFREQUENCY;
2874 }
2875
2876 /* find_class()
2877 *
2878 * inputs - string name of class
2879 * output - corresponding Class pointer
2880 * side effects - NONE
2881 */
2882 struct ConfItem *
2883 find_class(const char *classname)
2884 {
2885 struct ConfItem *conf;
2886
2887 if ((conf = find_exact_name_conf(CLASS_TYPE, classname, NULL, NULL)) != NULL)
2888 return conf;
2889
2890 return class_default;
2891 }
2892
2893 /* check_class()
2894 *
2895 * inputs - NONE
2896 * output - NONE
2897 * side effects -
2898 */
2899 void
2900 check_class(void)
2901 {
2902 dlink_node *ptr = NULL, *next_ptr = NULL;
2903
2904 DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2905 {
2906 struct ClassItem *aclass = map_to_conf(ptr->data);
2907
2908 if (!aclass->active && !CurrUserCount(aclass))
2909 {
2910 destroy_cidr_class(aclass);
2911 delete_conf_item(ptr->data);
2912 }
2913 }
2914 }
2915
2916 /* init_class()
2917 *
2918 * inputs - NONE
2919 * output - NONE
2920 * side effects -
2921 */
2922 void
2923 init_class(void)
2924 {
2925 struct ClassItem *aclass;
2926
2927 class_default = make_conf_item(CLASS_TYPE);
2928
2929 aclass = map_to_conf(class_default);
2930 aclass->active = 1;
2931 DupString(class_default->name, "default");
2932 ConFreq(aclass) = DEFAULT_CONNECTFREQUENCY;
2933 PingFreq(aclass) = DEFAULT_PINGFREQUENCY;
2934 MaxTotal(aclass) = MAXIMUM_LINKS_DEFAULT;
2935 MaxSendq(aclass) = DEFAULT_SENDQ;
2936
2937 client_check_cb = register_callback("check_client", check_client);
2938 }
2939
2940 /* get_sendq()
2941 *
2942 * inputs - pointer to client
2943 * output - sendq for this client as found from its class
2944 * side effects - NONE
2945 */
2946 unsigned int
2947 get_sendq(struct Client *client_p)
2948 {
2949 unsigned int sendq = DEFAULT_SENDQ;
2950 dlink_node *ptr;
2951 struct ConfItem *conf;
2952 struct ConfItem *class_conf;
2953 struct ClassItem *aclass;
2954 struct AccessItem *aconf;
2955
2956 if (client_p && !IsMe(client_p) && (client_p->localClient->confs.head))
2957 {
2958 DLINK_FOREACH(ptr, client_p->localClient->confs.head)
2959 {
2960 conf = ptr->data;
2961 if ((conf->type == SERVER_TYPE) || (conf->type == OPER_TYPE)
2962 || (conf->type == CLIENT_TYPE))
2963 {
2964 aconf = (struct AccessItem *)map_to_conf(conf);
2965 if ((class_conf = aconf->class_ptr) == NULL)
2966 continue;
2967 aclass = (struct ClassItem *)map_to_conf(class_conf);
2968 sendq = MaxSendq(aclass);
2969 return sendq;
2970 }
2971 }
2972 }
2973 /* XXX return a default?
2974 * if here, then there wasn't an attached conf with a sendq
2975 * that is very bad -Dianora
2976 */
2977 return DEFAULT_SENDQ;
2978 }
2979
2980 /* conf_add_class_to_conf()
2981 *
2982 * inputs - pointer to config item
2983 * output - NONE
2984 * side effects - Add a class pointer to a conf
2985 */
2986 void
2987 conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
2988 {
2989 struct AccessItem *aconf = map_to_conf(conf);
2990 struct ClassItem *class = NULL;
2991
2992 if (class_name == NULL)
2993 {
2994 aconf->class_ptr = class_default;
2995
2996 if (conf->type == CLIENT_TYPE)
2997 sendto_realops_flags(UMODE_ALL, L_ALL,
2998 "Warning *** Defaulting to default class for %s@%s",
2999 aconf->user, aconf->host);
3000 else
3001 sendto_realops_flags(UMODE_ALL, L_ALL,
3002 "Warning *** Defaulting to default class for %s",
3003 conf->name);
3004 }
3005 else
3006 aconf->class_ptr = find_class(class_name);
3007
3008 if (aconf->class_ptr)
3009 class = map_to_conf(aconf->class_ptr);
3010
3011 if (aconf->class_ptr == NULL || !class->active)
3012 {
3013 if (conf->type == CLIENT_TYPE)
3014 sendto_realops_flags(UMODE_ALL, L_ALL,
3015 "Warning *** Defaulting to default class for %s@%s",
3016 aconf->user, aconf->host);
3017 else
3018 sendto_realops_flags(UMODE_ALL, L_ALL,
3019 "Warning *** Defaulting to default class for %s",
3020 conf->name);
3021 aconf->class_ptr = class_default;
3022 }
3023 }
3024
3025 /* conf_add_server()
3026 *
3027 * inputs - pointer to config item
3028 * - pointer to link count already on this conf
3029 * output - NONE
3030 * side effects - Add a connect block
3031 */
3032 int
3033 conf_add_server(struct ConfItem *conf, const char *class_name)
3034 {
3035 struct AccessItem *aconf;
3036 struct split_nuh_item nuh;
3037 char conf_user[USERLEN + 1];
3038 char conf_host[HOSTLEN + 1];
3039
3040 aconf = map_to_conf(conf);
3041
3042 conf_add_class_to_conf(conf, class_name);
3043
3044 if (!aconf->host || !conf->name)
3045 {
3046 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
3047 ilog(L_WARN, "Bad connect block");
3048 return -1;
3049 }
3050
3051 if (EmptyString(aconf->passwd) && !IsConfCryptLink(aconf))
3052 {
3053 sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
3054 conf->name);
3055 ilog(L_WARN, "Bad connect block, host %s", conf->name);
3056 return -1;
3057 }
3058
3059 nuh.nuhmask = aconf->host;
3060 nuh.nickptr = NULL;
3061 nuh.userptr = conf_user;
3062 nuh.hostptr = conf_host;
3063
3064 nuh.nicksize = 0;
3065 nuh.usersize = sizeof(conf_user);
3066 nuh.hostsize = sizeof(conf_host);
3067
3068 split_nuh(&nuh);
3069
3070 MyFree(aconf->host);
3071 aconf->host = NULL;
3072
3073 DupString(aconf->user, conf_user); /* somehow username checking for servers
3074 got lost in H6/7, will have to be re-added */
3075 DupString(aconf->host, conf_host);
3076
3077 lookup_confhost(conf);
3078
3079 return 0;
3080 }
3081
3082 /* conf_add_d_conf()
3083 *
3084 * inputs - pointer to config item
3085 * output - NONE
3086 * side effects - Add a d/D line
3087 */
3088 void
3089 conf_add_d_conf(struct AccessItem *aconf)
3090 {
3091 if (aconf->host == NULL)
3092 return;
3093
3094 aconf->user = NULL;
3095
3096 /* XXX - Should 'd' ever be in the old conf? For new conf we don't
3097 * need this anyway, so I will disable it for now... -A1kmm
3098 */
3099 if (parse_netmask(aconf->host, NULL, NULL) == HM_HOST)
3100 {
3101 ilog(L_WARN, "Invalid Dline %s ignored", aconf->host);
3102 free_access_item(aconf);
3103 }
3104 else
3105 {
3106 /* XXX ensure user is NULL */
3107 MyFree(aconf->user);
3108 aconf->user = NULL;
3109 add_conf_by_address(CONF_DLINE, aconf);
3110 }
3111 }
3112
3113 /* yyerror()
3114 *
3115 * inputs - message from parser
3116 * output - NONE
3117 * side effects - message to opers and log file entry is made
3118 */
3119 void
3120 yyerror(const char *msg)
3121 {
3122 char newlinebuf[IRCD_BUFSIZE];
3123
3124 if (ypass != 1)
3125 return;
3126
3127 strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
3128 sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
3129 conffilebuf, lineno + 1, msg, newlinebuf);
3130 ilog(L_WARN, "\"%s\", line %u: %s: %s",
3131 conffilebuf, lineno + 1, msg, newlinebuf);
3132 }
3133
3134 int
3135 conf_fbgets(char *lbuf, unsigned int max_size, FBFILE *fb)
3136 {
3137 if (fbgets(lbuf, max_size, fb) == NULL)
3138 return 0;
3139
3140 return strlen(lbuf);
3141 }
3142
3143 int
3144 conf_yy_fatal_error(const char *msg)
3145 {
3146 return 0;
3147 }
3148
3149 /*
3150 * valid_tkline()
3151 *
3152 * inputs - pointer to ascii string to check
3153 * - whether the specified time is in seconds or minutes
3154 * output - -1 not enough parameters
3155 * - 0 if not an integer number, else the number
3156 * side effects - none
3157 * Originally written by Dianora (Diane, db@db.net)
3158 */
3159 time_t
3160 valid_tkline(char *p, int minutes)
3161 {
3162 time_t result = 0;
3163
3164 while (*p)
3165 {
3166 if (IsDigit(*p))
3167 {
3168 result *= 10;
3169 result += ((*p) & 0xF);
3170 p++;
3171 }
3172 else
3173 return 0;
3174 }
3175
3176 /* in the degenerate case where oper does a /quote kline 0 user@host :reason
3177 * i.e. they specifically use 0, I am going to return 1 instead
3178 * as a return value of non-zero is used to flag it as a temporary kline
3179 */
3180
3181 if (result == 0)
3182 result = 1;
3183
3184 /*
3185 * If the incoming time is in seconds convert it to minutes for the purpose
3186 * of this calculation
3187 */
3188 if (!minutes)
3189 result = result / (time_t)60;
3190
3191 if (result > MAX_TDKLINE_TIME)
3192 result = MAX_TDKLINE_TIME;
3193
3194 result = result * (time_t)60; /* turn it into seconds */
3195
3196 return result;
3197 }
3198
3199 /* valid_wild_card()
3200 *
3201 * input - pointer to client
3202 * - int flag, 0 for no warning oper 1 for warning oper
3203 * - count of following varargs to check
3204 * output - 0 if not valid, 1 if valid
3205 * side effects - NOTICE is given to source_p if warn is 1
3206 */
3207 int
3208 valid_wild_card(struct Client *source_p, int warn, int count, ...)
3209 {
3210 char *p;
3211 char tmpch;
3212 int nonwild = 0;
3213 va_list args;
3214
3215 /*
3216 * Now we must check the user and host to make sure there
3217 * are at least NONWILDCHARS non-wildcard characters in
3218 * them, otherwise assume they are attempting to kline
3219 * *@* or some variant of that. This code will also catch
3220 * people attempting to kline *@*.tld, as long as NONWILDCHARS
3221 * is greater than 3. In that case, there are only 3 non-wild
3222 * characters (tld), so if NONWILDCHARS is 4, the kline will
3223 * be disallowed.
3224 * -wnder
3225 */
3226
3227 va_start(args, count);
3228
3229 while (count--)
3230 {
3231 p = va_arg(args, char *);
3232 if (p == NULL)
3233 continue;
3234
3235 while ((tmpch = *p++))
3236 {
3237 if (!IsKWildChar(tmpch))
3238 {
3239 /*
3240 * If we find enough non-wild characters, we can
3241 * break - no point in searching further.
3242 */
3243 if (++nonwild >= ConfigFileEntry.min_nonwildcard)
3244 return 1;
3245 }
3246 }
3247 }
3248
3249 if (warn)
3250 sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
3251 me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
3252 return 0;
3253 }
3254
3255 /* XXX should this go into a separate file ? -Dianora */
3256 /* parse_aline
3257 *
3258 * input - pointer to cmd name being used
3259 * - pointer to client using cmd
3260 * - parc parameter count
3261 * - parv[] list of parameters to parse
3262 * - parse_flags bit map of things to test
3263 * - pointer to user or string to parse into
3264 * - pointer to host or NULL to parse into if non NULL
3265 * - pointer to optional tkline time or NULL
3266 * - pointer to target_server to parse into if non NULL
3267 * - pointer to reason to parse into
3268 *
3269 * output - 1 if valid, -1 if not valid
3270 * side effects - A generalised k/d/x etc. line parser,
3271 * "ALINE [time] user@host|string [ON] target :reason"
3272 * will parse returning a parsed user, host if
3273 * h_p pointer is non NULL, string otherwise.
3274 * if tkline_time pointer is non NULL a tk line will be set
3275 * to non zero if found.
3276 * if tkline_time pointer is NULL and tk line is found,
3277 * error is reported.
3278 * if target_server is NULL and an "ON" is found error
3279 * is reported.
3280 * if reason pointer is NULL ignore pointer,
3281 * this allows use of parse_a_line in unkline etc.
3282 *
3283 * - Dianora
3284 */
3285 int
3286 parse_aline(const char *cmd, struct Client *source_p,
3287 int parc, char **parv,
3288 int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
3289 char **target_server, char **reason)
3290 {
3291 int found_tkline_time=0;
3292 static char def_reason[] = "No Reason";
3293 static char user[USERLEN*4+1];
3294 static char host[HOSTLEN*4+1];
3295
3296 parv++;
3297 parc--;
3298
3299 found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3300
3301 if (found_tkline_time != 0)
3302 {
3303 parv++;
3304 parc--;
3305
3306 if (tkline_time != NULL)
3307 *tkline_time = found_tkline_time;
3308 else
3309 {
3310 sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3311 me.name, source_p->name, cmd);
3312 return -1;
3313 }
3314 }
3315
3316 if (parc == 0)
3317 {
3318 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3319 me.name, source_p->name, cmd);
3320 return -1;
3321 }
3322
3323 if (h_p == NULL)
3324 *up_p = *parv;
3325 else
3326 {
3327 if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3328 return -1;
3329
3330 *up_p = user;
3331 *h_p = host;
3332 }
3333
3334 parc--;
3335 parv++;
3336
3337 if (parc != 0)
3338 {
3339 if (irccmp(*parv, "ON") == 0)
3340 {
3341 parc--;
3342 parv++;
3343
3344 if (target_server == NULL)
3345 {
3346 sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3347 me.name, source_p->name, cmd);
3348 return -1;
3349 }
3350
3351 if (!IsOperRemoteBan(source_p))
3352 {
3353 sendto_one(source_p, form_str(ERR_NOPRIVS),
3354 me.name, source_p->name, "remoteban");
3355 return -1;
3356 }
3357
3358 if (parc == 0 || EmptyString(*parv))
3359 {
3360 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3361 me.name, source_p->name, cmd);
3362 return -1;
3363 }
3364
3365 *target_server = *parv;
3366 parc--;
3367 parv++;
3368 }
3369 else
3370 {
3371 /* Make sure target_server *is* NULL if no ON server found
3372 * caller probably NULL'd it first, but no harm to do it again -db
3373 */
3374 if (target_server != NULL)
3375 *target_server = NULL;
3376 }
3377 }
3378
3379 if (h_p != NULL)
3380 {
3381 if (strchr(user, '!') != NULL)
3382 {
3383 sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3384 me.name, source_p->name);
3385 return -1;
3386 }
3387
3388 if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 2, *up_p, *h_p))
3389 return -1;
3390 }
3391 else
3392 if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 1, *up_p))
3393 return -1;
3394
3395 if (reason != NULL)
3396 {
3397 if (parc != 0 && !EmptyString(*parv))
3398 {
3399 *reason = *parv;
3400 if (!valid_comment(source_p, *reason, YES))
3401 return -1;
3402 }
3403 else
3404 *reason = def_reason;
3405 }
3406
3407 return 1;
3408 }
3409
3410 /* find_user_host()
3411 *
3412 * inputs - pointer to client placing kline
3413 * - pointer to user_host_or_nick
3414 * - pointer to user buffer
3415 * - pointer to host buffer
3416 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3417 * side effects -
3418 */
3419 static int
3420 find_user_host(struct Client *source_p, char *user_host_or_nick,
3421 char *luser, char *lhost, unsigned int flags)
3422 {
3423 struct Client *target_p = NULL;
3424 char *hostp = NULL;
3425
3426 if (lhost == NULL)
3427 {
3428 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3429 return 1;
3430 }
3431
3432 if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3433 {
3434 /* Explicit user@host mask given */
3435
3436 if (hostp != NULL) /* I'm a little user@host */
3437 {
3438 *(hostp++) = '\0'; /* short and squat */
3439 if (*user_host_or_nick)
3440 strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3441 else
3442 strcpy(luser, "*");
3443 if (*hostp)
3444 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3445 else
3446 strcpy(lhost, "*");
3447 }
3448 else
3449 {
3450 luser[0] = '*'; /* no @ found, assume its *@somehost */
3451 luser[1] = '\0';
3452 strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3453 }
3454
3455 return 1;
3456 }
3457 else if (!(flags & NOUSERLOOKUP))
3458 {
3459 /* Try to find user@host mask from nick */
3460 /* Okay to use source_p as the first param, because source_p == client_p */
3461 if ((target_p =
3462 find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3463 return 0;
3464
3465 if (IsExemptKline(target_p))
3466 {
3467 if (!IsServer(source_p))
3468 sendto_one(source_p,
3469 ":%s NOTICE %s :%s is E-lined",
3470 me.name, source_p->name, target_p->name);
3471 return 0;
3472 }
3473
3474 /*
3475 * turn the "user" bit into "*user", blow away '~'
3476 * if found in original user name (non-idented)
3477 */
3478 strlcpy(luser, target_p->username, USERLEN*4 + 1);
3479
3480 if (target_p->username[0] == '~')
3481 luser[0] = '*';
3482
3483 if (target_p->sockhost[0] == '\0' ||
3484 (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3485 strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3486 else
3487 strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3488 return 1;
3489 }
3490
3491 return 0;
3492 }
3493
3494 /* valid_comment()
3495 *
3496 * inputs - pointer to client
3497 * - pointer to comment
3498 * output - 0 if no valid comment,
3499 * - 1 if valid
3500 * side effects - truncates reason where necessary
3501 */
3502 int
3503 valid_comment(struct Client *source_p, char *comment, int warn)
3504 {
3505 if (strchr(comment, '"'))
3506 {
3507 if (warn)
3508 sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3509 me.name, source_p->name);
3510 return 0;
3511 }
3512
3513 if (strlen(comment) > REASONLEN)
3514 comment[REASONLEN-1] = '\0';
3515
3516 return 1;
3517 }
3518
3519 /* match_conf_password()
3520 *
3521 * inputs - pointer to given password
3522 * - pointer to Conf
3523 * output - 1 or 0 if match
3524 * side effects - none
3525 */
3526 int
3527 match_conf_password(const char *password, const struct AccessItem *aconf)
3528 {
3529 const char *encr = NULL;
3530
3531 if (password == NULL || aconf->passwd == NULL)
3532 return 0;
3533
3534 if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3535 {
3536 /* use first two chars of the password they send in as salt */
3537 /* If the password in the conf is MD5, and ircd is linked
3538 * to scrypt on FreeBSD, or the standard crypt library on
3539 * glibc Linux, then this code will work fine on generating
3540 * the proper encrypted hash for comparison.
3541 */
3542 if (*aconf->passwd)
3543 encr = crypt(password, aconf->passwd);
3544 else
3545 encr = "";
3546 }
3547 else
3548 encr = password;
3549
3550 return !strcmp(encr, aconf->passwd);
3551 }
3552
3553 /*
3554 * cluster_a_line
3555 *
3556 * inputs - client sending the cluster
3557 * - command name "KLINE" "XLINE" etc.
3558 * - capab -- CAP_KLN etc. from s_serv.h
3559 * - cluster type -- CLUSTER_KLINE etc. from s_conf.h
3560 * - pattern and args to send along
3561 * output - none
3562 * side effects - Take source_p send the pattern with args given
3563 * along to all servers that match capab and cluster type
3564 */
3565 void
3566 cluster_a_line(struct Client *source_p, const char *command,
3567 int capab, int cluster_type, const char *pattern, ...)
3568 {
3569 va_list args;
3570 char buffer[IRCD_BUFSIZE];
3571 const dlink_node *ptr = NULL;
3572
3573 va_start(args, pattern);
3574 vsnprintf(buffer, sizeof(buffer), pattern, args);
3575 va_end(args);
3576
3577 DLINK_FOREACH(ptr, cluster_items.head)
3578 {
3579 const struct ConfItem *conf = ptr->data;
3580
3581 if (conf->flags & cluster_type)
3582 sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3583 "%s %s %s", command, conf->name, buffer);
3584 }
3585 }
3586
3587 /*
3588 * split_nuh
3589 *
3590 * inputs - pointer to original mask (modified in place)
3591 * - pointer to pointer where nick should go
3592 * - pointer to pointer where user should go
3593 * - pointer to pointer where host should go
3594 * output - NONE
3595 * side effects - mask is modified in place
3596 * If nick pointer is NULL, ignore writing to it
3597 * this allows us to use this function elsewhere.
3598 *
3599 * mask nick user host
3600 * ---------------------- ------- ------- ------
3601 * Dianora!db@db.net Dianora db db.net
3602 * Dianora Dianora * *
3603 * db.net * * db.net
3604 * OR if nick pointer is NULL
3605 * Dianora - * Dianora
3606 * Dianora! Dianora * *
3607 * Dianora!@ Dianora * *
3608 * Dianora!db Dianora db *
3609 * Dianora!@db.net Dianora * db.net
3610 * db@db.net * db db.net
3611 * !@ * * *
3612 * @ * * *
3613 * ! * * *
3614 */
3615 void
3616 split_nuh(struct split_nuh_item *const iptr)
3617 {
3618 char *p = NULL, *q = NULL;
3619
3620 if (iptr->nickptr)
3621 strlcpy(iptr->nickptr, "*", iptr->nicksize);
3622 if (iptr->userptr)
3623 strlcpy(iptr->userptr, "*", iptr->usersize);
3624 if (iptr->hostptr)
3625 strlcpy(iptr->hostptr, "*", iptr->hostsize);
3626
3627 if ((p = strchr(iptr->nuhmask, '!')))
3628 {
3629 *p = '\0';
3630
3631 if (iptr->nickptr && *iptr->nuhmask != '\0')
3632 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3633
3634 if ((q = strchr(++p, '@'))) {
3635 *q++ = '\0';
3636
3637 if (*p != '\0')
3638 strlcpy(iptr->userptr, p, iptr->usersize);
3639
3640 if (*q != '\0')
3641 strlcpy(iptr->hostptr, q, iptr->hostsize);
3642 }
3643 else
3644 {
3645 if (*p != '\0')
3646 strlcpy(iptr->userptr, p, iptr->usersize);
3647 }
3648 }
3649 else
3650 {
3651 /* No ! found so lets look for a user@host */
3652 if ((p = strchr(iptr->nuhmask, '@')))
3653 {
3654 /* if found a @ */
3655 *p++ = '\0';
3656
3657 if (*iptr->nuhmask != '\0')
3658 strlcpy(iptr->userptr, iptr->nuhmask, iptr->usersize);
3659
3660 if (*p != '\0')
3661 strlcpy(iptr->hostptr, p, iptr->hostsize);
3662 }
3663 else
3664 {
3665 /* no @ found */
3666 if (!iptr->nickptr || strpbrk(iptr->nuhmask, ".:"))
3667 strlcpy(iptr->hostptr, iptr->nuhmask, iptr->hostsize);
3668 else
3669 strlcpy(iptr->nickptr, iptr->nuhmask, iptr->nicksize);
3670 }
3671 }
3672 }
3673
3674 /*
3675 * flags_to_ascii
3676 *
3677 * inputs - flags is a bitmask
3678 * - pointer to table of ascii letters corresponding
3679 * to each bit
3680 * - flag 1 for convert ToLower if bit missing
3681 * 0 if ignore.
3682 * output - none
3683 * side effects - string pointed to by p has bitmap chars written to it
3684 */
3685 static void
3686 flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3687 int lowerit)
3688 {
3689 unsigned int mask = 1;
3690 int i = 0;
3691
3692 for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3693 {
3694 if (flags & mask)
3695 *p++ = bit_table[i];
3696 else if (lowerit)
3697 *p++ = ToLower(bit_table[i]);
3698 }
3699 *p = '\0';
3700 }
3701
3702 /*
3703 * cidr_limit_reached
3704 *
3705 * inputs - int flag allowing over_rule of limits
3706 * - pointer to the ip to be added
3707 * - pointer to the class
3708 * output - non zero if limit reached
3709 * 0 if limit not reached
3710 * side effects -
3711 */
3712 static int
3713 cidr_limit_reached(int over_rule,
3714 struct irc_ssaddr *ip, struct ClassItem *aclass)
3715 {
3716 dlink_node *ptr = NULL;
3717 struct CidrItem *cidr;
3718
3719 if (NumberPerCidr(aclass) <= 0)
3720 return 0;
3721
3722 if (ip->ss.ss_family == AF_INET)
3723 {
3724 if (CidrBitlenIPV4(aclass) <= 0)
3725 return 0;
3726
3727 DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3728 {
3729 cidr = ptr->data;
3730 if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3731 {
3732 if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3733 return -1;
3734 cidr->number_on_this_cidr++;
3735 return 0;
3736 }
3737 }
3738 cidr = MyMalloc(sizeof(struct CidrItem));
3739 cidr->number_on_this_cidr = 1;
3740 cidr->mask = *ip;
3741 mask_addr(&cidr->mask, CidrBitlenIPV4(aclass));
3742 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3743 }
3744 #ifdef IPV6
3745 else if (CidrBitlenIPV6(aclass) > 0)
3746 {
3747 DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3748 {
3749 cidr = ptr->data;
3750 if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3751 {
3752 if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3753 return -1;
3754 cidr->number_on_this_cidr++;
3755 return 0;
3756 }
3757 }
3758 cidr = MyMalloc(sizeof(struct CidrItem));
3759 cidr->number_on_this_cidr = 1;
3760 cidr->mask = *ip;
3761 mask_addr(&cidr->mask, CidrBitlenIPV6(aclass));
3762 dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3763 }
3764 #endif
3765 return 0;
3766 }
3767
3768 /*
3769 * remove_from_cidr_check
3770 *
3771 * inputs - pointer to the ip to be removed
3772 * - pointer to the class
3773 * output - NONE
3774 * side effects -
3775 */
3776 static void
3777 remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3778 {
3779 dlink_node *ptr = NULL;
3780 dlink_node *next_ptr = NULL;
3781 struct CidrItem *cidr;
3782
3783 if (NumberPerCidr(aclass) == 0)
3784 return;
3785
3786 if (ip->ss.ss_family == AF_INET)
3787 {
3788 if (CidrBitlenIPV4(aclass) <= 0)
3789 return;
3790
3791 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3792 {
3793 cidr = ptr->data;
3794 if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3795 {
3796 cidr->number_on_this_cidr--;
3797 if (cidr->number_on_this_cidr == 0)
3798 {
3799 dlinkDelete(ptr, &aclass->list_ipv4);
3800 MyFree(cidr);
3801 return;
3802 }
3803 }
3804 }
3805 }
3806 #ifdef IPV6
3807 else if (CidrBitlenIPV6(aclass) > 0)
3808 {
3809 DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3810 {
3811 cidr = ptr->data;
3812 if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3813 {
3814 cidr->number_on_this_cidr--;
3815 if (cidr->number_on_this_cidr == 0)
3816 {
3817 dlinkDelete(ptr, &aclass->list_ipv6);
3818 MyFree(cidr);
3819 return;
3820 }
3821 }
3822 }
3823 }
3824 #endif
3825 }
3826
3827 static void
3828 rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3829 dlink_list *old_list, dlink_list *new_list, int changed)
3830 {
3831 dlink_node *ptr;
3832 struct Client *client_p;
3833 struct ConfItem *conf;
3834 struct AccessItem *aconf;
3835
3836 if (!changed)
3837 {
3838 *new_list = *old_list;
3839 old_list->head = old_list->tail = NULL;
3840 old_list->length = 0;
3841 return;
3842 }
3843
3844 DLINK_FOREACH(ptr, local_client_list.head)
3845 {
3846 client_p = ptr->data;
3847 if (client_p->localClient->aftype != aftype)
3848 continue;
3849 if (dlink_list_length(&client_p->localClient->confs) == 0)
3850 continue;
3851
3852 conf = client_p->localClient->confs.tail->data;
3853 if (conf->type == CLIENT_TYPE)
3854 {
3855 aconf = map_to_conf(conf);
3856 if (aconf->class_ptr == oldcl)
3857 cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3858 }
3859 }
3860 }
3861
3862 /*
3863 * rebuild_cidr_class
3864 *
3865 * inputs - pointer to old conf
3866 * - pointer to new_class
3867 * output - none
3868 * side effects - rebuilds the class link list of cidr blocks
3869 */
3870 void
3871 rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3872 {
3873 struct ClassItem *old_class = map_to_conf(conf);
3874
3875 if (NumberPerCidr(old_class) > 0 && NumberPerCidr(new_class) > 0)
3876 {
3877 if (CidrBitlenIPV4(old_class) > 0 && CidrBitlenIPV4(new_class) > 0)
3878 rebuild_cidr_list(AF_INET, conf, new_class,
3879 &old_class->list_ipv4, &new_class->list_ipv4,
3880 CidrBitlenIPV4(old_class) != CidrBitlenIPV4(new_class));
3881
3882 #ifdef IPV6
3883 if (CidrBitlenIPV6(old_class) > 0 && CidrBitlenIPV6(new_class) > 0)
3884 rebuild_cidr_list(AF_INET6, conf, new_class,
3885 &old_class->list_ipv6, &new_class->list_ipv6,
3886 CidrBitlenIPV6(old_class) != CidrBitlenIPV6(new_class));
3887 #endif
3888 }
3889
3890 destroy_cidr_class(old_class);
3891 }
3892
3893 /*
3894 * destroy_cidr_list
3895 *
3896 * inputs - pointer to class dlink list of cidr blocks
3897 * output - none
3898 * side effects - completely destroys the class link list of cidr blocks
3899 */
3900 static void
3901 destroy_cidr_list(dlink_list *list)
3902 {
3903 dlink_node *ptr = NULL, *next_ptr = NULL;
3904
3905 DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3906 {
3907 dlinkDelete(ptr, list);
3908 MyFree(ptr->data);
3909 }
3910 }
3911
3912 /*
3913 * destroy_cidr_class
3914 *
3915 * inputs - pointer to class
3916 * output - none
3917 * side effects - completely destroys the class link list of cidr blocks
3918 */
3919 static void
3920 destroy_cidr_class(struct ClassItem *aclass)
3921 {
3922 destroy_cidr_list(&aclass->list_ipv4);
3923 destroy_cidr_list(&aclass->list_ipv6);
3924 }

Properties

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