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
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 $
47 #include "irc_string.h"
48 #include "sprintf_irc.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
);
95 * parv[1] - thing to xline
96 * parv[2] - optional type/reason
100 mo_xline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
102 struct ConfItem
*aconf
;
105 const char *target_server
= NULL
;
109 if(!IsOperXline(source_p
))
111 sendto_one(source_p
, form_str(ERR_NOPRIVS
),
112 me
.name
, source_p
->name
, "xline");
116 if((temp_time
= valid_temp_time(parv
[loc
])) >= 0)
118 /* we just set temp_time to -1! */
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");
135 target_server
= parv
[loc
+1];
139 if(parc
<= loc
|| EmptyString(parv
[loc
]))
141 sendto_one(source_p
, form_str(ERR_NEEDMOREPARAMS
),
142 me
.name
, source_p
->name
, "XLINE");
148 if(target_server
!= NULL
)
150 propagate_xline(source_p
, target_server
, temp_time
,
153 if(!match(target_server
, me
.name
))
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
);
166 if(!valid_xline(source_p
, name
, reason
, temp_time
))
169 apply_xline(source_p
, name
, reason
, temp_time
);
176 * handles a remote xline
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
))
189 /* destined for me? */
190 if(!match(parv
[1], me
.name
))
193 handle_remote_xline(source_p
, 0, parv
[2], parv
[4]);
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
))
204 handle_remote_xline(source_p
, atoi(parv
[1]), parv
[2], parv
[4]);
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
))
219 if(!valid_xline(source_p
, name
, reason
, temp_time
))
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
);
231 apply_xline(source_p
, name
, reason
, temp_time
);
236 * inputs - client xlining, gecos, reason and whether to warn
238 * side effects - checks the xline for validity, erroring if needed
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");
252 if(strchr(reason
, ':') != NULL
)
254 sendto_one_notice(source_p
,
255 ":Invalid character ':' in comment");
259 if(strchr(reason
, '"'))
261 sendto_one_notice(source_p
,
262 ":Invalid character '\"' in comment");
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
);
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.");
292 apply_xline(struct Client
*source_p
, const char *name
, const char *reason
,
295 struct ConfItem
*aconf
;
298 aconf
->status
= CONF_XLINE
;
300 if(strstr(name
, "\\s"))
302 char *tmp
= LOCAL_COPY(name
);
308 if(*orig
== '\\' && *(orig
+ 1) != '\0')
310 if(*(orig
+ 1) == 's')
315 /* otherwise skip that and the escaped
316 * character after it, so we dont mistake
330 DupString(aconf
->name
, tmp
);
333 DupString(aconf
->name
, name
);
335 DupString(aconf
->passwd
, reason
);
336 collapse(aconf
->name
);
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,
349 sendto_one_notice(source_p
, ":Added temporary %d min. X-Line [%s]",
350 temp_time
/ 60, aconf
->name
);
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
);
371 * inputs - gecos, reason, xline type
372 * outputs - writes an xline to the config
376 write_xline(struct Client
*source_p
, struct ConfItem
*aconf
)
378 char buffer
[BUFSIZE
* 2];
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
);
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
);
407 propagate_xline(struct Client
*source_p
, const char *target
,
408 int temp_time
, const char *name
, const char *type
,
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
);
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
);
427 cluster_xline(struct Client
*source_p
, int temp_time
, const char *name
,
430 struct remote_conf
*shared_p
;
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
442 if(!(shared_p
->flags
& SHARED_PXLINE
))
445 sendto_match_servs(source_p
, shared_p
->server
, CAP_CLUSTER
, NOCAPS
,
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
);
461 * parv[1] - thing to unxline
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");
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");
482 propagate_generic(source_p
, "UNXLINE", parv
[3], CAP_CLUSTER
,
485 if(match(parv
[3], me
.name
) == 0)
488 else if(dlink_list_length(&cluster_conf_list
))
489 cluster_generic(source_p
, "UNXLINE", SHARED_UNXLINE
, CAP_CLUSTER
,
492 if(remove_temp_xline(source_p
, parv
[1]))
495 remove_xline(source_p
, parv
[1]);
502 * handles a remote unxline
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
,
513 if(!match(parv
[1], me
.name
))
516 if(!IsPerson(source_p
))
519 handle_remote_unxline(source_p
, parv
[2]);
524 me_unxline(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
527 if(!IsPerson(source_p
))
530 handle_remote_unxline(source_p
, parv
[1]);
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
))
541 if(remove_temp_xline(source_p
, name
))
544 remove_xline(source_p
, name
);
550 remove_temp_xline(struct Client
*source_p
, const char *name
)
552 struct ConfItem
*aconf
;
555 DLINK_FOREACH(ptr
, xline_conf_list
.head
)
559 /* only want to check temp ones! */
563 if(!irccmp(aconf
->name
, name
))
565 sendto_one_notice(source_p
,
566 ":X-Line for [%s] is removed",
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
);
575 dlinkDestroy(ptr
, &xline_conf_list
);
585 * inputs - gecos to remove
587 * side effects - removes xline from conf, if exists
590 remove_xline(struct Client
*source_p
, const char *huntgecos
)
595 char temppath
[BUFSIZE
];
596 const char *filename
;
600 int error_on_write
= 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
);
615 if((out
= fopen(temppath
, "w")) == NULL
)
617 sendto_one_notice(source_p
, ":Cannot open %s", temppath
);
625 while (fgets(buf
, sizeof(buf
), in
))
630 (void) unlink(temppath
);
635 strlcpy(buff
, buf
, sizeof(buff
));
637 if((p
= strchr(buff
, '\n')) != NULL
)
640 if((*buff
== '\0') || (*buff
== '#'))
642 error_on_write
= (fputs(buf
, out
) < 0) ? YES
: NO
;
646 if((gecos
= getfield(buff
)) == NULL
)
648 error_on_write
= (fputs(buf
, out
) < 0) ? YES
: NO
;
653 if(irccmp(gecos
, huntgecos
) == 0)
656 error_on_write
= (fputs(buf
, out
) < 0) ? YES
: NO
;
664 sendto_one_notice(source_p
,
665 ":Couldn't write temp xline file, aborted");
668 else if(found_xline
== 0)
670 sendto_one_notice(source_p
, ":No X-Line for %s", huntgecos
);
673 (void) unlink(temppath
);
677 (void) rename(temppath
, filename
);
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
);