ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 632
Committed: Thu Jun 1 10:53:00 2006 UTC (19 years, 3 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 101434 byte(s)
Log Message:
- Added channel::disable_fake_channels which disallows creation of channels
  that have ascii 2, 3, 31 and 160 in their names.
- Minor improvements and cleanups to channel name validation routines
  backported from 7.3

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

Properties

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