ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/conf.c
Revision: 672
Committed: Tue Jun 13 07:28:30 2006 UTC (17 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100897 byte(s)
Log Message:
- Fixed possible core introduced by previous commit
- Put some asserts into detach_conf()

File Contents

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

Properties

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