ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/src/conf.c
Revision: 596
Committed: Fri May 12 21:44:39 2006 UTC (17 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 101676 byte(s)
Log Message:
- Cosmetical fix to "STATS k|K".  temporary regexp based k-lines should 
  be prefixed with 'kR' and permanent ones with 'KR'.

File Contents

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

Properties

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