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