Initial import
[ratbox-ambernet.git] / modules / m_xline.c
blob14e27f48ba39daa11bbbd0b2cfaa7d42c3f30450
1 /* modules/m_xline.c
2 *
3 * Copyright (C) 2002-2003 Lee Hardy <lee@leeh.co.uk>
4 * Copyright (C) 2002-2005 ircd-ratbox development team
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
10 * 1.Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 * 2.Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3.The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * $Id: m_xline.c 23291 2006-11-27 11:44:20Z jilles $
33 #include "stdinc.h"
34 #include "tools.h"
35 #include "send.h"
36 #include "channel.h"
37 #include "client.h"
38 #include "common.h"
39 #include "config.h"
40 #include "class.h"
41 #include "ircd.h"
42 #include "numeric.h"
43 #include "memory.h"
44 #include "s_log.h"
45 #include "s_serv.h"
46 #include "whowas.h"
47 #include "irc_string.h"
48 #include "sprintf_irc.h"
49 #include "hash.h"
50 #include "msg.h"
51 #include "parse.h"
52 #include "modules.h"
53 #include "s_conf.h"
54 #include "s_newconf.h"
56 static int mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
57 static int ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
58 static int me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
59 static int mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
60 static int ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
61 static int me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
63 struct Message xline_msgtab = {
64 "XLINE", 0, 0, 0, MFLG_SLOW,
65 {mg_unreg, mg_not_oper, {ms_xline, 5}, {ms_xline, 5}, {me_xline, 5}, {mo_xline, 3}}
67 struct Message unxline_msgtab = {
68 "UNXLINE", 0, 0, 0, MFLG_SLOW,
69 {mg_unreg, mg_not_oper, {ms_unxline, 3}, {ms_unxline, 3}, {me_unxline, 2}, {mo_unxline, 2}}
72 mapi_clist_av1 xline_clist[] = { &xline_msgtab, &unxline_msgtab, NULL };
73 DECLARE_MODULE_AV1(xline, NULL, NULL, xline_clist, NULL, NULL, "$Revision: 23291 $");
75 static int valid_xline(struct Client *, const char *, const char *, int temp);
76 static void apply_xline(struct Client *client_p, const char *name,
77 const char *reason, int temp_time);
78 static void write_xline(struct Client *source_p, struct ConfItem *aconf);
79 static void propagate_xline(struct Client *source_p, const char *target,
80 int temp_time, const char *name,
81 const char *type, const char *reason);
82 static void cluster_xline(struct Client *source_p, int temp_time,
83 const char *name, const char *reason);
85 static void handle_remote_xline(struct Client *source_p, int temp_time,
86 const char *name, const char *reason);
87 static void handle_remote_unxline(struct Client *source_p, const char *name);
89 static int remove_temp_xline(struct Client *source_p, const char *name);
90 static void remove_xline(struct Client *source_p, const char *gecos);
93 /* m_xline()
95 * parv[1] - thing to xline
96 * parv[2] - optional type/reason
97 * parv[3] - reason
99 static int
100 mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
102 struct ConfItem *aconf;
103 const char *name;
104 const char *reason;
105 const char *target_server = NULL;
106 int temp_time;
107 int loc = 1;
109 if(!IsOperXline(source_p))
111 sendto_one(source_p, form_str(ERR_NOPRIVS),
112 me.name, source_p->name, "xline");
113 return 0;
116 if((temp_time = valid_temp_time(parv[loc])) >= 0)
117 loc++;
118 /* we just set temp_time to -1! */
119 else
120 temp_time = 0;
122 name = parv[loc];
123 loc++;
125 /* XLINE <gecos> ON <server> :<reason> */
126 if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
128 if(!IsOperRemoteBan(source_p))
130 sendto_one(source_p, form_str(ERR_NOPRIVS),
131 me.name, source_p->name, "remoteban");
132 return 0;
135 target_server = parv[loc+1];
136 loc += 2;
139 if(parc <= loc || EmptyString(parv[loc]))
141 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
142 me.name, source_p->name, "XLINE");
143 return 0;
146 reason = parv[loc];
148 if(target_server != NULL)
150 propagate_xline(source_p, target_server, temp_time,
151 name, "2", reason);
153 if(!match(target_server, me.name))
154 return 0;
156 else if(dlink_list_length(&cluster_conf_list) > 0)
157 cluster_xline(source_p, temp_time, name, reason);
159 if((aconf = find_xline(name, 0)) != NULL)
161 sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
162 me.name, source_p->name, parv[1], aconf->name, aconf->passwd);
163 return 0;
166 if(!valid_xline(source_p, name, reason, temp_time))
167 return 0;
169 apply_xline(source_p, name, reason, temp_time);
171 return 0;
174 /* ms_xline()
176 * handles a remote xline
178 static int
179 ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
181 /* parv[0] parv[1] parv[2] parv[3] parv[4]
182 * oper target serv xline type reason
184 propagate_xline(source_p, parv[1], 0, parv[2], parv[3], parv[4]);
186 if(!IsPerson(source_p))
187 return 0;
189 /* destined for me? */
190 if(!match(parv[1], me.name))
191 return 0;
193 handle_remote_xline(source_p, 0, parv[2], parv[4]);
194 return 0;
197 static int
198 me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
200 /* time name type :reason */
201 if(!IsPerson(source_p))
202 return 0;
204 handle_remote_xline(source_p, atoi(parv[1]), parv[2], parv[4]);
205 return 0;
208 static void
209 handle_remote_xline(struct Client *source_p, int temp_time,
210 const char *name, const char *reason)
212 struct ConfItem *aconf;
214 if(!find_shared_conf(source_p->username, source_p->host,
215 source_p->servptr->name,
216 (temp_time > 0) ? SHARED_TXLINE : SHARED_PXLINE))
217 return;
219 if(!valid_xline(source_p, name, reason, temp_time))
220 return;
222 /* already xlined */
223 if((aconf = find_xline(name, 0)) != NULL)
225 sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
226 me.name, source_p->name, name,
227 aconf->name, aconf->passwd);
228 return;
231 apply_xline(source_p, name, reason, temp_time);
234 /* valid_xline()
236 * inputs - client xlining, gecos, reason and whether to warn
237 * outputs -
238 * side effects - checks the xline for validity, erroring if needed
240 static int
241 valid_xline(struct Client *source_p, const char *gecos,
242 const char *reason, int temp_time)
244 if(EmptyString(reason))
246 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
247 get_id(&me, source_p),
248 get_id(source_p, source_p), "XLINE");
249 return 0;
252 if(strchr(reason, ':') != NULL)
254 sendto_one_notice(source_p,
255 ":Invalid character ':' in comment");
256 return 0;
259 if(strchr(reason, '"'))
261 sendto_one_notice(source_p,
262 ":Invalid character '\"' in comment");
263 return 0;
266 if(!valid_wild_card_simple(gecos))
268 sendto_one_notice(source_p,
269 ":Please include at least %d non-wildcard "
270 "characters with the xline",
271 ConfigFileEntry.min_nonwildcard_simple);
272 return 0;
275 /* The following test checks for an xline which would break the
276 * parser (which doesnt understand quoting).
278 * We dont lose much here, permanent versions of these would break
279 * the parser on a reload anyway. --anfl
281 if(!temp_time && strstr(gecos, "\","))
283 sendto_one_notice(source_p,
284 ":Xlines containing \", must be temporary.");
285 return 0;
288 return 1;
291 void
292 apply_xline(struct Client *source_p, const char *name, const char *reason,
293 int temp_time)
295 struct ConfItem *aconf;
297 aconf = make_conf();
298 aconf->status = CONF_XLINE;
300 if(strstr(name, "\\s"))
302 char *tmp = LOCAL_COPY(name);
303 char *orig = tmp;
304 char *new = tmp;
306 while(*orig)
308 if(*orig == '\\' && *(orig + 1) != '\0')
310 if(*(orig + 1) == 's')
312 *new++ = ' ';
313 orig += 2;
315 /* otherwise skip that and the escaped
316 * character after it, so we dont mistake
317 * \\s as \s --fl
319 else
321 *new++ = *orig++;
322 *new++ = *orig++;
325 else
326 *new++ = *orig++;
329 *new = '\0';
330 DupString(aconf->name, tmp);
332 else
333 DupString(aconf->name, name);
335 DupString(aconf->passwd, reason);
336 collapse(aconf->name);
338 if(temp_time > 0)
340 aconf->hold = CurrentTime + temp_time;
342 sendto_realops_flags(UMODE_ALL, L_ALL,
343 "%s added temporary %d min. X-Line for [%s] [%s]",
344 get_oper_name(source_p), temp_time / 60,
345 aconf->name, reason);
346 ilog(L_KLINE, "X %s %d %s %s",
347 get_oper_name(source_p), temp_time / 60,
348 name, reason);
349 sendto_one_notice(source_p, ":Added temporary %d min. X-Line [%s]",
350 temp_time / 60, aconf->name);
352 else
354 write_xline(source_p, aconf);
356 sendto_realops_flags(UMODE_ALL, L_ALL, "%s added X-Line for [%s] [%s]",
357 get_oper_name(source_p),
358 aconf->name, aconf->passwd);
359 sendto_one_notice(source_p, ":Added X-Line for [%s] [%s]",
360 aconf->name, aconf->passwd);
361 ilog(L_KLINE, "X %s 0 %s %s",
362 get_oper_name(source_p), name, reason);
365 dlinkAddAlloc(aconf, &xline_conf_list);
366 check_xlines();
369 /* write_xline()
371 * inputs - gecos, reason, xline type
372 * outputs - writes an xline to the config
373 * side effects -
375 static void
376 write_xline(struct Client *source_p, struct ConfItem *aconf)
378 char buffer[BUFSIZE * 2];
379 FILE *out;
380 const char *filename;
382 filename = ConfigFileEntry.xlinefile;
384 if((out = fopen(filename, "a")) == NULL)
386 sendto_realops_flags(UMODE_ALL, L_ALL, "*** Problem opening %s ", filename);
387 free_conf(aconf);
388 return;
391 ircsprintf(buffer, "\"%s\",\"0\",\"%s\",\"%s\",%ld\n",
392 aconf->name, aconf->passwd,
393 get_oper_name(source_p), CurrentTime);
395 if(fputs(buffer, out) == -1)
397 sendto_realops_flags(UMODE_ALL, L_ALL, "*** Problem writing to %s", filename);
398 free_conf(aconf);
399 fclose(out);
400 return;
403 fclose(out);
406 static void
407 propagate_xline(struct Client *source_p, const char *target,
408 int temp_time, const char *name, const char *type,
409 const char *reason)
411 if(!temp_time)
413 sendto_match_servs(source_p, target, CAP_CLUSTER, NOCAPS,
414 "XLINE %s %s %s :%s",
415 target, name, type, reason);
416 sendto_match_servs(source_p, target, CAP_ENCAP, CAP_CLUSTER,
417 "ENCAP %s XLINE %d %s 2 :%s",
418 target, temp_time, name, reason);
420 else
421 sendto_match_servs(source_p, target, CAP_ENCAP, NOCAPS,
422 "ENCAP %s XLINE %d %s %s :%s",
423 target, temp_time, name, type, reason);
426 static void
427 cluster_xline(struct Client *source_p, int temp_time, const char *name,
428 const char *reason)
430 struct remote_conf *shared_p;
431 dlink_node *ptr;
433 DLINK_FOREACH(ptr, cluster_conf_list.head)
435 shared_p = ptr->data;
437 /* old protocol cant handle temps, and we dont really want
438 * to convert them to perm.. --fl
440 if(!temp_time)
442 if(!(shared_p->flags & SHARED_PXLINE))
443 continue;
445 sendto_match_servs(source_p, shared_p->server, CAP_CLUSTER, NOCAPS,
446 "XLINE %s %s 2 :%s",
447 shared_p->server, name, reason);
448 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, CAP_CLUSTER,
449 "ENCAP %s XLINE 0 %s 2 :%s",
450 shared_p->server, name, reason);
452 else if(shared_p->flags & SHARED_TXLINE)
453 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, NOCAPS,
454 "ENCAP %s XLINE %d %s 2 :%s",
455 shared_p->server, temp_time, name, reason);
459 /* mo_unxline()
461 * parv[1] - thing to unxline
463 static int
464 mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
466 if(!IsOperXline(source_p))
468 sendto_one(source_p, form_str(ERR_NOPRIVS),
469 me.name, source_p->name, "xline");
470 return 0;
473 if(parc == 4 && !(irccmp(parv[2], "ON")))
475 if(!IsOperRemoteBan(source_p))
477 sendto_one(source_p, form_str(ERR_NOPRIVS),
478 me.name, source_p->name, "remoteban");
479 return 0;
482 propagate_generic(source_p, "UNXLINE", parv[3], CAP_CLUSTER,
483 "%s", parv[1]);
485 if(match(parv[3], me.name) == 0)
486 return 0;
488 else if(dlink_list_length(&cluster_conf_list))
489 cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER,
490 "%s", parv[1]);
492 if(remove_temp_xline(source_p, parv[1]))
493 return 0;
495 remove_xline(source_p, parv[1]);
497 return 0;
500 /* ms_unxline()
502 * handles a remote unxline
504 static int
505 ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
507 /* parv[0] parv[1] parv[2]
508 * oper target server gecos
510 propagate_generic(source_p, "UNXLINE", parv[1], CAP_CLUSTER,
511 "%s", parv[2]);
513 if(!match(parv[1], me.name))
514 return 0;
516 if(!IsPerson(source_p))
517 return 0;
519 handle_remote_unxline(source_p, parv[2]);
520 return 0;
523 static int
524 me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
526 /* name */
527 if(!IsPerson(source_p))
528 return 0;
530 handle_remote_unxline(source_p, parv[1]);
531 return 0;
534 static void
535 handle_remote_unxline(struct Client *source_p, const char *name)
537 if(!find_shared_conf(source_p->username, source_p->host,
538 source_p->servptr->name, SHARED_UNXLINE))
539 return;
541 if(remove_temp_xline(source_p, name))
542 return;
544 remove_xline(source_p, name);
546 return;
549 static int
550 remove_temp_xline(struct Client *source_p, const char *name)
552 struct ConfItem *aconf;
553 dlink_node *ptr;
555 DLINK_FOREACH(ptr, xline_conf_list.head)
557 aconf = ptr->data;
559 /* only want to check temp ones! */
560 if(!aconf->hold)
561 continue;
563 if(!irccmp(aconf->name, name))
565 sendto_one_notice(source_p,
566 ":X-Line for [%s] is removed",
567 name);
568 sendto_realops_flags(UMODE_ALL, L_ALL,
569 "%s has removed the temporary X-Line for: [%s]",
570 get_oper_name(source_p), name);
571 ilog(L_KLINE, "UX %s %s",
572 get_oper_name(source_p), name);
574 free_conf(aconf);
575 dlinkDestroy(ptr, &xline_conf_list);
576 return 1;
580 return 0;
583 /* remove_xline()
585 * inputs - gecos to remove
586 * outputs -
587 * side effects - removes xline from conf, if exists
589 static void
590 remove_xline(struct Client *source_p, const char *huntgecos)
592 FILE *in, *out;
593 char buf[BUFSIZE];
594 char buff[BUFSIZE];
595 char temppath[BUFSIZE];
596 const char *filename;
597 const char *gecos;
598 mode_t oldumask;
599 char *p;
600 int error_on_write = 0;
601 int found_xline = 0;
603 filename = ConfigFileEntry.xlinefile;
604 ircsnprintf(temppath, sizeof(temppath),
605 "%s.tmp", ConfigFileEntry.xlinefile);
607 if((in = fopen(filename, "r")) == NULL)
609 sendto_one_notice(source_p, ":Cannot open %s", filename);
610 return;
613 oldumask = umask(0);
615 if((out = fopen(temppath, "w")) == NULL)
617 sendto_one_notice(source_p, ":Cannot open %s", temppath);
618 fclose(in);
619 umask(oldumask);
620 return;
623 umask(oldumask);
625 while (fgets(buf, sizeof(buf), in))
627 if(error_on_write)
629 if(temppath != NULL)
630 (void) unlink(temppath);
632 break;
635 strlcpy(buff, buf, sizeof(buff));
637 if((p = strchr(buff, '\n')) != NULL)
638 *p = '\0';
640 if((*buff == '\0') || (*buff == '#'))
642 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
643 continue;
646 if((gecos = getfield(buff)) == NULL)
648 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
649 continue;
652 /* matching.. */
653 if(irccmp(gecos, huntgecos) == 0)
654 found_xline++;
655 else
656 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
659 fclose(in);
660 fclose(out);
662 if(error_on_write)
664 sendto_one_notice(source_p,
665 ":Couldn't write temp xline file, aborted");
666 return;
668 else if(found_xline == 0)
670 sendto_one_notice(source_p, ":No X-Line for %s", huntgecos);
672 if(temppath != NULL)
673 (void) unlink(temppath);
674 return;
677 (void) rename(temppath, filename);
678 rehash_bans(0);
680 sendto_one_notice(source_p, ":X-Line for [%s] is removed", huntgecos);
681 sendto_realops_flags(UMODE_ALL, L_ALL,
682 "%s has removed the X-Line for: [%s]",
683 get_oper_name(source_p), huntgecos);
684 ilog(L_KLINE, "UX %s %s", get_oper_name(source_p), huntgecos);