ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/s_conf.c
Revision: 885
Committed: Wed Oct 31 18:09:24 2007 UTC (16 years, 5 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100841 byte(s)
Log Message:
- Removed LazyLinks in 7.2 to stop people from asking why we keep
  broken code for half a decade. LL will be implemented in a smarter
  fashion in due time

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

Properties

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