]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_xline.c
Speed up /undline similarly
[irc/rqf/shadowircd.git] / modules / m_xline.c
CommitLineData
212380e3 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
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
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.
17 *
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.
29 *
5366977b 30 * $Id: m_xline.c 3161 2007-01-25 07:23:01Z nenolod $
212380e3 31 */
32
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"
55
56static int mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
57static int ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
58static int me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
59static int mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
60static int ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
61static int me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[]);
62
63struct 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}}
66};
67struct 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}}
70};
71
72mapi_clist_av1 xline_clist[] = { &xline_msgtab, &unxline_msgtab, NULL };
5366977b 73DECLARE_MODULE_AV1(xline, NULL, NULL, xline_clist, NULL, NULL, "$Revision: 3161 $");
212380e3 74
75static int valid_xline(struct Client *, const char *, const char *);
76static void apply_xline(struct Client *client_p, const char *name,
77 const char *reason, int temp_time);
78static void write_xline(struct Client *source_p, struct ConfItem *aconf);
79static void propagate_xline(struct Client *source_p, const char *target,
80 int temp_time, const char *name,
81 const char *type, const char *reason);
82static void cluster_xline(struct Client *source_p, int temp_time,
83 const char *name, const char *reason);
84
85static void handle_remote_xline(struct Client *source_p, int temp_time,
86 const char *name, const char *reason);
87static void handle_remote_unxline(struct Client *source_p, const char *name);
88
89static int remove_temp_xline(struct Client *source_p, const char *name);
90static void remove_xline(struct Client *source_p, const char *gecos);
91
92
93/* m_xline()
94 *
95 * parv[1] - thing to xline
96 * parv[2] - optional type/reason
97 * parv[3] - reason
98 */
99static int
100mo_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
101{
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;
108
109 if(!IsOperXline(source_p))
110 {
111 sendto_one(source_p, form_str(ERR_NOPRIVS),
112 me.name, source_p->name, "xline");
113 return 0;
114 }
115
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;
121
122 name = parv[loc];
123 loc++;
124
125 /* XLINE <gecos> ON <server> :<reason> */
126 if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
127 {
128 if(!IsOperRemoteBan(source_p))
129 {
130 sendto_one(source_p, form_str(ERR_NOPRIVS),
131 me.name, source_p->name, "remoteban");
132 return 0;
133 }
134
135 target_server = parv[loc+1];
136 loc += 2;
137 }
138
139 if(parc <= loc || EmptyString(parv[loc]))
140 {
141 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
142 me.name, source_p->name, "XLINE");
143 return 0;
144 }
145
146 reason = parv[loc];
147
148 if(target_server != NULL)
149 {
150 propagate_xline(source_p, target_server, temp_time,
151 name, "2", reason);
152
153 if(!match(target_server, me.name))
154 return 0;
155 }
156 else if(dlink_list_length(&cluster_conf_list) > 0)
157 cluster_xline(source_p, temp_time, name, reason);
158
0fdb2570 159 if((aconf = find_xline_mask(name)) != NULL)
212380e3 160 {
161 sendto_one(source_p, ":%s NOTICE %s :[%s] already X-Lined by [%s] - %s",
60e127c1 162 me.name, source_p->name, name, aconf->name, aconf->passwd);
212380e3 163 return 0;
164 }
165
166 if(!valid_xline(source_p, name, reason))
167 return 0;
168
169 apply_xline(source_p, name, reason, temp_time);
170
171 return 0;
172}
173
174/* ms_xline()
175 *
176 * handles a remote xline
177 */
178static int
179ms_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
180{
181 /* parv[0] parv[1] parv[2] parv[3] parv[4]
182 * oper target serv xline type reason
183 */
184 propagate_xline(source_p, parv[1], 0, parv[2], parv[3], parv[4]);
185
186 if(!IsPerson(source_p))
187 return 0;
188
189 /* destined for me? */
190 if(!match(parv[1], me.name))
191 return 0;
192
193 handle_remote_xline(source_p, 0, parv[2], parv[4]);
194 return 0;
195}
196
197static int
198me_xline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
199{
200 /* time name type :reason */
201 if(!IsPerson(source_p))
202 return 0;
203
204 handle_remote_xline(source_p, atoi(parv[1]), parv[2], parv[4]);
205 return 0;
206}
207
208static void
209handle_remote_xline(struct Client *source_p, int temp_time,
210 const char *name, const char *reason)
211{
212 struct ConfItem *aconf;
213
214 if(!find_shared_conf(source_p->username, source_p->host,
c88cdb00 215 source_p->servptr->name,
212380e3 216 (temp_time > 0) ? SHARED_TXLINE : SHARED_PXLINE))
217 return;
218
219 if(!valid_xline(source_p, name, reason))
220 return;
221
222 /* already xlined */
0fdb2570 223 if((aconf = find_xline_mask(name)) != NULL)
212380e3 224 {
5366977b 225 sendto_one_notice(source_p, ":[%s] already X-Lined by [%s] - %s", name, aconf->name, aconf->passwd);
212380e3 226 return;
227 }
228
229 apply_xline(source_p, name, reason, temp_time);
230}
231
232/* valid_xline()
233 *
234 * inputs - client xlining, gecos, reason and whether to warn
235 * outputs -
236 * side effects - checks the xline for validity, erroring if needed
237 */
238static int
239valid_xline(struct Client *source_p, const char *gecos,
240 const char *reason)
241{
242 if(EmptyString(reason))
243 {
244 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
245 get_id(&me, source_p),
246 get_id(source_p, source_p), "XLINE");
247 return 0;
248 }
249
250 if(strchr(reason, ':') != NULL)
251 {
252 sendto_one_notice(source_p,
253 ":Invalid character ':' in comment");
254 return 0;
255 }
256
257 if(strchr(reason, '"'))
258 {
259 sendto_one_notice(source_p,
260 ":Invalid character '\"' in comment");
261 return 0;
262 }
263
264 if(!valid_wild_card_simple(gecos))
265 {
266 sendto_one_notice(source_p,
267 ":Please include at least %d non-wildcard "
268 "characters with the xline",
269 ConfigFileEntry.min_nonwildcard_simple);
270 return 0;
271 }
272
273 return 1;
274}
275
276void
277apply_xline(struct Client *source_p, const char *name, const char *reason,
278 int temp_time)
279{
280 struct ConfItem *aconf;
281
282 aconf = make_conf();
283 aconf->status = CONF_XLINE;
284
285 if(strstr(name, "\\s"))
286 {
287 char *tmp = LOCAL_COPY(name);
288 char *orig = tmp;
289 char *new = tmp;
290
291 while(*orig)
292 {
293 if(*orig == '\\' && *(orig + 1) != '\0')
294 {
295 if(*(orig + 1) == 's')
296 {
297 *new++ = ' ';
298 orig += 2;
299 }
300 /* otherwise skip that and the escaped
301 * character after it, so we dont mistake
302 * \\s as \s --fl
303 */
304 else
305 {
306 *new++ = *orig++;
307 *new++ = *orig++;
308 }
309 }
310 else
311 *new++ = *orig++;
312 }
313
314 *new = '\0';
315 DupString(aconf->name, tmp);
316 }
317 else
318 DupString(aconf->name, name);
319
320 DupString(aconf->passwd, reason);
321 collapse(aconf->name);
322
323 if(temp_time > 0)
324 {
325 aconf->hold = CurrentTime + temp_time;
326
327 sendto_realops_snomask(SNO_GENERAL, L_ALL,
328 "%s added temporary %d min. X-Line for [%s] [%s]",
329 get_oper_name(source_p), temp_time / 60,
330 aconf->name, reason);
331 ilog(L_KLINE, "X %s %d %s %s",
332 get_oper_name(source_p), temp_time / 60,
333 name, reason);
334 sendto_one_notice(source_p, ":Added temporary %d min. X-Line [%s]",
335 temp_time / 60, aconf->name);
336 }
337 else
338 {
339 sendto_realops_snomask(SNO_GENERAL, L_ALL, "%s added X-Line for [%s] [%s]",
340 get_oper_name(source_p),
341 aconf->name, aconf->passwd);
342 sendto_one_notice(source_p, ":Added X-Line for [%s] [%s]",
343 aconf->name, aconf->passwd);
344 write_xline(source_p, aconf);
345 ilog(L_KLINE, "X %s 0 %s %s",
346 get_oper_name(source_p), name, reason);
347 }
348
349 dlinkAddAlloc(aconf, &xline_conf_list);
350 check_xlines();
351}
352
353/* write_xline()
354 *
355 * inputs - gecos, reason, xline type
356 * outputs - writes an xline to the config
357 * side effects -
358 */
359static void
360write_xline(struct Client *source_p, struct ConfItem *aconf)
361{
362 char buffer[BUFSIZE * 2];
363 FILE *out;
364 const char *filename;
365
366 filename = ConfigFileEntry.xlinefile;
367
368 if((out = fopen(filename, "a")) == NULL)
369 {
370 sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem opening %s ", filename);
371 sendto_one_notice(source_p, ":*** Problem opening file, xline added temporarily only");
372 return;
373 }
374
375 ircsprintf(buffer, "\"%s\",\"0\",\"%s\",\"%s\",%ld\n",
376 aconf->name, aconf->passwd,
377 get_oper_name(source_p), CurrentTime);
378
379 if(fputs(buffer, out) == -1)
380 {
381 sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
382 sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
383 fclose(out);
384 return;
385 }
386
387 if(fclose(out))
388 {
389 sendto_realops_snomask(SNO_GENERAL, L_ALL, "*** Problem writing to %s", filename);
390 sendto_one_notice(source_p, ":*** Problem writing to file, xline added temporarily only");
391 return;
392 }
393}
394
395static void
396propagate_xline(struct Client *source_p, const char *target,
397 int temp_time, const char *name, const char *type,
398 const char *reason)
399{
400 if(!temp_time)
401 {
402 sendto_match_servs(source_p, target, CAP_CLUSTER, NOCAPS,
403 "XLINE %s %s %s :%s",
404 target, name, type, reason);
405 sendto_match_servs(source_p, target, CAP_ENCAP, CAP_CLUSTER,
406 "ENCAP %s XLINE %d %s 2 :%s",
407 target, temp_time, name, reason);
408 }
409 else
410 sendto_match_servs(source_p, target, CAP_ENCAP, NOCAPS,
411 "ENCAP %s XLINE %d %s %s :%s",
412 target, temp_time, name, type, reason);
413}
414
415static void
416cluster_xline(struct Client *source_p, int temp_time, const char *name,
417 const char *reason)
418{
419 struct remote_conf *shared_p;
420 dlink_node *ptr;
421
422 DLINK_FOREACH(ptr, cluster_conf_list.head)
423 {
424 shared_p = ptr->data;
425
426 /* old protocol cant handle temps, and we dont really want
427 * to convert them to perm.. --fl
428 */
429 if(!temp_time)
430 {
431 if(!(shared_p->flags & SHARED_PXLINE))
432 continue;
433
434 sendto_match_servs(source_p, shared_p->server, CAP_CLUSTER, NOCAPS,
435 "XLINE %s %s 2 :%s",
436 shared_p->server, name, reason);
437 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, CAP_CLUSTER,
438 "ENCAP %s XLINE 0 %s 2 :%s",
439 shared_p->server, name, reason);
440 }
441 else if(shared_p->flags & SHARED_TXLINE)
442 sendto_match_servs(source_p, shared_p->server, CAP_ENCAP, NOCAPS,
443 "ENCAP %s XLINE %d %s 2 :%s",
444 shared_p->server, temp_time, name, reason);
445 }
446}
447
448/* mo_unxline()
449 *
450 * parv[1] - thing to unxline
451 */
452static int
453mo_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
454{
455 if(!IsOperXline(source_p))
456 {
457 sendto_one(source_p, form_str(ERR_NOPRIVS),
458 me.name, source_p->name, "xline");
459 return 0;
460 }
461
462 if(parc == 4 && !(irccmp(parv[2], "ON")))
463 {
464 if(!IsOperRemoteBan(source_p))
465 {
466 sendto_one(source_p, form_str(ERR_NOPRIVS),
467 me.name, source_p->name, "remoteban");
468 return 0;
469 }
470
471 propagate_generic(source_p, "UNXLINE", parv[3], CAP_CLUSTER,
472 "%s", parv[1]);
473
474 if(match(parv[3], me.name) == 0)
475 return 0;
476 }
477 else if(dlink_list_length(&cluster_conf_list))
478 cluster_generic(source_p, "UNXLINE", SHARED_UNXLINE, CAP_CLUSTER,
479 "%s", parv[1]);
480
481 if(remove_temp_xline(source_p, parv[1]))
482 return 0;
483
484 remove_xline(source_p, parv[1]);
485
486 return 0;
487}
488
489/* ms_unxline()
490 *
491 * handles a remote unxline
492 */
493static int
494ms_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
495{
496 /* parv[0] parv[1] parv[2]
497 * oper target server gecos
498 */
499 propagate_generic(source_p, "UNXLINE", parv[1], CAP_CLUSTER,
500 "%s", parv[2]);
501
502 if(!match(parv[1], me.name))
503 return 0;
504
505 if(!IsPerson(source_p))
506 return 0;
507
508 handle_remote_unxline(source_p, parv[2]);
509 return 0;
510}
511
512static int
513me_unxline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
514{
515 /* name */
516 if(!IsPerson(source_p))
517 return 0;
518
519 handle_remote_unxline(source_p, parv[1]);
520 return 0;
521}
522
523static void
524handle_remote_unxline(struct Client *source_p, const char *name)
525{
526 if(!find_shared_conf(source_p->username, source_p->host,
c88cdb00 527 source_p->servptr->name, SHARED_UNXLINE))
212380e3 528 return;
529
530 if(remove_temp_xline(source_p, name))
531 return;
532
533 remove_xline(source_p, name);
534
535 return;
536}
537
538static int
539remove_temp_xline(struct Client *source_p, const char *name)
540{
541 struct ConfItem *aconf;
542 dlink_node *ptr;
543
544 DLINK_FOREACH(ptr, xline_conf_list.head)
545 {
546 aconf = ptr->data;
547
548 /* only want to check temp ones! */
549 if(!aconf->hold)
550 continue;
551
552 if(!irccmp(aconf->name, name))
553 {
554 sendto_one_notice(source_p,
555 ":X-Line for [%s] is removed",
556 name);
557 sendto_realops_snomask(SNO_GENERAL, L_ALL,
558 "%s has removed the temporary X-Line for: [%s]",
559 get_oper_name(source_p), name);
560 ilog(L_KLINE, "UX %s %s",
561 get_oper_name(source_p), name);
562
563 free_conf(aconf);
564 dlinkDestroy(ptr, &xline_conf_list);
565 return 1;
566 }
567 }
568
569 return 0;
570}
571
572/* remove_xline()
573 *
574 * inputs - gecos to remove
575 * outputs -
576 * side effects - removes xline from conf, if exists
577 */
578static void
579remove_xline(struct Client *source_p, const char *huntgecos)
580{
581 FILE *in, *out;
582 char buf[BUFSIZE];
583 char buff[BUFSIZE];
584 char temppath[BUFSIZE];
585 const char *filename;
586 const char *gecos;
587 mode_t oldumask;
588 char *p;
589 int error_on_write = 0;
590 int found_xline = 0;
591
592 filename = ConfigFileEntry.xlinefile;
593 ircsnprintf(temppath, sizeof(temppath),
594 "%s.tmp", ConfigFileEntry.xlinefile);
595
596 if((in = fopen(filename, "r")) == NULL)
597 {
598 sendto_one_notice(source_p, ":Cannot open %s", filename);
599 return;
600 }
601
602 oldumask = umask(0);
603
604 if((out = fopen(temppath, "w")) == NULL)
605 {
606 sendto_one_notice(source_p, ":Cannot open %s", temppath);
607 fclose(in);
608 umask(oldumask);
609 return;
610 }
611
612 umask(oldumask);
613
614 while (fgets(buf, sizeof(buf), in))
615 {
616 if(error_on_write)
617 {
618 if(temppath != NULL)
619 (void) unlink(temppath);
620
621 break;
622 }
623
624 strlcpy(buff, buf, sizeof(buff));
625
626 if((p = strchr(buff, '\n')) != NULL)
627 *p = '\0';
628
629 if((*buff == '\0') || (*buff == '#'))
630 {
631 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
632 continue;
633 }
634
635 if((gecos = getfield(buff)) == NULL)
636 {
637 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
638 continue;
639 }
640
641 /* matching.. */
642 if(irccmp(gecos, huntgecos) == 0)
643 found_xline++;
644 else
645 error_on_write = (fputs(buf, out) < 0) ? YES : NO;
646 }
647
648 fclose(in);
649 if (fclose(out))
650 error_on_write = YES;
651
652 if(error_on_write)
653 {
654 sendto_one_notice(source_p,
655 ":Couldn't write temp xline file, aborted");
656 return;
657 }
658 else if(found_xline == 0)
659 {
660 sendto_one_notice(source_p, ":No X-Line for %s", huntgecos);
661
662 if(temppath != NULL)
663 (void) unlink(temppath);
664 return;
665 }
666
667 if (rename(temppath, filename))
668 {
669 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
670 return;
671 }
672 rehash_bans(0);
673
674 sendto_one_notice(source_p, ":X-Line for [%s] is removed", huntgecos);
675 sendto_realops_snomask(SNO_GENERAL, L_ALL,
676 "%s has removed the X-Line for: [%s]",
677 get_oper_name(source_p), huntgecos);
678 ilog(L_KLINE, "UX %s %s", get_oper_name(source_p), huntgecos);
679}