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 (19 years, 10 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

# Content
1 /*
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 aconf = &conf->conf.AccessItem;
527 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 aconf = &conf->conf.AccessItem;
536 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 aconf = &conf->conf.AccessItem;
543 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 aconf = &conf->conf.AccessItem;
613 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 xconf = &conf->conf.MatchItem;
642 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 aconf = &conf->conf.AccessItem;
656 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 nconf = &conf->conf.MatchItem;
671 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 cconf = &conf->conf.ResvChannel;
684 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 struct AccessItem *aptr = &((struct ConfItem *)ptr->data)->conf.AccessItem;
713
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"