ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/s_conf.c
Revision: 69
Committed: Tue Oct 4 16:09:51 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 101012 byte(s)
Log Message:
- splitted ircd/libio, all headers connected with libio sources have been
  moved for internal use only. To use libio interface, include "libio.h"
  (which is already done in "stdinc.h")


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

Properties

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