ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.3/src/s_conf.c
Revision: 1118
Committed: Thu Jan 6 13:39:10 2011 UTC (13 years, 2 months ago) by michael
Content type: text/x-csrc
File size: 99463 byte(s)
Log Message:
- cleanup and sanitize m_server.c. remove hostmasking. Improve TS6 suppport

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

Properties

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