ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/s_conf.c
Revision: 967
Committed: Sun Aug 2 18:05:28 2009 UTC (14 years, 8 months ago) by michael
Content type: text/x-csrc
File size: 100641 byte(s)
Log Message:
- added ssl_server_protocol configuration option to servinfo{}.
  valid flags are 'sslv3' and 'tlsv1'

File Contents

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

Properties

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