ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 671
Committed: Tue Jun 13 07:15:38 2006 UTC (17 years, 9 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 100999 byte(s)
Log Message:
- Fixed class limit bug as spotted by stu.  ("REHASH" would always reset
  current user count)
- Made "STATS y|Y" show inactive (deleted) classes that still have attached
  clients

File Contents

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

Properties

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