ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 1219
Committed: Sun Sep 18 09:02:38 2011 UTC (12 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-8/src/s_conf.c
File size: 100407 byte(s)
Log Message:
- Start cleaning up macros in client.h. Replace several ClientHasSomeCoolFlag()
with simple HasFlag/HasUMode macros.

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

Properties

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