ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/s_conf.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 100366 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


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     dlinkAddTail(conf, &conf->node, &gdeny_items);
302     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.invite_ops_only = YES;
1864     ConfigChannel.max_chans_per_user = 15;
1865     ConfigChannel.quiet_on_ban = YES;
1866     ConfigChannel.max_bans = 25;
1867     ConfigChannel.default_split_user_count = 0;
1868     ConfigChannel.default_split_server_count = 0;
1869     ConfigChannel.no_join_on_split = NO;
1870     ConfigChannel.no_create_on_split = NO;
1871     ConfigChannel.burst_topicwho = YES;
1872    
1873     ConfigServerHide.flatten_links = NO;
1874     ConfigServerHide.links_delay = 300;
1875     ConfigServerHide.hidden = NO;
1876     ConfigServerHide.disable_hidden = NO;
1877     ConfigServerHide.hide_servers = NO;
1878     DupString(ConfigServerHide.hidden_name, NETWORK_NAME_DEFAULT);
1879     ConfigServerHide.hide_server_ips = NO;
1880    
1881     ConfigFileEntry.gline_min_cidr = 16;
1882     ConfigFileEntry.gline_min_cidr6 = 48;
1883     ConfigFileEntry.invisible_on_connect = YES;
1884     ConfigFileEntry.burst_away = NO;
1885     ConfigFileEntry.use_whois_actually = YES;
1886     ConfigFileEntry.tkline_expire_notices = YES;
1887     ConfigFileEntry.hide_spoof_ips = YES;
1888     ConfigFileEntry.ignore_bogus_ts = NO;
1889     ConfigFileEntry.disable_auth = NO;
1890     ConfigFileEntry.disable_remote = NO;
1891     ConfigFileEntry.kill_chase_time_limit = 90;
1892     ConfigFileEntry.default_floodcount = 8; /* XXX */
1893     ConfigFileEntry.failed_oper_notice = YES;
1894     ConfigFileEntry.dots_in_ident = 0; /* XXX */
1895     ConfigFileEntry.dot_in_ip6_addr = YES;
1896     ConfigFileEntry.min_nonwildcard = 4;
1897     ConfigFileEntry.min_nonwildcard_simple = 3;
1898     ConfigFileEntry.max_accept = 20;
1899     ConfigFileEntry.anti_nick_flood = NO; /* XXX */
1900     ConfigFileEntry.max_nick_time = 20;
1901     ConfigFileEntry.max_nick_changes = 5;
1902     ConfigFileEntry.anti_spam_exit_message_time = 0; /* XXX */
1903     ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1904     ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT; /* XXX */
1905     ConfigFileEntry.kline_with_reason = YES;
1906     ConfigFileEntry.kline_reason = NULL;
1907     ConfigFileEntry.warn_no_nline = YES;
1908     ConfigFileEntry.stats_o_oper_only = NO; /* XXX */
1909     ConfigFileEntry.stats_k_oper_only = 1; /* masked */
1910     ConfigFileEntry.stats_i_oper_only = 1; /* masked */
1911     ConfigFileEntry.stats_P_oper_only = NO;
1912     ConfigFileEntry.caller_id_wait = 60;
1913     ConfigFileEntry.opers_bypass_callerid = NO;
1914     ConfigFileEntry.pace_wait = 10;
1915     ConfigFileEntry.pace_wait_simple = 1;
1916     ConfigFileEntry.short_motd = NO;
1917     ConfigFileEntry.ping_cookie = NO;
1918     ConfigFileEntry.no_oper_flood = NO; /* XXX */
1919     ConfigFileEntry.true_no_oper_flood = NO; /* XXX */
1920     ConfigFileEntry.oper_pass_resv = YES;
1921     ConfigFileEntry.glines = NO; /* XXX */
1922     ConfigFileEntry.gline_time = 12 * 3600; /* XXX */
1923     ConfigFileEntry.idletime = 0;
1924     ConfigFileEntry.max_targets = MAX_TARGETS_DEFAULT;
1925     ConfigFileEntry.client_flood = CLIENT_FLOOD_DEFAULT;
1926     ConfigFileEntry.oper_only_umodes = UMODE_DEBUG; /* XXX */
1927     ConfigFileEntry.oper_umodes = UMODE_LOCOPS | UMODE_SERVNOTICE |
1928     UMODE_OPERWALL | UMODE_WALLOP; /* XXX */
1929     DupString(ConfigFileEntry.servlink_path, SLPATH);
1930     #ifdef HAVE_LIBCRYPTO
1931     /* jdc -- This is our default value for a cipher. According to the
1932     * CRYPTLINK document (doc/cryptlink.txt), BF/128 must be supported
1933     * under all circumstances if cryptlinks are enabled. So,
1934     * this will be our default.
1935     *
1936     * NOTE: I apologise for the hard-coded value of "1" (BF/128).
1937     * This should be moved into a find_cipher() routine.
1938     */
1939     ConfigFileEntry.default_cipher_preference = &CipherTable[1];
1940     #endif
1941     ConfigFileEntry.use_egd = NO;
1942     ConfigFileEntry.egdpool_path = NULL;
1943     #ifdef HAVE_LIBZ
1944     ConfigFileEntry.compression_level = 0;
1945     #endif
1946     ConfigFileEntry.throttle_time = 10;
1947     }
1948    
1949     /* read_conf()
1950     *
1951     * inputs - file descriptor pointing to config file to use
1952     * output - None
1953     * side effects - Read configuration file.
1954     */
1955     static void
1956     read_conf(FBFILE *file)
1957     {
1958     scount = lineno = 0;
1959    
1960     set_default_conf(); /* Set default values prior to conf parsing */
1961     ypass = 1;
1962     yyparse(); /* pick up the classes first */
1963    
1964     fbrewind(file);
1965    
1966     ypass = 2;
1967     yyparse(); /* Load the values from the conf */
1968     validate_conf(); /* Check to make sure some values are still okay. */
1969     /* Some global values are also loaded here. */
1970     check_class(); /* Make sure classes are valid */
1971     }
1972    
1973     static void
1974     validate_conf(void)
1975     {
1976     if (ConfigFileEntry.ts_warn_delta < TS_WARN_DELTA_MIN)
1977     ConfigFileEntry.ts_warn_delta = TS_WARN_DELTA_DEFAULT;
1978    
1979     if (ConfigFileEntry.ts_max_delta < TS_MAX_DELTA_MIN)
1980     ConfigFileEntry.ts_max_delta = TS_MAX_DELTA_DEFAULT;
1981    
1982     if (ConfigFileEntry.servlink_path == NULL)
1983     DupString(ConfigFileEntry.servlink_path, SLPATH);
1984    
1985     if (ServerInfo.network_name == NULL)
1986     DupString(ServerInfo.network_name,NETWORK_NAME_DEFAULT);
1987    
1988     if (ServerInfo.network_desc == NULL)
1989     DupString(ServerInfo.network_desc,NETWORK_DESC_DEFAULT);
1990    
1991     if ((ConfigFileEntry.client_flood < CLIENT_FLOOD_MIN) ||
1992     (ConfigFileEntry.client_flood > CLIENT_FLOOD_MAX))
1993     ConfigFileEntry.client_flood = CLIENT_FLOOD_MAX;
1994     }
1995    
1996     /* lookup_confhost()
1997     *
1998     * start DNS lookups of all hostnames in the conf
1999     * line and convert an IP addresses in a.b.c.d number for to IP#s.
2000     */
2001     static void
2002     lookup_confhost(struct ConfItem *conf)
2003     {
2004     struct AccessItem *aconf;
2005     struct addrinfo hints, *res;
2006    
2007     aconf = map_to_conf(conf);
2008    
2009     if (EmptyString(aconf->host) ||
2010     EmptyString(aconf->user))
2011     {
2012     ilog(L_ERROR, "Host/server name error: (%s) (%s)",
2013     aconf->host, conf->name);
2014     return;
2015     }
2016    
2017     if (strchr(aconf->host, '*') ||
2018     strchr(aconf->host, '?'))
2019     return;
2020    
2021     /* Do name lookup now on hostnames given and store the
2022     * ip numbers in conf structure.
2023     */
2024     memset(&hints, 0, sizeof(hints));
2025    
2026     hints.ai_family = AF_UNSPEC;
2027     hints.ai_socktype = SOCK_STREAM;
2028    
2029     /* Get us ready for a bind() and don't bother doing dns lookup */
2030     hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
2031    
2032     if (irc_getaddrinfo(aconf->host, NULL, &hints, &res))
2033     {
2034     conf_dns_lookup(aconf);
2035     return;
2036     }
2037    
2038     assert(res != NULL);
2039    
2040     memcpy(&aconf->ipnum, res->ai_addr, res->ai_addrlen);
2041     aconf->ipnum.ss_len = res->ai_addrlen;
2042     aconf->ipnum.ss.ss_family = res->ai_family;
2043     irc_freeaddrinfo(res);
2044     }
2045    
2046     /* conf_connect_allowed()
2047     *
2048     * inputs - pointer to inaddr
2049     * - int type ipv4 or ipv6
2050     * output - BANNED or accepted
2051     * side effects - none
2052     */
2053     int
2054     conf_connect_allowed(struct irc_ssaddr *addr, int aftype)
2055     {
2056     struct ip_entry *ip_found;
2057     struct AccessItem *aconf = find_dline_conf(addr, aftype);
2058    
2059     /* DLINE exempt also gets you out of static limits/pacing... */
2060     if (aconf && (aconf->status & CONF_EXEMPTDLINE))
2061     return 0;
2062    
2063     if (aconf != NULL)
2064     return BANNED_CLIENT;
2065    
2066     ip_found = find_or_add_ip(addr);
2067    
2068     if ((CurrentTime - ip_found->last_attempt) <
2069     ConfigFileEntry.throttle_time)
2070     {
2071     ip_found->last_attempt = CurrentTime;
2072     return TOO_FAST;
2073     }
2074    
2075     ip_found->last_attempt = CurrentTime;
2076     return 0;
2077     }
2078    
2079     static struct AccessItem *
2080     find_regexp_kline(const char *uhi[])
2081     {
2082     const dlink_node *ptr = NULL;
2083    
2084     DLINK_FOREACH(ptr, rkconf_items.head)
2085     {
2086     struct AccessItem *aptr = map_to_conf(ptr->data);
2087    
2088     assert(aptr->regexuser);
2089     assert(aptr->regexhost);
2090    
2091     if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
2092     (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
2093     !ircd_pcre_exec(aptr->regexhost, uhi[2])))
2094     return aptr;
2095     }
2096    
2097     return NULL;
2098     }
2099    
2100     /* find_kill()
2101     *
2102     * inputs - pointer to client structure
2103     * output - pointer to struct AccessItem if found
2104     * side effects - See if this user is klined already,
2105     * and if so, return struct AccessItem pointer
2106     */
2107     struct AccessItem *
2108     find_kill(struct Client *client_p)
2109     {
2110     struct AccessItem *aconf = NULL;
2111     const char *uhi[3];
2112    
2113     uhi[0] = client_p->username;
2114     uhi[1] = client_p->host;
2115     uhi[2] = client_p->sockhost;
2116    
2117     assert(client_p != NULL);
2118    
2119     aconf = find_kline_conf(client_p->host, client_p->username,
2120     &client_p->localClient->ip,
2121     client_p->localClient->aftype);
2122     if (aconf == NULL)
2123     aconf = find_regexp_kline(uhi);
2124    
2125     if (aconf && (aconf->status & CONF_KLINE))
2126     return aconf;
2127    
2128     return NULL;
2129     }
2130    
2131     struct AccessItem *
2132     find_gline(struct Client *client_p)
2133     {
2134     struct AccessItem *aconf;
2135    
2136     assert(client_p != NULL);
2137    
2138     aconf = find_gline_conf(client_p->host, client_p->username,
2139     &client_p->localClient->ip,
2140     client_p->localClient->aftype);
2141    
2142     if (aconf && (aconf->status & CONF_GLINE))
2143     return aconf;
2144    
2145     return NULL;
2146     }
2147    
2148     /* add_temp_line()
2149     *
2150     * inputs - pointer to struct ConfItem
2151     * output - none
2152     * Side effects - links in given struct ConfItem into
2153     * temporary *line link list
2154     */
2155     void
2156     add_temp_line(struct ConfItem *conf)
2157     {
2158     struct AccessItem *aconf;
2159    
2160     if (conf->type == DLINE_TYPE)
2161     {
2162     aconf = map_to_conf(conf);
2163     SetConfTemporary(aconf);
2164     dlinkAdd(conf, &conf->node, &temporary_dlines);
2165     MyFree(aconf->user);
2166     aconf->user = NULL;
2167     add_conf_by_address(CONF_DLINE, aconf);
2168     }
2169     else if (conf->type == KLINE_TYPE)
2170     {
2171     aconf = map_to_conf(conf);
2172     SetConfTemporary(aconf);
2173     dlinkAdd(conf, &conf->node, &temporary_klines);
2174     add_conf_by_address(CONF_KILL, aconf);
2175     }
2176     else if (conf->type == GLINE_TYPE)
2177     {
2178     aconf = map_to_conf(conf);
2179     SetConfTemporary(aconf);
2180     dlinkAdd(conf, &conf->node, &temporary_glines);
2181     add_conf_by_address(CONF_GLINE, aconf);
2182     }
2183     else if (conf->type == XLINE_TYPE)
2184     {
2185     conf->flags |= CONF_FLAGS_TEMPORARY;
2186     dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
2187     }
2188     else if (conf->type == RXLINE_TYPE)
2189     {
2190     conf->flags |= CONF_FLAGS_TEMPORARY;
2191     dlinkAdd(conf, make_dlink_node(), &temporary_rxlines);
2192     }
2193     else if (conf->type == RKLINE_TYPE)
2194     {
2195     conf->flags |= CONF_FLAGS_TEMPORARY;
2196     dlinkAdd(conf, make_dlink_node(), &temporary_rklines);
2197     }
2198     else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
2199     {
2200     conf->flags |= CONF_FLAGS_TEMPORARY;
2201     dlinkAdd(conf, make_dlink_node(), &temporary_resv);
2202     }
2203     }
2204    
2205     /* cleanup_tklines()
2206     *
2207     * inputs - NONE
2208     * output - NONE
2209     * side effects - call function to expire temporary k/d lines
2210     * This is an event started off in ircd.c
2211     */
2212     void
2213     cleanup_tklines(void *notused)
2214     {
2215     expire_tklines(&temporary_glines);
2216     expire_tklines(&temporary_klines);
2217     expire_tklines(&temporary_dlines);
2218     expire_tklines(&temporary_xlines);
2219     expire_tklines(&temporary_rxlines);
2220     expire_tklines(&temporary_rklines);
2221     expire_tklines(&temporary_resv);
2222     }
2223    
2224     /* expire_tklines()
2225     *
2226     * inputs - tkline list pointer
2227     * output - NONE
2228     * side effects - expire tklines
2229     */
2230     static void
2231     expire_tklines(dlink_list *tklist)
2232     {
2233     dlink_node *ptr;
2234     dlink_node *next_ptr;
2235     struct ConfItem *conf;
2236     struct MatchItem *xconf;
2237     struct MatchItem *nconf;
2238     struct AccessItem *aconf;
2239     struct ResvChannel *cconf;
2240    
2241     DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
2242     {
2243     conf = ptr->data;
2244     if (conf->type == GLINE_TYPE ||
2245     conf->type == KLINE_TYPE ||
2246     conf->type == DLINE_TYPE)
2247     {
2248     aconf = (struct AccessItem *)map_to_conf(conf);
2249     if (aconf->hold <= CurrentTime)
2250     {
2251     /* XXX - Do we want GLINE expiry notices?? */
2252     /* Alert opers that a TKline expired - Hwy */
2253     if (ConfigFileEntry.tkline_expire_notices)
2254     {
2255     if (aconf->status & CONF_KILL)
2256     {
2257     sendto_realops_flags(UMODE_ALL, L_ALL,
2258     "Temporary K-line for [%s@%s] expired",
2259     (aconf->user) ? aconf->user : "*",
2260     (aconf->host) ? aconf->host : "*");
2261     }
2262     else if (conf->type == DLINE_TYPE)
2263     {
2264     sendto_realops_flags(UMODE_ALL, L_ALL,
2265     "Temporary D-line for [%s] expired",
2266     (aconf->host) ? aconf->host : "*");
2267     }
2268     }
2269    
2270     delete_one_address_conf(aconf->host, aconf);
2271     dlinkDelete(ptr, tklist);
2272     }
2273     }
2274     else if (conf->type == XLINE_TYPE ||
2275     conf->type == RXLINE_TYPE)
2276     {
2277     xconf = (struct MatchItem *)map_to_conf(conf);
2278     if (xconf->hold <= CurrentTime)
2279     {
2280     if (ConfigFileEntry.tkline_expire_notices)
2281     sendto_realops_flags(UMODE_ALL, L_ALL,
2282     "Temporary X-line for [%s] %sexpired", conf->name,
2283     conf->type == RXLINE_TYPE ? "(REGEX) " : "");
2284     dlinkDelete(ptr, tklist);
2285     free_dlink_node(ptr);
2286     delete_conf_item(conf);
2287     }
2288     }
2289     else if (conf->type == RKLINE_TYPE)
2290     {
2291     aconf = map_to_conf(conf);
2292     if (aconf->hold <= CurrentTime)
2293     {
2294     if (ConfigFileEntry.tkline_expire_notices)
2295     sendto_realops_flags(UMODE_ALL, L_ALL,
2296     "Temporary K-line for [%s@%s] (REGEX) expired",
2297     (aconf->user) ? aconf->user : "*",
2298     (aconf->host) ? aconf->host : "*");
2299     dlinkDelete(ptr, tklist);
2300     free_dlink_node(ptr);
2301     delete_conf_item(conf);
2302     }
2303     }
2304     else if (conf->type == NRESV_TYPE)
2305     {
2306     nconf = (struct MatchItem *)map_to_conf(conf);
2307     if (nconf->hold <= CurrentTime)
2308     {
2309     if (ConfigFileEntry.tkline_expire_notices)
2310     sendto_realops_flags(UMODE_ALL, L_ALL,
2311     "Temporary RESV for [%s] expired", conf->name);
2312     dlinkDelete(ptr, tklist);
2313     free_dlink_node(ptr);
2314     delete_conf_item(conf);
2315     }
2316     }
2317     else if (conf->type == CRESV_TYPE)
2318     {
2319     cconf = (struct ResvChannel *)map_to_conf(conf);
2320     if (cconf->hold <= CurrentTime)
2321     {
2322     if (ConfigFileEntry.tkline_expire_notices)
2323     sendto_realops_flags(UMODE_ALL, L_ALL,
2324     "Temporary RESV for [%s] expired", cconf->name);
2325     dlinkDelete(ptr, tklist);
2326     free_dlink_node(ptr);
2327     delete_conf_item(conf);
2328     }
2329     }
2330     }
2331     }
2332    
2333     /* oper_privs_as_string()
2334     *
2335     * inputs - pointer to client_p or NULL
2336     * output - pointer to static string showing oper privs
2337     * side effects - return as string, the oper privs as derived from port
2338     */
2339    
2340     static const unsigned int oper_flags_table[] =
2341     { 'O', 'R', 'U', 'G', 'N', 'K', 'X', 'D', 'H', 'A' , 0 };
2342    
2343     char *
2344     oper_privs_as_string(const unsigned int port)
2345     {
2346     static char privs_out[12];
2347    
2348     if (port & OPER_FLAG_HIDDEN_ADMIN)
2349     flags_to_ascii(port & ~OPER_FLAG_ADMIN, oper_flags_table, privs_out, 1);
2350     else
2351     flags_to_ascii(port, oper_flags_table, privs_out, 1);
2352     return privs_out;
2353     }
2354    
2355     /*
2356     * Input: A client to find the active oper{} name for.
2357     * Output: The nick!user@host{oper} of the oper.
2358     * "oper" is server name for remote opers
2359     * Side effects: None.
2360     */
2361     char *
2362     get_oper_name(const struct Client *client_p)
2363     {
2364     dlink_node *cnode;
2365     struct ConfItem *conf;
2366     struct AccessItem *aconf;
2367    
2368     /* +5 for !,@,{,} and null */
2369     static char buffer[NICKLEN+USERLEN+HOSTLEN+HOSTLEN+5];
2370    
2371     if (MyConnect(client_p))
2372     {
2373     DLINK_FOREACH(cnode, client_p->localClient->confs.head)
2374     {
2375     conf = cnode->data;
2376     aconf = map_to_conf(conf);
2377    
2378     if (IsConfOperator(aconf))
2379     {
2380     ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
2381     client_p->username, client_p->host,
2382     conf->name);
2383     return buffer;
2384     }
2385     }
2386    
2387     /* Probably should assert here for now. If there is an oper out there
2388     * with no oper{} conf attached, it would be good for us to know...
2389     */
2390     assert(0); /* Oper without oper conf! */
2391     }
2392    
2393     ircsprintf(buffer, "%s!%s@%s{%s}", client_p->name,
2394     client_p->username, client_p->host, client_p->servptr->name);
2395     return buffer;
2396     }
2397    
2398     /* read_conf_files()
2399     *
2400     * inputs - cold start YES or NO
2401     * output - none
2402     * side effects - read all conf files needed, ircd.conf kline.conf etc.
2403     */
2404     void
2405     read_conf_files(int cold)
2406     {
2407     const char *filename;
2408     char chanmodes[32];
2409     char chanlimit[32];
2410    
2411     filename = get_conf_name(CONF_TYPE);
2412    
2413     /* We need to know the initial filename for the yyerror() to report
2414     FIXME: The full path is in conffilenamebuf first time since we
2415     dont know anything else
2416    
2417     - Gozem 2002-07-21
2418     */
2419     strlcpy(conffilebuf, filename, sizeof(conffilebuf));
2420    
2421     if ((conf_fbfile_in = fbopen(filename, "r")) == NULL)
2422     {
2423     if (cold)
2424     {
2425     ilog(L_CRIT, "Unable to read configuration file '%s': %s",
2426     filename, strerror(errno));
2427     exit(-1);
2428     }
2429     else
2430     {
2431     sendto_realops_flags(UMODE_ALL, L_ALL,
2432     "Unable to read configuration file '%s': %s",
2433     filename, strerror(errno));
2434     return;
2435     }
2436     }
2437    
2438     if (!cold)
2439     clear_out_old_conf();
2440    
2441     read_conf(conf_fbfile_in);
2442     fbclose(conf_fbfile_in);
2443    
2444     add_isupport("NETWORK", ServerInfo.network_name, -1);
2445     ircsprintf(chanmodes, "b%s%s:%d", ConfigChannel.use_except ? "e" : "",
2446     ConfigChannel.use_invex ? "I" : "", ConfigChannel.max_bans);
2447     add_isupport("MAXLIST", chanmodes, -1);
2448     add_isupport("MAXTARGETS", NULL, ConfigFileEntry.max_targets);
2449     if (ConfigChannel.disable_local_channels)
2450     add_isupport("CHANTYPES", "#", -1);
2451     else
2452     add_isupport("CHANTYPES", "#&", -1);
2453     ircsprintf(chanlimit, "%s:%d", ConfigChannel.disable_local_channels ? "#" : "#&",
2454     ConfigChannel.max_chans_per_user);
2455     add_isupport("CHANLIMIT", chanlimit, -1);
2456     ircsprintf(chanmodes, "%s%s%s", ConfigChannel.use_except ? "e" : "",
2457     ConfigChannel.use_invex ? "I" : "", "b,k,l,imnpst");
2458     add_isupport("CHANNELLEN", NULL, CHANNELLEN);
2459     if (ConfigChannel.use_except)
2460     add_isupport("EXCEPTS", "e", -1);
2461     if (ConfigChannel.use_invex)
2462     add_isupport("INVEX", "I", -1);
2463     add_isupport("CHANMODES", chanmodes, -1);
2464    
2465     /*
2466     * message_locale may have changed. rebuild isupport since it relies
2467     * on strlen(form_str(RPL_ISUPPORT))
2468     */
2469     rebuild_isupport_message_line();
2470    
2471     parse_conf_file(KLINE_TYPE, cold);
2472     parse_conf_file(RKLINE_TYPE, cold);
2473     parse_conf_file(DLINE_TYPE, cold);
2474     parse_conf_file(XLINE_TYPE, cold);
2475     parse_conf_file(RXLINE_TYPE, cold);
2476     parse_conf_file(NRESV_TYPE, cold);
2477     parse_conf_file(CRESV_TYPE, cold);
2478     }
2479    
2480     /* parse_conf_file()
2481     *
2482     * inputs - type of conf file to parse
2483     * output - none
2484     * side effects - conf file for givenconf type is opened and read then parsed
2485     */
2486     static void
2487     parse_conf_file(int type, int cold)
2488     {
2489     FBFILE *file = NULL;
2490     const char *filename = get_conf_name(type);
2491    
2492     if ((file = fbopen(filename, "r")) == NULL)
2493     {
2494     if (cold)
2495     ilog(L_ERROR, "Unable to read configuration file '%s': %s",
2496     filename, strerror(errno));
2497     else
2498     sendto_realops_flags(UMODE_ALL, L_ALL,
2499     "Unable to read configuration file '%s': %s",
2500     filename, strerror(errno));
2501     }
2502     else
2503     {
2504     parse_csv_file(file, type);
2505     fbclose(file);
2506     }
2507     }
2508    
2509     /* clear_out_old_conf()
2510     *
2511     * inputs - none
2512     * output - none
2513     * side effects - Clear out the old configuration
2514     */
2515     static void
2516     clear_out_old_conf(void)
2517     {
2518     dlink_node *ptr = NULL, *next_ptr = NULL;
2519     struct ConfItem *conf;
2520     struct AccessItem *aconf;
2521     struct ClassItem *cltmp;
2522     struct MatchItem *match_item;
2523     dlink_list *free_items [] = {
2524     &server_items, &oconf_items, &hub_items, &leaf_items,
2525     &uconf_items, &xconf_items, &rxconf_items, &rkconf_items,
2526     &nresv_items, &cluster_items, &gdeny_items, NULL
2527     };
2528    
2529     dlink_list ** iterator = free_items; /* C is dumb */
2530    
2531     /* We only need to free anything allocated by yyparse() here.
2532     * Resetting structs, etc, is taken care of by set_default_conf().
2533     */
2534    
2535     for (; *iterator != NULL; iterator++)
2536     {
2537     DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2538     {
2539     conf = ptr->data;
2540     /* XXX This is less than pretty */
2541     if (conf->type == SERVER_TYPE)
2542     {
2543     aconf = (struct AccessItem *)map_to_conf(conf);
2544     if (aconf->clients != 0)
2545     {
2546     SetConfIllegal(aconf);
2547     dlinkDelete(&conf->node, &server_items);
2548     }
2549     else
2550     {
2551     delete_conf_item(conf);
2552     }
2553     }
2554     else if (conf->type == OPER_TYPE)
2555     {
2556     aconf = (struct AccessItem *)map_to_conf(conf);
2557     if (aconf->clients != 0)
2558     {
2559     SetConfIllegal(aconf);
2560     dlinkDelete(&conf->node, &oconf_items);
2561     }
2562     else
2563     {
2564     delete_conf_item(conf);
2565     }
2566     }
2567     else if (conf->type == CLIENT_TYPE)
2568     {
2569     aconf = (struct AccessItem *)map_to_conf(conf);
2570     if (aconf->clients != 0)
2571     {
2572     SetConfIllegal(aconf);
2573     }
2574     else
2575     {
2576     delete_conf_item(conf);
2577     }
2578     }
2579     else if (conf->type == XLINE_TYPE ||
2580     conf->type == RXLINE_TYPE ||
2581     conf->type == RKLINE_TYPE)
2582     {
2583     /* temporary (r)xlines are also on
2584     * the (r)xconf items list */
2585     if (conf->flags & CONF_FLAGS_TEMPORARY)
2586     continue;
2587    
2588     delete_conf_item(conf);
2589     }
2590     else
2591     {
2592     if ((conf->type == LEAF_TYPE) || (conf->type == HUB_TYPE))
2593     {
2594     match_item = (struct MatchItem *)map_to_conf(conf);
2595     if ((match_item->ref_count <= 0))
2596     delete_conf_item(conf);
2597     else
2598     {
2599     match_item->illegal = 1;
2600     dlinkDelete(&conf->node, *iterator);
2601     }
2602     }
2603     else
2604     delete_conf_item(conf);
2605     }
2606     }
2607     }
2608    
2609     /* don't delete the class table, rather mark all entries
2610     * for deletion. The table is cleaned up by check_class. - avalon
2611     */
2612     DLINK_FOREACH(ptr, class_items.head)
2613     {
2614     conf = ptr->data;
2615     cltmp = (struct ClassItem *)map_to_conf(conf);
2616     if (ptr != class_items.tail) /* never mark the "default" class */
2617     MaxTotal(cltmp) = -1;
2618     }
2619    
2620     clear_out_address_conf();
2621    
2622     /* clean out module paths */
2623     #ifndef STATIC_MODULES
2624     mod_clear_paths();
2625     #endif
2626    
2627     /* clean out ServerInfo */
2628     MyFree(ServerInfo.description);
2629     ServerInfo.description = NULL;
2630     MyFree(ServerInfo.network_name);
2631     ServerInfo.network_name = NULL;
2632     MyFree(ServerInfo.network_desc);
2633     ServerInfo.network_desc = NULL;
2634     MyFree(ConfigFileEntry.egdpool_path);
2635     ConfigFileEntry.egdpool_path = NULL;
2636     #ifdef HAVE_LIBCRYPTO
2637     if (ServerInfo.rsa_private_key != NULL)
2638     {
2639     RSA_free(ServerInfo.rsa_private_key);
2640     ServerInfo.rsa_private_key = NULL;
2641     }
2642    
2643     MyFree(ServerInfo.rsa_private_key_file);
2644     ServerInfo.rsa_private_key_file = NULL;
2645     #endif
2646    
2647     /* clean out old resvs from the conf */
2648     clear_conf_resv();
2649    
2650     /* clean out AdminInfo */
2651     MyFree(AdminInfo.name);
2652     AdminInfo.name = NULL;
2653     MyFree(AdminInfo.email);
2654     AdminInfo.email = NULL;
2655     MyFree(AdminInfo.description);
2656     AdminInfo.description = NULL;
2657    
2658     /* operator{} and class{} blocks are freed above */
2659     /* clean out listeners */
2660     close_listeners();
2661    
2662     /* auth{}, quarantine{}, shared{}, connect{}, kill{}, deny{},
2663     * exempt{} and gecos{} blocks are freed above too
2664     */
2665    
2666     /* clean out general */
2667     MyFree(ConfigFileEntry.servlink_path);
2668     ConfigFileEntry.servlink_path = NULL;
2669     #ifdef HAVE_LIBCRYPTO
2670     ConfigFileEntry.default_cipher_preference = NULL;
2671     #endif /* HAVE_LIBCRYPTO */
2672     delete_isupport("INVEX");
2673     delete_isupport("EXCEPTS");
2674     }
2675    
2676     /* flush_deleted_I_P()
2677     *
2678     * inputs - none
2679     * output - none
2680     * side effects - This function removes I/P conf items
2681     */
2682     static void
2683     flush_deleted_I_P(void)
2684     {
2685     dlink_node *ptr;
2686     dlink_node *next_ptr;
2687     struct ConfItem *conf;
2688     struct AccessItem *aconf;
2689     dlink_list * free_items [] = {
2690     &server_items, &oconf_items, &hub_items, &leaf_items, NULL
2691     };
2692     dlink_list ** iterator = free_items; /* C is dumb */
2693    
2694     /* flush out deleted I and P lines
2695     * although still in use.
2696     */
2697     for (; *iterator != NULL; iterator++)
2698     {
2699     DLINK_FOREACH_SAFE(ptr, next_ptr, (*iterator)->head)
2700     {
2701     conf = ptr->data;
2702     aconf = (struct AccessItem *)map_to_conf(conf);
2703    
2704     if (IsConfIllegal(aconf))
2705     {
2706     dlinkDelete(ptr, *iterator);
2707    
2708     if (aconf->clients == 0)
2709     delete_conf_item(conf);
2710     }
2711     }
2712     }
2713     }
2714    
2715     /* get_conf_name()
2716     *
2717     * inputs - type of conf file to return name of file for
2718     * output - pointer to filename for type of conf
2719     * side effects - none
2720     */
2721     const char *
2722     get_conf_name(ConfType type)
2723     {
2724     switch (type)
2725     {
2726     case CONF_TYPE:
2727     return ConfigFileEntry.configfile;
2728     break;
2729     case KLINE_TYPE:
2730     return ConfigFileEntry.klinefile;
2731     break;
2732     case RKLINE_TYPE:
2733     return ConfigFileEntry.rklinefile;
2734     break;
2735     case DLINE_TYPE:
2736     return ConfigFileEntry.dlinefile;
2737     break;
2738     case XLINE_TYPE:
2739     return ConfigFileEntry.xlinefile;
2740     break;
2741     case RXLINE_TYPE:
2742     return ConfigFileEntry.rxlinefile;
2743     break;
2744     case CRESV_TYPE:
2745     return ConfigFileEntry.cresvfile;
2746     break;
2747     case NRESV_TYPE:
2748     return ConfigFileEntry.nresvfile;
2749     break;
2750     case GLINE_TYPE:
2751     return ConfigFileEntry.glinefile;
2752     break;
2753    
2754     default:
2755     return NULL; /* This should NEVER HAPPEN since we call this function
2756     only with the above values, this will cause us to core
2757     at some point if this happens so we know where it was */
2758     }
2759     }
2760    
2761     #define BAD_PING (-1)
2762    
2763     /* get_conf_ping()
2764     *
2765     * inputs - pointer to struct AccessItem
2766     * - pointer to a variable that receives ping warning time
2767     * output - ping frequency
2768     * side effects - NONE
2769     */
2770     static int
2771     get_conf_ping(struct ConfItem *conf, int *pingwarn)
2772     {
2773     struct ClassItem *aclass;
2774     struct AccessItem *aconf;
2775    
2776     if (conf != NULL)
2777     {
2778     aconf = (struct AccessItem *)map_to_conf(conf);
2779     if (aconf->class_ptr != NULL)
2780     {
2781     aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
2782     *pingwarn = PingWarning(aclass);
2783     return PingFreq(aclass);
2784     }
2785     }
2786    
2787     return BAD_PING;
2788     }
2789    
2790     /* get_client_class()
2791     *
2792     * inputs - pointer to client struct
2793     * output - pointer to name of class
2794     * side effects - NONE
2795     */
2796     const char *
2797     get_client_class(struct Client *target_p)
2798     {
2799     dlink_node *ptr;
2800     struct ConfItem *conf;
2801     struct AccessItem *aconf;
2802    
2803     if (target_p != NULL && !IsMe(target_p) &&
2804     target_p->localClient->confs.head != NULL)
2805     {
2806     DLINK_FOREACH(ptr, target_p->localClient->confs.head)
2807     {
2808     conf = ptr->data;
2809    
2810     if (conf->type == CLIENT_TYPE || conf->type == SERVER_TYPE ||
2811     conf->type == OPER_TYPE)
2812     {
2813     aconf = (struct AccessItem *) map_to_conf(conf);
2814     if (aconf->class_ptr != NULL)
2815     return aconf->class_ptr->name;
2816     }
2817     }
2818     }
2819    
2820     return "default";
2821     }
2822    
2823     /* get_client_ping()
2824     *
2825     * inputs - pointer to client struct
2826     * - pointer to a variable that receives ping warning time
2827     * output - ping frequency
2828     * side effects - NONE
2829     */
2830     int
2831     get_client_ping(struct Client *target_p, int *pingwarn)
2832     {
2833     int ping;
2834     struct ConfItem *conf;
2835     dlink_node *nlink;
2836    
2837     if (target_p->localClient->confs.head != NULL)
2838     DLINK_FOREACH(nlink, target_p->localClient->confs.head)
2839     {
2840     conf = nlink->data;
2841    
2842     if ((conf->type == CLIENT_TYPE) || (conf->type == SERVER_TYPE) ||
2843     (conf->type == OPER_TYPE))
2844     {
2845     ping = get_conf_ping(conf, pingwarn);
2846     if (ping > 0)
2847     return ping;
2848     }
2849     }
2850    
2851     *pingwarn = 0;
2852     return DEFAULT_PINGFREQUENCY;
2853     }
2854    
2855     /* find_class()
2856     *
2857     * inputs - string name of class
2858     * output - corresponding Class pointer
2859     * side effects - NONE
2860     */
2861     struct ConfItem *
2862     find_class(const char *classname)
2863     {
2864     struct ConfItem *conf;
2865    
2866     if ((conf = find_exact_name_conf(CLASS_TYPE, classname, NULL, NULL)) != NULL)
2867     return(conf);
2868    
2869     return class_default;
2870     }
2871    
2872     /* check_class()
2873     *
2874     * inputs - NONE
2875     * output - NONE
2876     * side effects -
2877     */
2878     void
2879     check_class(void)
2880     {
2881     dlink_node *ptr;
2882     dlink_node *next_ptr;
2883     struct ConfItem *conf;
2884     struct ClassItem *aclass;
2885    
2886     DLINK_FOREACH_SAFE(ptr, next_ptr, class_items.head)
2887     {
2888     conf = ptr->data;
2889     aclass = (struct ClassItem *)map_to_conf(conf);
2890    
2891     if (MaxTotal(aclass) < 0)
2892     {
2893     destroy_cidr_class(aclass);
2894     if (CurrUserCount(aclass) > 0)
2895     dlinkDelete(&conf->node, &class_items);
2896     else
2897     delete_conf_item(conf);
2898     }
2899     }
2900     }
2901    
2902     /* init_class()
2903     *
2904     * inputs - NONE
2905     * output - NONE
2906     * side effects -
2907     */
2908     void
2909     init_class(void)
2910     {
2911     struct ClassItem *aclass;
2912    
2913     class_default = make_conf_item(CLASS_TYPE);
2914     aclass = (struct ClassItem *)map_to_conf(class_default);
2915     DupString(class_default->name, "default");
2916     ConFreq(aclass) = DEFAULT_CONNECTFREQUENCY;
2917     PingFreq(aclass) = DEFAULT_PINGFREQUENCY;
2918     MaxTotal(aclass) = MAXIMUM_LINKS_DEFAULT;
2919     MaxSendq(aclass) = DEFAULT_SENDQ;
2920    
2921     client_check_cb = register_callback("check_client", check_client);
2922     }
2923    
2924     /* get_sendq()
2925     *
2926     * inputs - pointer to client
2927     * output - sendq for this client as found from its class
2928     * side effects - NONE
2929     */
2930     unsigned long
2931     get_sendq(struct Client *client_p)
2932     {
2933     unsigned long sendq = DEFAULT_SENDQ;
2934     dlink_node *ptr;
2935     struct ConfItem *conf;
2936     struct ConfItem *class_conf;
2937     struct ClassItem *aclass;
2938     struct AccessItem *aconf;
2939    
2940     if (client_p && !IsMe(client_p) && (client_p->localClient->confs.head))
2941     {
2942     DLINK_FOREACH(ptr, client_p->localClient->confs.head)
2943     {
2944     conf = ptr->data;
2945     if ((conf->type == SERVER_TYPE) || (conf->type == OPER_TYPE)
2946     || (conf->type == CLIENT_TYPE))
2947     {
2948     aconf = (struct AccessItem *)map_to_conf(conf);
2949     if ((class_conf = aconf->class_ptr) == NULL)
2950     continue;
2951     aclass = (struct ClassItem *)map_to_conf(class_conf);
2952     sendq = MaxSendq(aclass);
2953     return sendq;
2954     }
2955     }
2956     }
2957     /* XXX return a default?
2958     * if here, then there wasn't an attached conf with a sendq
2959     * that is very bad -Dianora
2960     */
2961     return DEFAULT_SENDQ;
2962     }
2963    
2964     /* conf_add_class_to_conf()
2965     *
2966     * inputs - pointer to config item
2967     * output - NONE
2968     * side effects - Add a class pointer to a conf
2969     */
2970     void
2971     conf_add_class_to_conf(struct ConfItem *conf, const char *class_name)
2972     {
2973     struct AccessItem *aconf;
2974     struct ClassItem *aclass;
2975    
2976     aconf = (struct AccessItem *)map_to_conf(conf);
2977    
2978     if (class_name == NULL)
2979     {
2980     aconf->class_ptr = class_default;
2981     if (conf->type == CLIENT_TYPE)
2982     sendto_realops_flags(UMODE_ALL, L_ALL,
2983     "Warning *** Defaulting to default class for %s@%s",
2984     aconf->user, aconf->host);
2985     else
2986     sendto_realops_flags(UMODE_ALL, L_ALL,
2987     "Warning *** Defaulting to default class for %s",
2988     conf->name);
2989     }
2990     else
2991     {
2992     aconf->class_ptr = find_class(class_name);
2993     }
2994    
2995     if (aconf->class_ptr == NULL)
2996     {
2997     if (conf->type == CLIENT_TYPE)
2998     sendto_realops_flags(UMODE_ALL, L_ALL,
2999     "Warning *** Defaulting to default class for %s@%s",
3000     aconf->user, aconf->host);
3001     else
3002     sendto_realops_flags(UMODE_ALL, L_ALL,
3003     "Warning *** Defaulting to default class for %s",
3004     conf->name);
3005     aconf->class_ptr = class_default;
3006     }
3007     else
3008     {
3009     aclass = (struct ClassItem *)map_to_conf(aconf->class_ptr);
3010     if (MaxTotal(aclass) < 0)
3011     {
3012     aconf->class_ptr = class_default;
3013     }
3014     }
3015     }
3016    
3017     #define MAXCONFLINKS 150
3018    
3019     /* conf_add_server()
3020     *
3021     * inputs - pointer to config item
3022     * - pointer to link count already on this conf
3023     * output - NONE
3024     * side effects - Add a connect block
3025     */
3026     int
3027     conf_add_server(struct ConfItem *conf, unsigned int lcount, const char *class_name)
3028     {
3029     struct AccessItem *aconf;
3030     char *orig_host;
3031    
3032     aconf = map_to_conf(conf);
3033    
3034     conf_add_class_to_conf(conf, class_name);
3035    
3036     if (lcount > MAXCONFLINKS || !aconf->host || !conf->name)
3037     {
3038     sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block");
3039     ilog(L_WARN, "Bad connect block");
3040     return -1;
3041     }
3042    
3043     if (EmptyString(aconf->passwd) && !IsConfCryptLink(aconf))
3044     {
3045     sendto_realops_flags(UMODE_ALL, L_ALL, "Bad connect block, name %s",
3046     conf->name);
3047     ilog(L_WARN, "Bad connect block, host %s", conf->name);
3048     return -1;
3049     }
3050    
3051     orig_host = aconf->host;
3052     split_nuh(orig_host, NULL, &aconf->user, &aconf->host);
3053     MyFree(orig_host);
3054     lookup_confhost(conf);
3055    
3056     return 0;
3057     }
3058    
3059     /* conf_add_d_conf()
3060     *
3061     * inputs - pointer to config item
3062     * output - NONE
3063     * side effects - Add a d/D line
3064     */
3065     void
3066     conf_add_d_conf(struct AccessItem *aconf)
3067     {
3068     if (aconf->host == NULL)
3069     return;
3070    
3071     aconf->user = NULL;
3072    
3073     /* XXX - Should 'd' ever be in the old conf? For new conf we don't
3074     * need this anyway, so I will disable it for now... -A1kmm
3075     */
3076     if (parse_netmask(aconf->host, NULL, NULL) == HM_HOST)
3077     {
3078     ilog(L_WARN, "Invalid Dline %s ignored", aconf->host);
3079     free_access_item(aconf);
3080     }
3081     else
3082     {
3083     /* XXX ensure user is NULL */
3084     MyFree(aconf->user);
3085     aconf->user = NULL;
3086     add_conf_by_address(CONF_DLINE, aconf);
3087     }
3088     }
3089    
3090     /* yyerror()
3091     *
3092     * inputs - message from parser
3093     * output - NONE
3094     * side effects - message to opers and log file entry is made
3095     */
3096     void
3097     yyerror(const char *msg)
3098     {
3099     char newlinebuf[IRCD_BUFSIZE];
3100    
3101     if (ypass != 1)
3102     return;
3103    
3104     strip_tabs(newlinebuf, linebuf, sizeof(newlinebuf));
3105     sendto_realops_flags(UMODE_ALL, L_ALL, "\"%s\", line %u: %s: %s",
3106     conffilebuf, lineno + 1, msg, newlinebuf);
3107     ilog(L_WARN, "\"%s\", line %u: %s: %s",
3108     conffilebuf, lineno + 1, msg, newlinebuf);
3109     }
3110    
3111     int
3112     conf_fbgets(char *lbuf, unsigned int max_size, FBFILE *fb)
3113     {
3114     if (fbgets(lbuf, max_size, fb) == NULL)
3115     return 0;
3116    
3117     return strlen(lbuf);
3118     }
3119    
3120     int
3121     conf_yy_fatal_error(const char *msg)
3122     {
3123     return 0;
3124     }
3125    
3126     /*
3127     * valid_tkline()
3128     *
3129     * inputs - pointer to ascii string to check
3130     * - whether the specified time is in seconds or minutes
3131     * output - -1 not enough parameters
3132     * - 0 if not an integer number, else the number
3133     * side effects - none
3134     * Originally written by Dianora (Diane, db@db.net)
3135     */
3136     time_t
3137     valid_tkline(char *p, int minutes)
3138     {
3139     time_t result = 0;
3140    
3141     while (*p)
3142     {
3143     if (IsDigit(*p))
3144     {
3145     result *= 10;
3146     result += ((*p) & 0xF);
3147     p++;
3148     }
3149     else
3150     return 0;
3151     }
3152    
3153     /* in the degenerate case where oper does a /quote kline 0 user@host :reason
3154     * i.e. they specifically use 0, I am going to return 1 instead
3155     * as a return value of non-zero is used to flag it as a temporary kline
3156     */
3157    
3158     if (result == 0)
3159     result = 1;
3160    
3161     /*
3162     * If the incoming time is in seconds convert it to minutes for the purpose
3163     * of this calculation
3164     */
3165     if (!minutes)
3166     result = result / (time_t)60;
3167    
3168     if (result > MAX_TDKLINE_TIME)
3169     result = MAX_TDKLINE_TIME;
3170    
3171     result = result * (time_t)60; /* turn it into seconds */
3172    
3173     return result;
3174     }
3175    
3176     /* valid_wild_card()
3177     *
3178     * input - pointer to client
3179     * - int flag, 0 for no warning oper 1 for warning oper
3180     * - count of following varargs to check
3181     * output - 0 if not valid, 1 if valid
3182     * side effects - NOTICE is given to source_p if warn is 1
3183     */
3184     int
3185     valid_wild_card(struct Client *source_p, int warn, int count, ...)
3186     {
3187     char *p;
3188     char tmpch;
3189     int nonwild = 0;
3190     va_list args;
3191    
3192     /*
3193     * Now we must check the user and host to make sure there
3194     * are at least NONWILDCHARS non-wildcard characters in
3195     * them, otherwise assume they are attempting to kline
3196     * *@* or some variant of that. This code will also catch
3197     * people attempting to kline *@*.tld, as long as NONWILDCHARS
3198     * is greater than 3. In that case, there are only 3 non-wild
3199     * characters (tld), so if NONWILDCHARS is 4, the kline will
3200     * be disallowed.
3201     * -wnder
3202     */
3203    
3204     va_start(args, count);
3205    
3206     while (count--)
3207     {
3208     p = va_arg(args, char *);
3209     if (p == NULL)
3210     continue;
3211    
3212     while ((tmpch = *p++))
3213     {
3214     if (!IsKWildChar(tmpch))
3215     {
3216     /*
3217     * If we find enough non-wild characters, we can
3218     * break - no point in searching further.
3219     */
3220     if (++nonwild >= ConfigFileEntry.min_nonwildcard)
3221     return 1;
3222     }
3223     }
3224     }
3225    
3226     if (warn)
3227     sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
3228     me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
3229     return 0;
3230     }
3231    
3232     /* XXX should this go into a separate file ? -Dianora */
3233     /* parse_aline
3234     *
3235     * input - pointer to cmd name being used
3236     * - pointer to client using cmd
3237     * - parc parameter count
3238     * - parv[] list of parameters to parse
3239     * - parse_flags bit map of things to test
3240     * - pointer to user or string to parse into
3241     * - pointer to host or NULL to parse into if non NULL
3242     * - pointer to optional tkline time or NULL
3243     * - pointer to target_server to parse into if non NULL
3244     * - pointer to reason to parse into
3245     *
3246     * output - 1 if valid, -1 if not valid
3247     * side effects - A generalised k/d/x etc. line parser,
3248     * "ALINE [time] user@host|string [ON] target :reason"
3249     * will parse returning a parsed user, host if
3250     * h_p pointer is non NULL, string otherwise.
3251     * if tkline_time pointer is non NULL a tk line will be set
3252     * to non zero if found.
3253     * if tkline_time pointer is NULL and tk line is found,
3254     * error is reported.
3255     * if target_server is NULL and an "ON" is found error
3256     * is reported.
3257     * if reason pointer is NULL ignore pointer,
3258     * this allows usee of parse_a_line in unkline etc.
3259     *
3260     * - Dianora
3261     */
3262     int
3263     parse_aline(const char *cmd, struct Client *source_p,
3264     int parc, char **parv,
3265     int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
3266     char **target_server, char **reason)
3267     {
3268     int found_tkline_time=0;
3269     static char def_reason[] = "No Reason";
3270     static char user[USERLEN*4+1];
3271     static char host[HOSTLEN*4+1];
3272    
3273     parv++;
3274     parc--;
3275    
3276     found_tkline_time = valid_tkline(*parv, TK_MINUTES);
3277    
3278     if (found_tkline_time != 0)
3279     {
3280     parv++;
3281     parc--;
3282    
3283     if (tkline_time != NULL)
3284     *tkline_time = found_tkline_time;
3285     else
3286     {
3287     sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
3288     me.name, source_p->name, cmd);
3289     return -1;
3290     }
3291     }
3292    
3293     if (parc == 0)
3294     {
3295     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3296     me.name, source_p->name, cmd);
3297     return -1;
3298     }
3299    
3300     if (h_p == NULL)
3301     *up_p = *parv;
3302     else
3303     {
3304     if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
3305     return -1;
3306    
3307     *up_p = user;
3308     *h_p = host;
3309     }
3310    
3311     parc--;
3312     parv++;
3313    
3314     if (parc != 0)
3315     {
3316     if (irccmp(*parv, "ON") == 0)
3317     {
3318     parc--;
3319     parv++;
3320    
3321     if (target_server == NULL)
3322     {
3323     sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
3324     me.name, source_p->name, cmd);
3325     return -1;
3326     }
3327    
3328     if (!IsOperRemoteBan(source_p))
3329     {
3330     sendto_one(source_p, form_str(ERR_NOPRIVS),
3331     me.name, source_p->name, "remoteban");
3332     return -1;
3333     }
3334    
3335     if (parc == 0 || EmptyString(*parv))
3336     {
3337     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
3338     me.name, source_p->name, cmd);
3339     return -1;
3340     }
3341    
3342     *target_server = *parv;
3343     parc--;
3344     parv++;
3345     }
3346     else
3347     {
3348     /* Make sure target_server *is* NULL if no ON server found
3349     * caller probably NULL'd it first, but no harm to do it again -db
3350     */
3351     if (target_server != NULL)
3352     *target_server = NULL;
3353     }
3354     }
3355    
3356     if (h_p != NULL)
3357     {
3358     if (strchr(user, '!') != NULL)
3359     {
3360     sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
3361     me.name, source_p->name);
3362     return -1;
3363     }
3364    
3365     if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 2, *up_p, *h_p))
3366     return -1;
3367     }
3368     else
3369     if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 1, *up_p))
3370     return -1;
3371    
3372     if (reason != NULL)
3373     {
3374     if (parc != 0)
3375     {
3376     *reason = *parv;
3377     if (!valid_comment(source_p, *reason, YES))
3378     return -1;
3379     }
3380     else
3381     *reason = def_reason;
3382     }
3383    
3384     return 1;
3385     }
3386    
3387     /* find_user_host()
3388     *
3389     * inputs - pointer to client placing kline
3390     * - pointer to user_host_or_nick
3391     * - pointer to user buffer
3392     * - pointer to host buffer
3393     * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
3394     * side effects -
3395     */
3396     static int
3397     find_user_host(struct Client *source_p, char *user_host_or_nick,
3398     char *luser, char *lhost, unsigned int flags)
3399     {
3400     struct Client *target_p = NULL;
3401     char *hostp = NULL;
3402    
3403     if (lhost == NULL)
3404     {
3405     strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
3406     return 1;
3407     }
3408    
3409     if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
3410     {
3411     /* Explicit user@host mask given */
3412    
3413     if(hostp != NULL) /* I'm a little user@host */
3414     {
3415     *(hostp++) = '\0'; /* short and squat */
3416     if (*user_host_or_nick)
3417     strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
3418     else
3419     strcpy(luser, "*");
3420     if (*hostp)
3421     strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
3422     else
3423     strcpy(lhost, "*");
3424     }
3425     else
3426     {
3427     luser[0] = '*'; /* no @ found, assume its *@somehost */
3428     luser[1] = '\0';
3429     strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
3430     }
3431    
3432     return 1;
3433     }
3434     else if (!(flags & NOUSERLOOKUP))
3435     {
3436     /* Try to find user@host mask from nick */
3437     /* Okay to use source_p as the first param, because source_p == client_p */
3438     if ((target_p =
3439     find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
3440     return 0;
3441    
3442     if (IsExemptKline(target_p))
3443     {
3444     if (!IsServer(source_p))
3445     sendto_one(source_p,
3446     ":%s NOTICE %s :%s is E-lined",
3447     me.name, source_p->name, target_p->name);
3448     return 0;
3449     }
3450    
3451     /*
3452     * turn the "user" bit into "*user", blow away '~'
3453     * if found in original user name (non-idented)
3454     */
3455     strlcpy(luser, target_p->username, USERLEN*4 + 1);
3456    
3457     if (target_p->username[0] == '~')
3458     luser[0] = '*';
3459    
3460     if (target_p->sockhost[0] == '\0' ||
3461     (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
3462     strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
3463     else
3464     strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
3465     return 1;
3466     }
3467    
3468     return 0;
3469     }
3470    
3471     /* valid_comment()
3472     *
3473     * inputs - pointer to client
3474     * - pointer to comment
3475     * output - 0 if no valid comment,
3476     * - 1 if valid
3477     * side effects - truncates reason where necessary
3478     */
3479     int
3480     valid_comment(struct Client *source_p, char *comment, int warn)
3481     {
3482     if (strchr(comment, '"'))
3483     {
3484     if (warn)
3485     sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
3486     me.name, source_p->name);
3487     return 0;
3488     }
3489    
3490     if (strlen(comment) > REASONLEN)
3491     comment[REASONLEN-1] = '\0';
3492    
3493     return 1;
3494     }
3495    
3496     /* match_conf_password()
3497     *
3498     * inputs - pointer to given password
3499     * - pointer to Conf
3500     * output - 1 or 0 if match
3501     * side effects - none
3502     */
3503     int
3504     match_conf_password(const char *password, const struct AccessItem *aconf)
3505     {
3506     const char *encr = NULL;
3507    
3508     if (password == NULL || aconf->passwd == NULL)
3509     return 0;
3510    
3511     if (aconf->flags & CONF_FLAGS_ENCRYPTED)
3512     {
3513     /* use first two chars of the password they send in as salt */
3514     /* If the password in the conf is MD5, and ircd is linked
3515     * to scrypt on FreeBSD, or the standard crypt library on
3516     * glibc Linux, then this code will work fine on generating
3517     * the proper encrypted hash for comparison.
3518     */
3519     if (*aconf->passwd)
3520     encr = crypt(password, aconf->passwd);
3521     else
3522     encr = "";
3523     }
3524     else
3525     encr = password;
3526    
3527     return !strcmp(encr, aconf->passwd);
3528     }
3529    
3530     /*
3531     * cluster_a_line
3532     *
3533     * inputs - client sending the cluster
3534     * - command name "KLINE" "XLINE" etc.
3535     * - capab -- CAP_KLN etc. from s_serv.h
3536     * - cluster type -- CLUSTER_KLINE etc. from s_conf.h
3537     * - pattern and args to send along
3538     * output - none
3539     * side effects - Take source_p send the pattern with args given
3540     * along to all servers that match capab and cluster type
3541     */
3542     void
3543     cluster_a_line(struct Client *source_p, const char *command,
3544     int capab, int cluster_type, const char *pattern, ...)
3545     {
3546     va_list args;
3547     char buffer[IRCD_BUFSIZE];
3548     struct ConfItem *conf;
3549     dlink_node *ptr;
3550    
3551     va_start(args, pattern);
3552     vsnprintf(buffer, sizeof(buffer), pattern, args);
3553     va_end(args);
3554    
3555     DLINK_FOREACH(ptr, cluster_items.head)
3556     {
3557     conf = ptr->data;
3558    
3559     if (conf->flags & cluster_type)
3560     {
3561     sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
3562     "%s %s %s", command, conf->name, buffer);
3563     }
3564     }
3565     }
3566    
3567     /*
3568     * split_nuh
3569     *
3570     * inputs - pointer to original mask (modified in place)
3571     * - pointer to pointer where nick should go
3572     * - pointer to pointer where user should go
3573     * - pointer to pointer where host should go
3574     * output - NONE
3575     * side effects - mask is modified in place
3576     * If nick pointer is NULL, ignore writing to it
3577     * this allows us to use this function elsewhere.
3578     *
3579     * mask nick user host
3580     * ---------------------- ------- ------- ------
3581     * Dianora!db@db.net Dianora db db.net
3582     * Dianora Dianora * *
3583     * db.net * * db.net
3584     * OR if nick pointer is NULL
3585     * Dianora - * Dianora
3586     * Dianora! Dianora * *
3587     * Dianora!@ Dianora * *
3588     * Dianora!db Dianora db *
3589     * Dianora!@db.net Dianora * db.net
3590     * db@db.net * db db.net
3591     * !@ * * *
3592     * @ * * *
3593     * ! * * *
3594     */
3595    
3596     void
3597     split_nuh(char *mask, char **nick, char **user, char **host)
3598     {
3599     char *p = NULL, *q = NULL;
3600    
3601     if ((p = strchr(mask, '!')) != NULL)
3602     {
3603     *p = '\0';
3604     if (nick != NULL)
3605     {
3606     if (*mask != '\0')
3607     *nick = xstrldup(mask, NICKLEN);
3608     else
3609     DupString(*nick, "*");
3610     }
3611    
3612     if ((q = strchr(++p, '@')) != NULL)
3613     {
3614     *q = '\0';
3615    
3616     if (*p != '\0')
3617     *user = xstrldup(p, USERLEN+1);
3618     else
3619     DupString(*user, "*");
3620    
3621     if (*++q != '\0')
3622     *host = xstrldup(q, HOSTLEN+1);
3623     else
3624     DupString(*host, "*");
3625     }
3626     else
3627     {
3628     if (*p != '\0')
3629     *user = xstrldup(p, USERLEN+1);
3630     else
3631     DupString(*user, "*");
3632    
3633     DupString(*host, "*");
3634     }
3635     }
3636     else /* No ! found so lets look for a user@host */
3637     {
3638     if ((p = strchr(mask, '@')) != NULL) /* if found a @ */
3639     {
3640     if (nick != NULL)
3641     DupString(*nick, "*");
3642     *p = '\0';
3643    
3644     if (*mask != '\0')
3645     *user = xstrldup(mask, USERLEN+1);
3646     else
3647     DupString(*user, "*");
3648    
3649     if (*++p != '\0')
3650     *host = xstrldup(p, HOSTLEN+1);
3651     else
3652     DupString(*host, "*");
3653     }
3654     else /* no @ found */
3655     {
3656     if (nick != NULL)
3657     {
3658     if (strpbrk(mask, ".:"))
3659     {
3660     DupString(*nick, "*");
3661     *host = xstrldup(mask, HOSTLEN+1);
3662     }
3663     else
3664     {
3665     *nick = xstrldup(mask, NICKLEN);
3666     DupString(*host, "*");
3667     }
3668    
3669     DupString(*user, "*");
3670     }
3671     else
3672     {
3673     DupString(*user, "*");
3674     *host = xstrldup(mask, HOSTLEN+1);
3675     }
3676     }
3677     }
3678     }
3679    
3680     /*
3681     * flags_to_ascii
3682     *
3683     * inputs - flags is a bitmask
3684     * - pointer to table of ascii letters corresponding
3685     * to each bit
3686     * - flag 1 for convert ToLower if bit missing
3687     * 0 if ignore.
3688     * output - none
3689     * side effects - string pointed to by p has bitmap chars written to it
3690     */
3691     static void
3692     flags_to_ascii(unsigned int flags, const unsigned int bit_table[], char *p,
3693     int lowerit)
3694     {
3695     unsigned int mask = 1;
3696     int i = 0;
3697    
3698     for (mask = 1; (mask != 0) && (bit_table[i] != 0); mask <<= 1, i++)
3699     {
3700     if (flags & mask)
3701     *p++ = bit_table[i];
3702     else if(lowerit)
3703     *p++ = ToLower(bit_table[i]);
3704     }
3705     *p = '\0';
3706     }
3707    
3708     /*
3709     * cidr_limit_reached
3710     *
3711     * inputs - int flag allowing over_rule of limits
3712     * - pointer to the ip to be added
3713     * - pointer to the class
3714     * output - non zero if limit reached
3715     * 0 if limit not reached
3716     * side effects -
3717     */
3718     static int
3719     cidr_limit_reached(int over_rule,
3720     struct irc_ssaddr *ip, struct ClassItem *aclass)
3721     {
3722     dlink_node *ptr = NULL;
3723     struct CidrItem *cidr;
3724    
3725     if (NumberPerCidr(aclass) <= 0)
3726     return 0;
3727    
3728     if (ip->ss.ss_family == AF_INET)
3729     {
3730     if (CidrBitlenIPV4(aclass) <= 0)
3731     return 0;
3732    
3733     DLINK_FOREACH(ptr, aclass->list_ipv4.head)
3734     {
3735     cidr = ptr->data;
3736     if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3737     {
3738     if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3739     return -1;
3740     cidr->number_on_this_cidr++;
3741     return 0;
3742     }
3743     }
3744     cidr = MyMalloc(sizeof(struct CidrItem));
3745     cidr->number_on_this_cidr = 1;
3746     cidr->mask = *ip;
3747     mask_addr(&cidr->mask, CidrBitlenIPV4(aclass));
3748     dlinkAdd(cidr, &cidr->node, &aclass->list_ipv4);
3749     }
3750     #ifdef IPV6
3751     else if (CidrBitlenIPV6(aclass) > 0)
3752     {
3753     DLINK_FOREACH(ptr, aclass->list_ipv6.head)
3754     {
3755     cidr = ptr->data;
3756     if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3757     {
3758     if (!over_rule && (cidr->number_on_this_cidr >= NumberPerCidr(aclass)))
3759     return -1;
3760     cidr->number_on_this_cidr++;
3761     return 0;
3762     }
3763     }
3764     cidr = MyMalloc(sizeof(struct CidrItem));
3765     cidr->number_on_this_cidr = 1;
3766     cidr->mask = *ip;
3767     mask_addr(&cidr->mask, CidrBitlenIPV6(aclass));
3768     dlinkAdd(cidr, &cidr->node, &aclass->list_ipv6);
3769     }
3770     #endif
3771     return 0;
3772     }
3773    
3774     /*
3775     * remove_from_cidr_check
3776     *
3777     * inputs - pointer to the ip to be removed
3778     * - pointer to the class
3779     * output - NONE
3780     * side effects -
3781     */
3782     static void
3783     remove_from_cidr_check(struct irc_ssaddr *ip, struct ClassItem *aclass)
3784     {
3785     dlink_node *ptr = NULL;
3786     dlink_node *next_ptr = NULL;
3787     struct CidrItem *cidr;
3788    
3789     if (NumberPerCidr(aclass) == 0)
3790     return;
3791    
3792     if (ip->ss.ss_family == AF_INET)
3793     {
3794     if (CidrBitlenIPV4(aclass) <= 0)
3795     return;
3796    
3797     DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv4.head)
3798     {
3799     cidr = ptr->data;
3800     if (match_ipv4(ip, &cidr->mask, CidrBitlenIPV4(aclass)))
3801     {
3802     cidr->number_on_this_cidr--;
3803     if (cidr->number_on_this_cidr == 0)
3804     {
3805     dlinkDelete(ptr, &aclass->list_ipv4);
3806     MyFree(cidr);
3807     return;
3808     }
3809     }
3810     }
3811     }
3812     #ifdef IPV6
3813     else if (CidrBitlenIPV6(aclass) > 0)
3814     {
3815     DLINK_FOREACH_SAFE(ptr, next_ptr, aclass->list_ipv6.head)
3816     {
3817     cidr = ptr->data;
3818     if (match_ipv6(ip, &cidr->mask, CidrBitlenIPV6(aclass)))
3819     {
3820     cidr->number_on_this_cidr--;
3821     if (cidr->number_on_this_cidr == 0)
3822     {
3823     dlinkDelete(ptr, &aclass->list_ipv6);
3824     MyFree(cidr);
3825     return;
3826     }
3827     }
3828     }
3829     }
3830     #endif
3831     }
3832    
3833     static void
3834     rebuild_cidr_list(int aftype, struct ConfItem *oldcl, struct ClassItem *newcl,
3835     dlink_list *old_list, dlink_list *new_list, int changed)
3836     {
3837     dlink_node *ptr;
3838     struct Client *client_p;
3839     struct ConfItem *conf;
3840     struct AccessItem *aconf;
3841    
3842     if (!changed)
3843     {
3844     *new_list = *old_list;
3845     old_list->head = old_list->tail = NULL;
3846     old_list->length = 0;
3847     return;
3848     }
3849    
3850     DLINK_FOREACH(ptr, local_client_list.head)
3851     {
3852     client_p = ptr->data;
3853     if (client_p->localClient->aftype != aftype)
3854     continue;
3855     if (dlink_list_length(&client_p->localClient->confs) == 0)
3856     continue;
3857    
3858     conf = client_p->localClient->confs.tail->data;
3859     if (conf->type == CLIENT_TYPE)
3860     {
3861     aconf = map_to_conf(conf);
3862     if (aconf->class_ptr == oldcl)
3863     cidr_limit_reached(1, &client_p->localClient->ip, newcl);
3864     }
3865     }
3866     }
3867    
3868     /*
3869     * rebuild_cidr_class
3870     *
3871     * inputs - pointer to old conf
3872     * - pointer to new_class
3873     * output - none
3874     * side effects - rebuilds the class link list of cidr blocks
3875     */
3876     void
3877     rebuild_cidr_class(struct ConfItem *conf, struct ClassItem *new_class)
3878     {
3879     struct ClassItem *old_class = map_to_conf(conf);
3880    
3881     if (NumberPerCidr(old_class) > 0 && NumberPerCidr(new_class) > 0)
3882     {
3883     if (CidrBitlenIPV4(old_class) > 0 && CidrBitlenIPV4(new_class) > 0)
3884     rebuild_cidr_list(AF_INET, conf, new_class,
3885     &old_class->list_ipv4, &new_class->list_ipv4,
3886     CidrBitlenIPV4(old_class) != CidrBitlenIPV4(new_class));
3887    
3888     #ifdef IPV6
3889     if (CidrBitlenIPV6(old_class) > 0 && CidrBitlenIPV6(new_class) > 0)
3890     rebuild_cidr_list(AF_INET6, conf, new_class,
3891     &old_class->list_ipv6, &new_class->list_ipv6,
3892     CidrBitlenIPV6(old_class) != CidrBitlenIPV6(new_class));
3893     #endif
3894     }
3895    
3896     destroy_cidr_class(old_class);
3897     }
3898    
3899     /*
3900     * destroy_cidr_list
3901     *
3902     * inputs - pointer to class dlink list of cidr blocks
3903     * output - none
3904     * side effects - completely destroys the class link list of cidr blocks
3905     */
3906     static void
3907     destroy_cidr_list(dlink_list *list)
3908     {
3909     dlink_node *ptr = NULL;
3910     dlink_node *next_ptr = NULL;
3911     struct CidrItem *cidr;
3912    
3913     DLINK_FOREACH_SAFE(ptr, next_ptr, list->head)
3914     {
3915     cidr = ptr->data;
3916     dlinkDelete(ptr, list);
3917     MyFree(cidr);
3918     }
3919     }
3920    
3921     /*
3922     * destroy_cidr_class
3923     *
3924     * inputs - pointer to class
3925     * output - none
3926     * side effects - completely destroys the class link list of cidr blocks
3927     */
3928     static void
3929     destroy_cidr_class(struct ClassItem *aclass)
3930     {
3931     destroy_cidr_list(&aclass->list_ipv4);
3932     destroy_cidr_list(&aclass->list_ipv6);
3933     }

Properties

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