]> jfr.im git - solanum.git/blob - modules/m_kline.c
4456d1afb5915904f220e694205529468c021f81
[solanum.git] / modules / m_kline.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_kline.c: Bans/unbans a user.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 */
24
25 #include "stdinc.h"
26 #include "channel.h"
27 #include "class.h"
28 #include "client.h"
29 #include "common.h"
30 #include "match.h"
31 #include "ircd.h"
32 #include "hostmask.h"
33 #include "numeric.h"
34 #include "s_conf.h"
35 #include "s_newconf.h"
36 #include "logger.h"
37 #include "send.h"
38 #include "hash.h"
39 #include "s_serv.h"
40 #include "msg.h"
41 #include "parse.h"
42 #include "modules.h"
43 #include "reject.h"
44 #include "bandbi.h"
45 #include "operhash.h"
46
47 static const char kline_desc[] = "Provides the KLINE facility to ban users via hostmask";
48
49 static void mo_kline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
50 static void ms_kline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
51 static void me_kline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
52 static void mo_unkline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
53 static void ms_unkline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
54 static void me_unkline(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
55
56 struct Message kline_msgtab = {
57 "KLINE", 0, 0, 0, 0,
58 {mg_unreg, mg_not_oper, {ms_kline, 5}, {ms_kline, 5}, {me_kline, 5}, {mo_kline, 3}}
59 };
60
61 struct Message unkline_msgtab = {
62 "UNKLINE", 0, 0, 0, 0,
63 {mg_unreg, mg_not_oper, {ms_unkline, 4}, {ms_unkline, 4}, {me_unkline, 3}, {mo_unkline, 2}}
64 };
65
66 mapi_clist_av1 kline_clist[] = { &kline_msgtab, &unkline_msgtab, NULL };
67
68 DECLARE_MODULE_AV2(kline, NULL, NULL, kline_clist, NULL, NULL, NULL, NULL, kline_desc);
69
70 /* Local function prototypes */
71 static bool find_user_host(struct Client *source_p, const char *userhost, char *user, char *host);
72 static bool valid_user_host(struct Client *source_p, const char *user, const char *host);
73
74 static void handle_remote_kline(struct Client *source_p, int tkline_time,
75 const char *user, const char *host, const char *reason);
76 static void apply_kline(struct Client *source_p, struct ConfItem *aconf,
77 const char *reason, const char *oper_reason);
78 static void apply_tkline(struct Client *source_p, struct ConfItem *aconf,
79 const char *, const char *, int);
80 static void apply_prop_kline(struct Client *source_p, struct ConfItem *aconf,
81 const char *, const char *, int);
82 static bool already_placed_kline(struct Client *, const char *, const char *, int);
83
84 static void handle_remote_unkline(struct Client *source_p, const char *user, const char *host);
85 static void remove_permkline_match(struct Client *, struct ConfItem *);
86 static bool remove_temp_kline(struct Client *, struct ConfItem *);
87 static void remove_prop_kline(struct Client *, struct ConfItem *);
88
89 /* mo_kline()
90 *
91 * parv[1] - temp time or user@host
92 * parv[2] - user@host, "ON", or reason
93 * parv[3] - "ON", reason, or server to target
94 * parv[4] - server to target, or reason
95 * parv[5] - reason
96 */
97 static void
98 mo_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char **parv)
99 {
100 char def[] = "No Reason";
101 char user[USERLEN + 2];
102 char host[HOSTLEN + 2];
103 char *reason = def;
104 char *oper_reason;
105 const char *target_server = NULL;
106 struct ConfItem *aconf;
107 int tkline_time = 0;
108 int loc = 1;
109 int propagated = ConfigFileEntry.use_propagated_bans;
110
111 if(!IsOperK(source_p))
112 {
113 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "kline");
114 return;
115 }
116
117 if((tkline_time = valid_temp_time(parv[loc])) >= 0)
118 loc++;
119 /* we just set tkline_time to -1! */
120 else
121 tkline_time = 0;
122
123 if(find_user_host(source_p, parv[loc], user, host) == 0)
124 return;
125
126 loc++;
127
128 if(parc >= loc + 2 && !irccmp(parv[loc], "ON"))
129 {
130 if(!IsOperRemoteBan(source_p))
131 {
132 sendto_one(source_p, form_str(ERR_NOPRIVS),
133 me.name, source_p->name, "remoteban");
134 return;
135 }
136
137 target_server = parv[loc + 1];
138 loc += 2;
139 }
140
141 if(parc <= loc || EmptyString(parv[loc]))
142 {
143 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
144 me.name, source_p->name, "KLINE");
145 return;
146 }
147
148 reason = LOCAL_COPY(parv[loc]);
149
150 if(target_server != NULL)
151 {
152 propagate_generic(source_p, "KLINE", target_server, CAP_KLN,
153 "%d %s %s :%s", tkline_time, user, host, reason);
154
155 /* If we are sending it somewhere that doesnt include us, stop */
156 if(!match(target_server, me.name))
157 return;
158
159 /* Set as local-only. */
160 propagated = 0;
161 }
162 /* if we have cluster servers, send it to them.. */
163 else if(!propagated && rb_dlink_list_length(&cluster_conf_list) > 0)
164 cluster_generic(source_p, "KLINE",
165 (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE, CAP_KLN,
166 "%lu %s %s :%s", tkline_time, user, host, reason);
167
168 if(!valid_user_host(source_p, user, host))
169 return;
170
171 if(!valid_wild_card(user, host))
172 {
173 sendto_one_notice(source_p,
174 ":Please include at least %d non-wildcard "
175 "characters with the user@host",
176 ConfigFileEntry.min_nonwildcard);
177 return;
178 }
179
180 if(propagated && tkline_time == 0)
181 {
182 sendto_one_notice(source_p, ":Cannot set a permanent global ban");
183 return;
184 }
185
186 if(already_placed_kline(source_p, user, host, tkline_time))
187 return;
188
189 rb_set_time();
190 aconf = make_conf();
191 aconf->status = CONF_KILL;
192 aconf->created = rb_current_time();
193 aconf->host = rb_strdup(host);
194 aconf->user = rb_strdup(user);
195 aconf->port = 0;
196 aconf->info.oper = operhash_add(get_oper_name(source_p));
197
198 if(strlen(reason) > BANREASONLEN)
199 reason[BANREASONLEN] = '\0';
200
201 /* Look for an oper reason */
202 if((oper_reason = strchr(reason, '|')) != NULL)
203 {
204 *oper_reason = '\0';
205 oper_reason++;
206
207 if(!EmptyString(oper_reason))
208 aconf->spasswd = rb_strdup(oper_reason);
209 }
210 aconf->passwd = rb_strdup(reason);
211
212 if(propagated)
213 apply_prop_kline(source_p, aconf, reason, oper_reason, tkline_time);
214 else if(tkline_time > 0)
215 apply_tkline(source_p, aconf, reason, oper_reason, tkline_time);
216 else
217 apply_kline(source_p, aconf, reason, oper_reason);
218
219 if(ConfigFileEntry.kline_delay)
220 {
221 if(kline_queued == 0)
222 {
223 rb_event_addonce("check_klines", check_klines_event, NULL,
224 ConfigFileEntry.kline_delay);
225 kline_queued = 1;
226 }
227 }
228 else
229 check_klines();
230 }
231
232 /* ms_kline()
233 *
234 * parv[1] - server targeted at
235 * parv[2] - tkline time (0 if perm)
236 * parv[3] - user
237 * parv[4] - host
238 * parv[5] - reason
239 */
240 static void
241 ms_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
242 {
243 int tkline_time = atoi(parv[2]);
244
245 /* 1.5-3 and earlier contains a bug that allows remote klines to be
246 * sent with an empty reason field. This is a protocol violation,
247 * but its not worth dropping the link over.. --anfl
248 */
249 if(parc < 6 || EmptyString(parv[5]))
250 return;
251
252 propagate_generic(source_p, "KLINE", parv[1], CAP_KLN,
253 "%d %s %s :%s", tkline_time, parv[3], parv[4], parv[5]);
254
255 if(!match(parv[1], me.name))
256 return;
257
258 if(!IsPerson(source_p))
259 return;
260
261 handle_remote_kline(source_p, tkline_time, parv[3], parv[4], parv[5]);
262 }
263
264 static void
265 me_kline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
266 {
267 /* <tkline_time> <user> <host> :<reason> */
268 if(!IsPerson(source_p))
269 return;
270
271 handle_remote_kline(source_p, atoi(parv[1]), parv[2], parv[3], parv[4]);
272 }
273
274 static void
275 handle_remote_kline(struct Client *source_p, int tkline_time,
276 const char *user, const char *host, const char *kreason)
277 {
278 char *reason = LOCAL_COPY(kreason);
279 struct ConfItem *aconf = NULL;
280 char *oper_reason;
281
282 if(!find_shared_conf(source_p->username, source_p->host,
283 source_p->servptr->name,
284 (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE))
285 return;
286
287 if(!valid_user_host(source_p, user, host))
288 return;
289
290 if(!valid_wild_card(user, host))
291 {
292 sendto_one_notice(source_p,
293 ":Please include at least %d non-wildcard "
294 "characters with the user@host",
295 ConfigFileEntry.min_nonwildcard);
296 return;
297 }
298
299 if(already_placed_kline(source_p, user, host, tkline_time))
300 return;
301
302 aconf = make_conf();
303
304 aconf->status = CONF_KILL;
305 aconf->created = rb_current_time();
306 aconf->user = rb_strdup(user);
307 aconf->host = rb_strdup(host);
308 aconf->info.oper = operhash_add(get_oper_name(source_p));
309
310 if(strlen(reason) > BANREASONLEN)
311 reason[BANREASONLEN] = '\0';
312
313 /* Look for an oper reason */
314 if((oper_reason = strchr(reason, '|')) != NULL)
315 {
316 *oper_reason = '\0';
317 oper_reason++;
318
319 if(!EmptyString(oper_reason))
320 aconf->spasswd = rb_strdup(oper_reason);
321 }
322 aconf->passwd = rb_strdup(reason);
323
324 if(tkline_time > 0)
325 apply_tkline(source_p, aconf, reason, oper_reason, tkline_time);
326 else
327 apply_kline(source_p, aconf, reason, oper_reason);
328
329 if(ConfigFileEntry.kline_delay)
330 {
331 if(kline_queued == 0)
332 {
333 rb_event_addonce("check_klines", check_klines_event, NULL,
334 ConfigFileEntry.kline_delay);
335 kline_queued = 1;
336 }
337 }
338 else
339 check_klines();
340 }
341
342 /* mo_unkline()
343 *
344 * parv[1] - kline to remove
345 * parv[2] - optional "ON"
346 * parv[3] - optional target server
347 */
348 static void
349 mo_unkline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
350 {
351 const char *user;
352 char *host;
353 char splat[] = "*";
354 char *h = LOCAL_COPY(parv[1]);
355 struct ConfItem *aconf;
356 int propagated = 1;
357
358 if(!IsOperUnkline(source_p))
359 {
360 sendto_one(source_p, form_str(ERR_NOPRIVS), me.name, source_p->name, "unkline");
361 return;
362 }
363
364 if((host = strchr(h, '@')) || *h == '*' || strchr(h, '.') || strchr(h, ':'))
365 {
366 /* Explicit user@host mask given */
367
368 if(host) /* Found user@host */
369 {
370 *host++ = '\0';
371
372 /* check for @host */
373 if(*h)
374 user = h;
375 else
376 user = splat;
377
378 /* check for user@ */
379 if(!*host)
380 host = splat;
381 }
382 else
383 {
384 user = splat; /* no @ found, assume its *@somehost */
385 host = h;
386 }
387 }
388 else
389 {
390 sendto_one_notice(source_p, ":Invalid parameters");
391 return;
392 }
393
394 /* possible remote kline.. */
395 if((parc > 3) && (irccmp(parv[2], "ON") == 0))
396 {
397 if(!IsOperRemoteBan(source_p))
398 {
399 sendto_one(source_p, form_str(ERR_NOPRIVS),
400 me.name, source_p->name, "remoteban");
401 return;
402 }
403
404 propagate_generic(source_p, "UNKLINE", parv[3], CAP_UNKLN, "%s %s", user, host);
405
406 if(match(parv[3], me.name) == 0)
407 return;
408
409 propagated = 0;
410 }
411
412 aconf = find_exact_conf_by_address(host, CONF_KILL, user);
413
414 /* No clustering for removing a propagated kline */
415 if(propagated && (aconf == NULL || !aconf->lifetime) &&
416 rb_dlink_list_length(&cluster_conf_list) > 0)
417 cluster_generic(source_p, "UNKLINE", SHARED_UNKLINE, CAP_UNKLN,
418 "%s %s", user, host);
419
420 if(aconf == NULL)
421 {
422 sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
423 return;
424 }
425
426 if(aconf->lifetime)
427 {
428 if(propagated)
429 remove_prop_kline(source_p, aconf);
430 else
431 sendto_one_notice(source_p, ":Cannot remove global K-Line %s@%s on specific servers", user, host);
432 return;
433 }
434
435 if(remove_temp_kline(source_p, aconf))
436 return;
437
438 remove_permkline_match(source_p, aconf);
439 }
440
441 /* ms_unkline()
442 *
443 * parv[1] - target server
444 * parv[2] - user to unkline
445 * parv[3] - host to unkline
446 */
447 static void
448 ms_unkline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
449 {
450 /* parv[0] parv[1] parv[2] parv[3]
451 * oper target server user host */
452 propagate_generic(source_p, "UNKLINE", parv[1], CAP_UNKLN, "%s %s", parv[2], parv[3]);
453
454 if(!match(parv[1], me.name))
455 return;
456
457 if(!IsPerson(source_p))
458 return;
459
460 handle_remote_unkline(source_p, parv[2], parv[3]);
461 }
462
463 static void
464 me_unkline(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
465 {
466 /* user host */
467 if(!IsPerson(source_p))
468 return;
469
470 handle_remote_unkline(source_p, parv[1], parv[2]);
471 }
472
473 static void
474 handle_remote_unkline(struct Client *source_p, const char *user, const char *host)
475 {
476 struct ConfItem *aconf;
477
478 if(!find_shared_conf(source_p->username, source_p->host,
479 source_p->servptr->name, SHARED_UNKLINE))
480 return;
481
482 aconf = find_exact_conf_by_address(host, CONF_KILL, user);
483 if(aconf == NULL)
484 {
485 sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
486 return;
487 }
488 if(aconf->lifetime)
489 {
490 sendto_one_notice(source_p, ":Cannot remove global K-Line %s@%s on specific servers", user, host);
491 return;
492 }
493
494 if(remove_temp_kline(source_p, aconf))
495 return;
496
497 remove_permkline_match(source_p, aconf);
498 }
499
500 /* apply_kline()
501 *
502 * inputs -
503 * output - NONE
504 * side effects - kline as given, is added to the hashtable
505 * and conf file
506 */
507 static void
508 apply_kline(struct Client *source_p, struct ConfItem *aconf,
509 const char *reason, const char *oper_reason)
510 {
511 add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf);
512 bandb_add(BANDB_KLINE, source_p, aconf->user, aconf->host,
513 reason, EmptyString(oper_reason) ? NULL : oper_reason, 0);
514
515 /* no oper reason.. */
516 if(EmptyString(oper_reason))
517 {
518 sendto_realops_snomask(SNO_GENERAL, L_ALL,
519 "%s added K-Line for [%s@%s] [%s]",
520 get_oper_name(source_p), aconf->user, aconf->host, reason);
521 ilog(L_KLINE, "K %s 0 %s %s %s",
522 get_oper_name(source_p), aconf->user, aconf->host, reason);
523 }
524 else
525 {
526 sendto_realops_snomask(SNO_GENERAL, L_ALL,
527 "%s added K-Line for [%s@%s] [%s|%s]",
528 get_oper_name(source_p), aconf->user, aconf->host,
529 reason, oper_reason);
530 ilog(L_KLINE, "K %s 0 %s %s %s|%s",
531 get_oper_name(source_p), aconf->user, aconf->host, reason, oper_reason);
532 }
533
534 sendto_one_notice(source_p, ":Added K-Line [%s@%s]",
535 aconf->user, aconf->host);
536 }
537
538 /* apply_tkline()
539 *
540 * inputs -
541 * output - NONE
542 * side effects - tkline as given is placed
543 */
544 static void
545 apply_tkline(struct Client *source_p, struct ConfItem *aconf,
546 const char *reason, const char *oper_reason, int tkline_time)
547 {
548 aconf->hold = rb_current_time() + tkline_time;
549 add_temp_kline(aconf);
550
551 /* no oper reason.. */
552 if(EmptyString(oper_reason))
553 {
554 sendto_realops_snomask(SNO_GENERAL, L_ALL,
555 "%s added temporary %d min. K-Line for [%s@%s] [%s]",
556 get_oper_name(source_p), tkline_time / 60,
557 aconf->user, aconf->host, reason);
558 ilog(L_KLINE, "K %s %d %s %s %s",
559 get_oper_name(source_p), tkline_time / 60, aconf->user, aconf->host, reason);
560 }
561 else
562 {
563 sendto_realops_snomask(SNO_GENERAL, L_ALL,
564 "%s added temporary %d min. K-Line for [%s@%s] [%s|%s]",
565 get_oper_name(source_p), tkline_time / 60,
566 aconf->user, aconf->host, reason, oper_reason);
567 ilog(L_KLINE, "K %s %d %s %s %s|%s",
568 get_oper_name(source_p), tkline_time / 60,
569 aconf->user, aconf->host, reason, oper_reason);
570 }
571
572 sendto_one_notice(source_p, ":Added temporary %d min. K-Line [%s@%s]",
573 tkline_time / 60, aconf->user, aconf->host);
574 }
575
576 static void
577 apply_prop_kline(struct Client *source_p, struct ConfItem *aconf,
578 const char *reason, const char *oper_reason, int tkline_time)
579 {
580 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
581 aconf->hold = rb_current_time() + tkline_time;
582 aconf->lifetime = aconf->hold;
583
584 replace_old_ban(aconf);
585
586 rb_dlinkAddAlloc(aconf, &prop_bans);
587 add_conf_by_address(aconf->host, CONF_KILL, aconf->user, NULL, aconf);
588
589 /* no oper reason.. */
590 if(EmptyString(oper_reason))
591 {
592 sendto_realops_snomask(SNO_GENERAL, L_ALL,
593 "%s added global %d min. K-Line for [%s@%s] [%s]",
594 get_oper_name(source_p), tkline_time / 60,
595 aconf->user, aconf->host, reason);
596 ilog(L_KLINE, "K %s %d %s %s %s",
597 get_oper_name(source_p), tkline_time / 60, aconf->user, aconf->host, reason);
598 }
599 else
600 {
601 sendto_realops_snomask(SNO_GENERAL, L_ALL,
602 "%s added global %d min. K-Line for [%s@%s] [%s|%s]",
603 get_oper_name(source_p), tkline_time / 60,
604 aconf->user, aconf->host, reason, oper_reason);
605 ilog(L_KLINE, "K %s %d %s %s %s|%s",
606 get_oper_name(source_p), tkline_time / 60,
607 aconf->user, aconf->host, reason, oper_reason);
608 }
609
610 sendto_one_notice(source_p, ":Added global %d min. K-Line [%s@%s]",
611 tkline_time / 60, aconf->user, aconf->host);
612
613 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
614 ":%s BAN K %s %s %lu %d %d * :%s%s%s",
615 source_p->id, aconf->user, aconf->host,
616 (unsigned long)aconf->created,
617 (int)(aconf->hold - aconf->created),
618 (int)(aconf->lifetime - aconf->created),
619 reason,
620 oper_reason ? "|" : "",
621 oper_reason ? oper_reason : "");
622 }
623
624 /* find_user_host()
625 *
626 * inputs - client placing kline, user@host, user buffer, host buffer
627 * output - false if not ok to kline, true to kline i.e. if valid user host
628 * side effects -
629 */
630 static bool
631 find_user_host(struct Client *source_p, const char *userhost, char *luser, char *lhost)
632 {
633 char *hostp;
634
635 hostp = strchr(userhost, '@');
636
637 if(hostp != NULL) /* I'm a little user@host */
638 {
639 *(hostp++) = '\0'; /* short and squat */
640 if(*userhost)
641 rb_strlcpy(luser, userhost, USERLEN + 1); /* here is my user */
642 else
643 strcpy(luser, "*");
644 if(*hostp)
645 rb_strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
646 else
647 strcpy(lhost, "*");
648 }
649 else
650 {
651 /* no '@', no '.', so its not a user@host or host, therefore
652 * its a nick, which support was removed for.
653 */
654 if(strchr(userhost, '.') == NULL && strchr(userhost, ':') == NULL)
655 {
656 sendto_one_notice(source_p, ":K-Line must be a user@host or host");
657 return false;
658 }
659
660 luser[0] = '*'; /* no @ found, assume its *@somehost */
661 luser[1] = '\0';
662 rb_strlcpy(lhost, userhost, HOSTLEN + 1);
663 }
664
665 /* would break the protocol */
666 if (*luser == ':' || *lhost == ':')
667 {
668 sendto_one_notice(source_p, ":Invalid K-Line");
669 return false;
670 }
671
672 return true;
673 }
674
675 /* valid_user_host()
676 *
677 * inputs - user buffer, host buffer
678 * output - false if invalid, true if valid
679 * side effects -
680 */
681 static bool
682 valid_user_host(struct Client *source_p, const char *luser, const char *lhost)
683 {
684 /* # is invalid, as are '!' (n!u@h kline) and '@' (u@@h kline) */
685 if(strchr(lhost, '#') || strchr(luser, '#') || strchr(luser, '!') || strchr(lhost, '@'))
686 {
687 sendto_one_notice(source_p, ":Invalid K-Line");
688 return false;
689 }
690
691 return true;
692 }
693
694 /* already_placed_kline()
695 *
696 * inputs - source to notify, user@host to check, tkline time
697 * outputs - true if a perm kline or a tkline when a tkline is being
698 * set exists, else false
699 * side effects - notifies source_p kline exists
700 */
701 /* Note: This currently works if the new K-line is a special case of an
702 * existing K-line, but not the other way round. To do that we would
703 * have to walk the hash and check every existing K-line. -A1kmm.
704 */
705 static bool
706 already_placed_kline(struct Client *source_p, const char *luser, const char *lhost, int tkline)
707 {
708 const char *reason, *p;
709 struct rb_sockaddr_storage iphost, *piphost;
710 struct ConfItem *aconf;
711 int t, bits;
712
713 aconf = find_exact_conf_by_address(lhost, CONF_KILL, luser);
714 if(aconf == NULL && ConfigFileEntry.non_redundant_klines)
715 {
716 bits = 0;
717 if((t = parse_netmask(lhost, &iphost, &bits)) != HM_HOST)
718 {
719 #ifdef RB_IPV6
720 if(t == HM_IPV6)
721 t = AF_INET6;
722 else
723 #endif
724 t = AF_INET;
725
726 piphost = &iphost;
727 }
728 else
729 piphost = NULL;
730
731 aconf = find_conf_by_address(lhost, NULL, NULL, (struct sockaddr *) piphost,
732 CONF_KILL, t, luser, NULL);
733 if(aconf != NULL)
734 {
735 /* The above was really a lookup of a single IP,
736 * so check if the new kline is wider than the
737 * existing one.
738 * -- jilles
739 */
740 p = strchr(aconf->host, '/');
741 if(bits > 0 && (p == NULL || bits < atoi(p + 1)))
742 aconf = NULL;
743 }
744 }
745 if(aconf != NULL)
746 {
747 /* setting a tkline, or existing one is perm */
748 if(tkline || ((aconf->flags & CONF_FLAGS_TEMPORARY) == 0))
749 {
750 reason = aconf->passwd ? aconf->passwd : "<No Reason>";
751
752 sendto_one_notice(source_p,
753 ":[%s@%s] already K-Lined by [%s@%s] - %s",
754 luser, lhost, aconf->user, aconf->host, reason);
755 return true;
756 }
757 }
758
759 return false;
760 }
761
762 /* remove_permkline_match()
763 *
764 * hunts for a permanent kline, and removes it.
765 */
766 static void
767 remove_permkline_match(struct Client *source_p, struct ConfItem *aconf)
768 {
769 sendto_one_notice(source_p, ":K-Line for [%s@%s] is removed", aconf->user, aconf->host);
770
771 sendto_realops_snomask(SNO_GENERAL, L_ALL,
772 "%s has removed the K-Line for: [%s@%s]",
773 get_oper_name(source_p), aconf->user, aconf->host);
774
775 ilog(L_KLINE, "UK %s %s %s", get_oper_name(source_p), aconf->user, aconf->host);
776
777 remove_reject_mask(aconf->user, aconf->host);
778 bandb_del(BANDB_KLINE, aconf->user, aconf->host);
779 delete_one_address_conf(aconf->host, aconf);
780 }
781
782 /* remove_temp_kline()
783 *
784 * inputs - username, hostname to unkline
785 * outputs -
786 * side effects - tries to unkline anything that matches
787 */
788 static bool
789 remove_temp_kline(struct Client *source_p, struct ConfItem *aconf)
790 {
791 rb_dlink_node *ptr;
792 int i;
793
794 for(i = 0; i < LAST_TEMP_TYPE; i++)
795 {
796 RB_DLINK_FOREACH(ptr, temp_klines[i].head)
797 {
798 if(aconf == ptr->data)
799 {
800 sendto_one_notice(source_p,
801 ":Un-klined [%s@%s] from temporary k-lines",
802 aconf->user, aconf->host);
803 sendto_realops_snomask(SNO_GENERAL, L_ALL,
804 "%s has removed the temporary K-Line for: [%s@%s]",
805 get_oper_name(source_p), aconf->user,
806 aconf->host);
807
808 ilog(L_KLINE, "UK %s %s %s",
809 get_oper_name(source_p), aconf->user, aconf->host);
810 rb_dlinkDestroy(ptr, &temp_klines[i]);
811 remove_reject_mask(aconf->user, aconf->host);
812 delete_one_address_conf(aconf->host, aconf);
813 return true;
814 }
815 }
816 }
817
818 return false;
819 }
820
821 static void
822 remove_prop_kline(struct Client *source_p, struct ConfItem *aconf)
823 {
824 rb_dlink_node *ptr;
825 time_t now;
826
827 ptr = rb_dlinkFind(aconf, &prop_bans);
828 if (!ptr)
829 return;
830 sendto_one_notice(source_p,
831 ":Un-klined [%s@%s] from global k-lines",
832 aconf->user, aconf->host);
833 sendto_realops_snomask(SNO_GENERAL, L_ALL,
834 "%s has removed the global K-Line for: [%s@%s]",
835 get_oper_name(source_p), aconf->user,
836 aconf->host);
837
838 ilog(L_KLINE, "UK %s %s %s",
839 get_oper_name(source_p), aconf->user, aconf->host);
840 now = rb_current_time();
841 if(aconf->created < now)
842 aconf->created = now;
843 else
844 aconf->created++;
845 aconf->hold = aconf->created;
846 operhash_delete(aconf->info.oper);
847 aconf->info.oper = operhash_add(get_oper_name(source_p));
848 aconf->flags |= CONF_FLAGS_MYOPER | CONF_FLAGS_TEMPORARY;
849 sendto_server(NULL, NULL, CAP_BAN|CAP_TS6, NOCAPS,
850 ":%s BAN K %s %s %lu %d %d * :*",
851 source_p->id, aconf->user, aconf->host,
852 (unsigned long)aconf->created,
853 0,
854 (int)(aconf->lifetime - aconf->created));
855 remove_reject_mask(aconf->user, aconf->host);
856 deactivate_conf(aconf, ptr, now);
857 }