ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/s_conf.c
Revision: 58
Committed: Mon Oct 3 12:13:38 2005 UTC (18 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 101288 byte(s)
Log Message:
- Reverted oper_privs_as_string() back to its previous version which is easier
  to maintain when adding new operflags. Even the one who wrote the new version
  introduced a bug by not taking care to keep the oper_flags_table in sync
  with the OPER_FLAGS_* bits.  (which also no one really wants to do ...)
- Updated it to deal with new 'remoteban', 'operwall' and 'operspy' flags

File Contents

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

Properties

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