ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/conf.c
Revision: 432
Committed: Sat Feb 11 14:55:00 2006 UTC (19 years, 6 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/s_conf.c
File size: 101246 byte(s)
Log Message:
- Fixed possible core in expire_temp_lines()

File Contents

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

Properties

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