ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/parse_aline.c
Revision: 139
Committed: Sun Oct 16 06:01:13 2005 UTC (20 years, 9 months ago) by db
Content type: text/x-csrc
File size: 18966 byte(s)
Log Message:
- get rid of map_conf_item and unmap_conf_item
- Use an union in struct ConfItem, but only allocate memory needed


File Contents

# User Rev Content
1 db 91 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * parse_aline.c: All the functions needed for klining etc.
4     *
5     * Copyright (C) 2005 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22     * $Id$
23     */
24    
25     #include "stdinc.h"
26     #include "ircd_defs.h"
27     #include "s_conf.h"
28     #include "parse_aline.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 "hash.h"
36     #include "ircd.h"
37     #include "listener.h"
38     #include "hostmask.h"
39     #include "modules.h"
40     #include "numeric.h"
41     #include "send.h"
42     #include "s_gline.h"
43     #include "userhost.h"
44     #include "s_user.h"
45    
46     static void expire_tklines(dlink_list *);
47     static int find_user_host(struct Client *, char *, char *, char *, unsigned int);
48    
49    
50     dlink_list temporary_klines = { NULL, NULL, 0 };
51     dlink_list temporary_dlines = { NULL, NULL, 0 };
52     dlink_list temporary_xlines = { NULL, NULL, 0 };
53     dlink_list temporary_rklines = { NULL, NULL, 0 };
54     dlink_list temporary_glines = { NULL, NULL, 0 };
55     dlink_list temporary_rxlines = { NULL, NULL, 0 };
56     dlink_list temporary_resv = { NULL, NULL, 0 };
57    
58     /* parse_aline
59     *
60     * input - pointer to cmd name being used
61     * - pointer to client using cmd
62     * - parc parameter count
63     * - parv[] list of parameters to parse
64     * - parse_flags bit map of things to test
65     * - pointer to user or string to parse into
66     * - pointer to host or NULL to parse into if non NULL
67     * - pointer to optional tkline time or NULL
68     * - pointer to target_server to parse into if non NULL
69     * - pointer to reason to parse into
70     *
71     * output - 1 if valid, -1 if not valid
72     * side effects - A generalised k/d/x etc. line parser,
73     * "ALINE [time] user@host|string [ON] target :reason"
74     * will parse returning a parsed user, host if
75     * h_p pointer is non NULL, string otherwise.
76     * if tkline_time pointer is non NULL a tk line will be set
77     * to non zero if found.
78     * if tkline_time pointer is NULL and tk line is found,
79     * error is reported.
80     * if target_server is NULL and an "ON" is found error
81     * is reported.
82     * if reason pointer is NULL ignore pointer,
83     * this allows usee of parse_a_line in unkline etc.
84     *
85     * - Dianora
86     */
87     int
88     parse_aline(const char *cmd, struct Client *source_p,
89     int parc, char **parv,
90     int parse_flags, char **up_p, char **h_p, time_t *tkline_time,
91     char **target_server, char **reason)
92     {
93     int found_tkline_time=0;
94     static char def_reason[] = "No Reason";
95     static char user[USERLEN*4+1];
96     static char host[HOSTLEN*4+1];
97    
98     parv++;
99     parc--;
100    
101     found_tkline_time = valid_tkline(*parv, TK_MINUTES);
102    
103     if (found_tkline_time != 0)
104     {
105     parv++;
106     parc--;
107    
108     if (tkline_time != NULL)
109     *tkline_time = found_tkline_time;
110     else
111     {
112     sendto_one(source_p, ":%s NOTICE %s :temp_line not supported by %s",
113     me.name, source_p->name, cmd);
114     return -1;
115     }
116     }
117    
118     if (parc == 0)
119     {
120     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
121     me.name, source_p->name, cmd);
122     return -1;
123     }
124    
125     if (h_p == NULL)
126     *up_p = *parv;
127     else
128     {
129     if (find_user_host(source_p, *parv, user, host, parse_flags) == 0)
130     return -1;
131    
132     *up_p = user;
133     *h_p = host;
134     }
135    
136     parc--;
137     parv++;
138    
139     if (parc != 0)
140     {
141     if (irccmp(*parv, "ON") == 0)
142     {
143     parc--;
144     parv++;
145    
146     if (target_server == NULL)
147     {
148     sendto_one(source_p, ":%s NOTICE %s :ON server not supported by %s",
149     me.name, source_p->name, cmd);
150     return -1;
151     }
152    
153     if (!IsOperRemoteBan(source_p))
154     {
155     sendto_one(source_p, form_str(ERR_NOPRIVS),
156     me.name, source_p->name, "remoteban");
157     return -1;
158     }
159    
160     if (parc == 0 || EmptyString(*parv))
161     {
162     sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
163     me.name, source_p->name, cmd);
164     return -1;
165     }
166    
167     *target_server = *parv;
168     parc--;
169     parv++;
170     }
171     else
172     {
173     /* Make sure target_server *is* NULL if no ON server found
174     * caller probably NULL'd it first, but no harm to do it again -db
175     */
176     if (target_server != NULL)
177     *target_server = NULL;
178     }
179     }
180    
181     if (h_p != NULL)
182     {
183     if (strchr(user, '!') != NULL)
184     {
185     sendto_one(source_p, ":%s NOTICE %s :Invalid character '!' in kline",
186     me.name, source_p->name);
187     return -1;
188     }
189    
190     if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 2, *up_p, *h_p))
191     return -1;
192     }
193     else
194     if ((parse_flags & AWILD) && !valid_wild_card(source_p, YES, 1, *up_p))
195     return -1;
196    
197     if (reason != NULL)
198     {
199     if (parc != 0)
200     {
201     *reason = *parv;
202     if (!valid_comment(source_p, *reason, YES))
203     return -1;
204     }
205     else
206     *reason = def_reason;
207     }
208    
209     return 1;
210     }
211    
212     /*
213     * cluster_a_line
214     *
215     * inputs - client sending the cluster
216     * - command name "KLINE" "XLINE" etc.
217     * - capab -- CAP_KLN etc. from s_serv.h
218     * - cluster type -- CLUSTER_KLINE etc. from s_conf.h
219     * - pattern and args to send along
220     * output - none
221     * side effects - Take source_p send the pattern with args given
222     * along to all servers that match capab and cluster type
223     */
224     void
225     cluster_a_line(struct Client *source_p, const char *command,
226     int capab, int cluster_type, const char *pattern, ...)
227     {
228     va_list args;
229     char buffer[IRCD_BUFSIZE];
230     struct ConfItem *conf;
231     dlink_node *ptr;
232    
233     va_start(args, pattern);
234     vsnprintf(buffer, sizeof(buffer), pattern, args);
235     va_end(args);
236    
237     DLINK_FOREACH(ptr, cluster_items.head)
238     {
239     conf = ptr->data;
240    
241     if (conf->flags & cluster_type)
242     {
243     sendto_match_servs(source_p, conf->name, CAP_CLUSTER|capab,
244     "%s %s %s", command, conf->name, buffer);
245     }
246     }
247     }
248    
249     /* valid_comment()
250     *
251     * inputs - pointer to client
252     * - pointer to comment
253     * output - 0 if no valid comment,
254     * - 1 if valid
255     * side effects - truncates reason where necessary
256     */
257     int
258     valid_comment(struct Client *source_p, char *comment, int warn)
259     {
260     if (strchr(comment, '"'))
261     {
262     if (warn)
263     sendto_one(source_p, ":%s NOTICE %s :Invalid character '\"' in comment",
264     me.name, source_p->name);
265     return 0;
266     }
267    
268     if (strlen(comment) > REASONLEN)
269     comment[REASONLEN-1] = '\0';
270    
271     return 1;
272     }
273    
274     /* find_user_host()
275     *
276     * inputs - pointer to client placing kline
277     * - pointer to user_host_or_nick
278     * - pointer to user buffer
279     * - pointer to host buffer
280     * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
281     * side effects -
282     */
283     static int
284     find_user_host(struct Client *source_p, char *user_host_or_nick,
285     char *luser, char *lhost, unsigned int flags)
286     {
287     struct Client *target_p = NULL;
288     char *hostp = NULL;
289    
290     if (lhost == NULL)
291     {
292     strlcpy(luser, user_host_or_nick, USERLEN*4 + 1);
293     return 1;
294     }
295    
296     if ((hostp = strchr(user_host_or_nick, '@')) || *user_host_or_nick == '*')
297     {
298     /* Explicit user@host mask given */
299    
300     if(hostp != NULL) /* I'm a little user@host */
301     {
302     *(hostp++) = '\0'; /* short and squat */
303     if (*user_host_or_nick)
304     strlcpy(luser, user_host_or_nick, USERLEN*4 + 1); /* here is my user */
305     else
306     strcpy(luser, "*");
307     if (*hostp)
308     strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
309     else
310     strcpy(lhost, "*");
311     }
312     else
313     {
314     luser[0] = '*'; /* no @ found, assume its *@somehost */
315     luser[1] = '\0';
316     strlcpy(lhost, user_host_or_nick, HOSTLEN*4 + 1);
317     }
318    
319     return 1;
320     }
321     else if (!(flags & NOUSERLOOKUP))
322     {
323     /* Try to find user@host mask from nick */
324     /* Okay to use source_p as the first param, because source_p == client_p */
325     if ((target_p =
326     find_chasing(source_p, source_p, user_host_or_nick, NULL)) == NULL)
327     return 0;
328    
329     if (IsExemptKline(target_p))
330     {
331     if (!IsServer(source_p))
332     sendto_one(source_p,
333     ":%s NOTICE %s :%s is E-lined",
334     me.name, source_p->name, target_p->name);
335     return 0;
336     }
337    
338     /*
339     * turn the "user" bit into "*user", blow away '~'
340     * if found in original user name (non-idented)
341     */
342     strlcpy(luser, target_p->username, USERLEN*4 + 1);
343    
344     if (target_p->username[0] == '~')
345     luser[0] = '*';
346    
347     if (target_p->sockhost[0] == '\0' ||
348     (target_p->sockhost[0] == '0' && target_p->sockhost[1] == '\0'))
349     strlcpy(lhost, target_p->host, HOSTLEN*4 + 1);
350     else
351     strlcpy(lhost, target_p->sockhost, HOSTLEN*4 + 1);
352     return 1;
353     }
354    
355     return 0;
356     }
357    
358     /*
359     * valid_tkline()
360     *
361     * inputs - pointer to ascii string to check
362     * - whether the specified time is in seconds or minutes
363     * output - -1 not enough parameters
364     * - 0 if not an integer number, else the number
365     * side effects - none
366     * Originally written by Dianora (Diane, db@db.net)
367     */
368     time_t
369     valid_tkline(char *p, int minutes)
370     {
371     time_t result = 0;
372    
373     while (*p)
374     {
375     if (IsDigit(*p))
376     {
377     result *= 10;
378     result += ((*p) & 0xF);
379     p++;
380     }
381     else
382     return 0;
383     }
384    
385     /* in the degenerate case where oper does a /quote kline 0 user@host :reason
386     * i.e. they specifically use 0, I am going to return 1 instead
387     * as a return value of non-zero is used to flag it as a temporary kline
388     */
389    
390     if (result == 0)
391     result = 1;
392    
393     /*
394     * If the incoming time is in seconds convert it to minutes for the purpose
395     * of this calculation
396     */
397     if (!minutes)
398     result = result / (time_t)60;
399    
400     if (result > MAX_TDKLINE_TIME)
401     result = MAX_TDKLINE_TIME;
402    
403     result = result * (time_t)60; /* turn it into seconds */
404    
405     return result;
406     }
407    
408     /* valid_wild_card()
409     *
410     * input - pointer to client
411     * - int flag, 0 for no warning oper 1 for warning oper
412     * - count of following varargs to check
413     * output - 0 if not valid, 1 if valid
414     * side effects - NOTICE is given to source_p if warn is 1
415     */
416     int
417     valid_wild_card(struct Client *source_p, int warn, int count, ...)
418     {
419     char *p;
420     char tmpch;
421     int nonwild = 0;
422     va_list args;
423    
424     /*
425     * Now we must check the user and host to make sure there
426     * are at least NONWILDCHARS non-wildcard characters in
427     * them, otherwise assume they are attempting to kline
428     * *@* or some variant of that. This code will also catch
429     * people attempting to kline *@*.tld, as long as NONWILDCHARS
430     * is greater than 3. In that case, there are only 3 non-wild
431     * characters (tld), so if NONWILDCHARS is 4, the kline will
432     * be disallowed.
433     * -wnder
434     */
435    
436     va_start(args, count);
437    
438     while (count--)
439     {
440     p = va_arg(args, char *);
441     if (p == NULL)
442     continue;
443    
444     while ((tmpch = *p++))
445     {
446     if (!IsKWildChar(tmpch))
447     {
448     /*
449     * If we find enough non-wild characters, we can
450     * break - no point in searching further.
451     */
452     if (++nonwild >= ConfigFileEntry.min_nonwildcard)
453     return 1;
454     }
455     }
456     }
457    
458     if (warn)
459     sendto_one(source_p, ":%s NOTICE %s :Please include at least %d non-wildcard characters with the mask",
460     me.name, source_p->name, ConfigFileEntry.min_nonwildcard);
461     return 0;
462     }
463    
464     /* find_kill()
465     *
466     * inputs - pointer to client structure
467     * output - pointer to struct AccessItem if found
468     * side effects - See if this user is klined already,
469     * and if so, return struct AccessItem pointer
470     */
471     struct AccessItem *
472     find_kill(struct Client *client_p)
473     {
474     struct AccessItem *aconf = NULL;
475     const char *uhi[3];
476    
477     uhi[0] = client_p->username;
478     uhi[1] = client_p->host;
479     uhi[2] = client_p->sockhost;
480    
481     assert(client_p != NULL);
482    
483     aconf = find_kline_conf(client_p->host, client_p->username,
484     &client_p->localClient->ip,
485     client_p->localClient->aftype);
486     if (aconf == NULL)
487     aconf = find_regexp_kline(uhi);
488    
489     if (aconf && (aconf->status & CONF_KLINE))
490     return aconf;
491    
492     return NULL;
493     }
494    
495     struct AccessItem *
496     find_gline(struct Client *client_p)
497     {
498     struct AccessItem *aconf;
499    
500     assert(client_p != NULL);
501    
502     aconf = find_gline_conf(client_p->host, client_p->username,
503     &client_p->localClient->ip,
504     client_p->localClient->aftype);
505    
506     if (aconf && (aconf->status & CONF_GLINE))
507     return aconf;
508    
509     return NULL;
510     }
511    
512     /* add_temp_line()
513     *
514     * inputs - pointer to struct ConfItem
515     * output - none
516     * Side effects - links in given struct ConfItem into
517     * temporary *line link list
518     */
519     void
520     add_temp_line(struct ConfItem *conf)
521     {
522     struct AccessItem *aconf;
523    
524     if (conf->type == DLINE_TYPE)
525     {
526 db 139 aconf = &conf->conf.AccessItem;
527 db 91 SetConfTemporary(aconf);
528     dlinkAdd(conf, &conf->node, &temporary_dlines);
529     MyFree(aconf->user);
530     aconf->user = NULL;
531     add_conf_by_address(CONF_DLINE, aconf);
532     }
533     else if (conf->type == KLINE_TYPE)
534     {
535 db 139 aconf = &conf->conf.AccessItem;
536 db 91 SetConfTemporary(aconf);
537     dlinkAdd(conf, &conf->node, &temporary_klines);
538     add_conf_by_address(CONF_KILL, aconf);
539     }
540     else if (conf->type == GLINE_TYPE)
541     {
542 db 139 aconf = &conf->conf.AccessItem;
543 db 91 SetConfTemporary(aconf);
544     dlinkAdd(conf, &conf->node, &temporary_glines);
545     add_conf_by_address(CONF_GLINE, aconf);
546     }
547     else if (conf->type == XLINE_TYPE)
548     {
549     conf->flags |= CONF_FLAGS_TEMPORARY;
550     dlinkAdd(conf, make_dlink_node(), &temporary_xlines);
551     }
552     else if (conf->type == RXLINE_TYPE)
553     {
554     conf->flags |= CONF_FLAGS_TEMPORARY;
555     dlinkAdd(conf, make_dlink_node(), &temporary_rxlines);
556     }
557     else if (conf->type == RKLINE_TYPE)
558     {
559     conf->flags |= CONF_FLAGS_TEMPORARY;
560     dlinkAdd(conf, make_dlink_node(), &temporary_rklines);
561     }
562     else if ((conf->type == NRESV_TYPE) || (conf->type == CRESV_TYPE))
563     {
564     conf->flags |= CONF_FLAGS_TEMPORARY;
565     dlinkAdd(conf, make_dlink_node(), &temporary_resv);
566     }
567     }
568    
569     /* cleanup_tklines()
570     *
571     * inputs - NONE
572     * output - NONE
573     * side effects - call function to expire temporary k/d lines
574     * This is an event started off in ircd.c
575     */
576     void
577     cleanup_tklines(void *notused)
578     {
579     expire_tklines(&temporary_glines);
580     expire_tklines(&temporary_klines);
581     expire_tklines(&temporary_dlines);
582     expire_tklines(&temporary_xlines);
583     expire_tklines(&temporary_rxlines);
584     expire_tklines(&temporary_rklines);
585     expire_tklines(&temporary_resv);
586     }
587    
588     /* expire_tklines()
589     *
590     * inputs - tkline list pointer
591     * output - NONE
592     * side effects - expire tklines
593     */
594     static void
595     expire_tklines(dlink_list *tklist)
596     {
597     dlink_node *ptr;
598     dlink_node *next_ptr;
599     struct ConfItem *conf;
600     struct MatchItem *xconf;
601     struct MatchItem *nconf;
602     struct AccessItem *aconf;
603     struct ResvChannel *cconf;
604    
605     DLINK_FOREACH_SAFE(ptr, next_ptr, tklist->head)
606     {
607     conf = ptr->data;
608     if (conf->type == GLINE_TYPE ||
609     conf->type == KLINE_TYPE ||
610     conf->type == DLINE_TYPE)
611     {
612 db 139 aconf = &conf->conf.AccessItem;
613 db 91 if (aconf->hold <= CurrentTime)
614     {
615     /* XXX - Do we want GLINE expiry notices?? */
616     /* Alert opers that a TKline expired - Hwy */
617     if (ConfigFileEntry.tkline_expire_notices)
618     {
619     if (aconf->status & CONF_KILL)
620     {
621     sendto_realops_flags(UMODE_ALL, L_ALL,
622     "Temporary K-line for [%s@%s] expired",
623     (aconf->user) ? aconf->user : "*",
624     (aconf->host) ? aconf->host : "*");
625     }
626     else if (conf->type == DLINE_TYPE)
627     {
628     sendto_realops_flags(UMODE_ALL, L_ALL,
629     "Temporary D-line for [%s] expired",
630     (aconf->host) ? aconf->host : "*");
631     }
632     }
633    
634     delete_one_address_conf(aconf->host, aconf);
635     dlinkDelete(ptr, tklist);
636     }
637     }
638     else if (conf->type == XLINE_TYPE ||
639     conf->type == RXLINE_TYPE)
640     {
641 db 139 xconf = &conf->conf.MatchItem;
642 db 91 if (xconf->hold <= CurrentTime)
643     {
644     if (ConfigFileEntry.tkline_expire_notices)
645     sendto_realops_flags(UMODE_ALL, L_ALL,
646     "Temporary X-line for [%s] %sexpired", conf->name,
647     conf->type == RXLINE_TYPE ? "(REGEX) " : "");
648     dlinkDelete(ptr, tklist);
649     free_dlink_node(ptr);
650     delete_conf_item(conf);
651     }
652     }
653     else if (conf->type == RKLINE_TYPE)
654     {
655 db 139 aconf = &conf->conf.AccessItem;
656 db 91 if (aconf->hold <= CurrentTime)
657     {
658     if (ConfigFileEntry.tkline_expire_notices)
659     sendto_realops_flags(UMODE_ALL, L_ALL,
660     "Temporary K-line for [%s@%s] (REGEX) expired",
661     (aconf->user) ? aconf->user : "*",
662     (aconf->host) ? aconf->host : "*");
663     dlinkDelete(ptr, tklist);
664     free_dlink_node(ptr);
665     delete_conf_item(conf);
666     }
667     }
668     else if (conf->type == NRESV_TYPE)
669     {
670 db 139 nconf = &conf->conf.MatchItem;
671 db 91 if (nconf->hold <= CurrentTime)
672     {
673     if (ConfigFileEntry.tkline_expire_notices)
674     sendto_realops_flags(UMODE_ALL, L_ALL,
675     "Temporary RESV for [%s] expired", conf->name);
676     dlinkDelete(ptr, tklist);
677     free_dlink_node(ptr);
678     delete_conf_item(conf);
679     }
680     }
681     else if (conf->type == CRESV_TYPE)
682     {
683 db 139 cconf = &conf->conf.ResvChannel;
684 db 91 if (cconf->hold <= CurrentTime)
685     {
686     if (ConfigFileEntry.tkline_expire_notices)
687     sendto_realops_flags(UMODE_ALL, L_ALL,
688     "Temporary RESV for [%s] expired", cconf->name);
689     dlinkDelete(ptr, tklist);
690     free_dlink_node(ptr);
691     delete_conf_item(conf);
692     }
693     }
694     }
695     }
696    
697     /*
698     * find_regexp_kline
699     *
700     * inputs -
701     * output - return a pointer to an AccessItem if present
702     * NULL if not
703     * side effects - none
704     */
705     struct AccessItem *
706     find_regexp_kline(const char *uhi[])
707     {
708     const dlink_node *ptr = NULL;
709    
710     DLINK_FOREACH(ptr, rkconf_items.head)
711     {
712 db 139 struct AccessItem *aptr = &((struct ConfItem *)ptr->data)->conf.AccessItem;
713 db 91
714     assert(aptr->regexuser);
715     assert(aptr->regexhost);
716    
717     if (!ircd_pcre_exec(aptr->regexuser, uhi[0]) &&
718     (!ircd_pcre_exec(aptr->regexhost, uhi[1]) ||
719     !ircd_pcre_exec(aptr->regexhost, uhi[2])))
720     return aptr;
721     }
722    
723     return NULL;
724     }

Properties

Name Value
svn:eol-style native
svn:keywords "Author Date Id Revision"