]> jfr.im git - irc/rqf/shadowircd.git/blob - modules/m_kline.c
DubString -> rb_strdup
[irc/rqf/shadowircd.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 * $Id: m_kline.c 3466 2007-05-19 23:36:51Z jilles $
25 */
26
27 #include "stdinc.h"
28 #include "channel.h"
29 #include "class.h"
30 #include "client.h"
31 #include "common.h"
32 #include "irc_string.h"
33 #include "sprintf_irc.h"
34 #include "ircd.h"
35 #include "hostmask.h"
36 #include "numeric.h"
37 #include "s_conf.h"
38 #include "s_newconf.h"
39 #include "s_log.h"
40 #include "send.h"
41 #include "hash.h"
42 #include "s_serv.h"
43 #include "msg.h"
44 #include "parse.h"
45 #include "modules.h"
46 #include "reject.h"
47
48 static int mo_kline(struct Client *, struct Client *, int, const char **);
49 static int ms_kline(struct Client *, struct Client *, int, const char **);
50 static int me_kline(struct Client *, struct Client *, int, const char **);
51 static int mo_unkline(struct Client *, struct Client *, int, const char **);
52 static int ms_unkline(struct Client *, struct Client *, int, const char **);
53 static int me_unkline(struct Client *, struct Client *, int, const char **);
54
55 struct Message kline_msgtab = {
56 "KLINE", 0, 0, 0, MFLG_SLOW,
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, MFLG_SLOW,
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 DECLARE_MODULE_AV1(kline, NULL, NULL, kline_clist, NULL, NULL, "$Revision: 3466 $");
67
68 /* Local function prototypes */
69 static int find_user_host(struct Client *source_p, const char *userhost, char *user, char *host);
70 static int valid_comment(struct Client *source_p, char *comment);
71 static int valid_user_host(struct Client *source_p, const char *user, const char *host);
72 static int valid_wild_card(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, const char *current_date);
78 static void apply_tkline(struct Client *source_p, struct ConfItem *aconf,
79 const char *, const char *, const char *, int);
80 static int already_placed_kline(struct Client *, const char *, const char *, int);
81
82 static void handle_remote_unkline(struct Client *source_p,
83 const char *user, const char *host);
84 static void remove_permkline_match(struct Client *, struct ConfItem *);
85 static int flush_write(struct Client *, FILE *, const char *, const char *);
86 static int remove_temp_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 int
97 mo_kline(struct Client *client_p, struct Client *source_p,
98 int parc, const char **parv)
99 {
100 char def[] = "No Reason";
101 char user[USERLEN + 2];
102 char host[HOSTLEN + 2];
103 char buffer[IRCD_BUFSIZE];
104 char *reason = def;
105 char *oper_reason;
106 const char *current_date;
107 const char *target_server = NULL;
108 struct ConfItem *aconf;
109 int tkline_time = 0;
110 int loc = 1;
111
112 if(!IsOperK(source_p))
113 {
114 sendto_one(source_p, form_str(ERR_NOPRIVS),
115 me.name, source_p->name, "kline");
116 return 0;
117 }
118
119 if((tkline_time = valid_temp_time(parv[loc])) >= 0)
120 loc++;
121 /* we just set tkline_time to -1! */
122 else
123 tkline_time = 0;
124
125 if(find_user_host(source_p, parv[loc], user, host) == 0)
126 return 0;
127
128 loc++;
129
130 if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
131 {
132 if(!IsOperRemoteBan(source_p))
133 {
134 sendto_one(source_p, form_str(ERR_NOPRIVS),
135 me.name, source_p->name, "remoteban");
136 return 0;
137 }
138
139 target_server = parv[loc+1];
140 loc += 2;
141 }
142
143 if(parc <= loc || EmptyString(parv[loc]))
144 {
145 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
146 me.name, source_p->name, "KLINE");
147 return 0;
148 }
149
150 reason = LOCAL_COPY(parv[loc]);
151
152 if(target_server != NULL)
153 {
154 propagate_generic(source_p, "KLINE", target_server, CAP_KLN,
155 "%d %s %s :%s",
156 tkline_time, user, host, reason);
157
158 /* If we are sending it somewhere that doesnt include us, stop */
159 if(!match(target_server, me.name))
160 return 0;
161 }
162 /* if we have cluster servers, send it to them.. */
163 else if(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",
167 tkline_time, user, host, reason);
168
169 if(!valid_user_host(source_p, user, host) ||
170 !valid_wild_card(source_p, user, host) ||
171 !valid_comment(source_p, reason))
172 return 0;
173
174 if(already_placed_kline(source_p, user, host, tkline_time))
175 return 0;
176
177 set_time();
178 current_date = smalldate();
179 aconf = make_conf();
180 aconf->status = CONF_KILL;
181 aconf->host = rb_strdup(host);
182 aconf->user = rb_strdup(user);
183 aconf->port = 0;
184
185 /* Look for an oper reason */
186 if((oper_reason = strchr(reason, '|')) != NULL)
187 {
188 *oper_reason = '\0';
189 oper_reason++;
190
191 if(!EmptyString(oper_reason))
192 aconf->spasswd = rb_strdup(oper_reason);
193 }
194
195 if(tkline_time > 0)
196 {
197 rb_snprintf(buffer, sizeof(buffer),
198 "Temporary K-line %d min. - %s (%s)",
199 (int) (tkline_time / 60), reason, current_date);
200 aconf->passwd = rb_strdup(buffer);
201 apply_tkline(source_p, aconf, reason, oper_reason, current_date, tkline_time);
202 }
203 else
204 {
205 rb_snprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
206 aconf->passwd = rb_strdup(buffer);
207 apply_kline(source_p, aconf, reason, oper_reason, current_date);
208 }
209
210 if(ConfigFileEntry.kline_delay)
211 {
212 if(kline_queued == 0)
213 {
214 rb_event_addonce("check_klines", check_klines_event, NULL,
215 ConfigFileEntry.kline_delay);
216 kline_queued = 1;
217 }
218 }
219 else
220 check_klines();
221
222 return 0;
223 }
224
225 /* ms_kline()
226 *
227 * parv[1] - server targeted at
228 * parv[2] - tkline time (0 if perm)
229 * parv[3] - user
230 * parv[4] - host
231 * parv[5] - reason
232 */
233 static int
234 ms_kline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
235 {
236 int tkline_time = atoi(parv[2]);
237
238 /* 1.5-3 and earlier contains a bug that allows remote klines to be
239 * sent with an empty reason field. This is a protocol violation,
240 * but its not worth dropping the link over.. --anfl
241 */
242 if(parc < 6 || EmptyString(parv[5]))
243 return 0;
244
245 propagate_generic(source_p, "KLINE", parv[1], CAP_KLN,
246 "%d %s %s :%s",
247 tkline_time, parv[3], parv[4], parv[5]);
248
249 if(!match(parv[1], me.name))
250 return 0;
251
252 if(!IsPerson(source_p))
253 return 0;
254
255 handle_remote_kline(source_p, tkline_time, parv[3], parv[4], parv[5]);
256 return 0;
257 }
258
259 static int
260 me_kline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
261 {
262 /* <tkline_time> <user> <host> :<reason> */
263 if(!IsPerson(source_p))
264 return 0;
265
266 handle_remote_kline(source_p, atoi(parv[1]), parv[2], parv[3], parv[4]);
267 return 0;
268 }
269
270 static void
271 handle_remote_kline(struct Client *source_p, int tkline_time,
272 const char *user, const char *host, const char *kreason)
273 {
274 char buffer[BUFSIZE];
275 const char *current_date;
276 char *reason = LOCAL_COPY(kreason);
277 struct ConfItem *aconf = NULL;
278 char *oper_reason;
279
280 if(!find_shared_conf(source_p->username, source_p->host,
281 source_p->servptr->name,
282 (tkline_time > 0) ? SHARED_TKLINE : SHARED_PKLINE))
283 return;
284
285 if(!valid_user_host(source_p, user, host) ||
286 !valid_wild_card(source_p, user, host) ||
287 !valid_comment(source_p, reason))
288 return;
289
290 if(already_placed_kline(source_p, user, host, tkline_time))
291 return;
292
293 aconf = make_conf();
294
295 aconf->status = CONF_KILL;
296 aconf->user = rb_strdup(user);
297 aconf->host = rb_strdup(host);
298
299 /* Look for an oper reason */
300 if((oper_reason = strchr(reason, '|')) != NULL)
301 {
302 *oper_reason = '\0';
303 oper_reason++;
304
305 if(!EmptyString(oper_reason))
306 aconf->spasswd = rb_strdup(oper_reason);
307 }
308
309 current_date = smalldate();
310
311 if(tkline_time > 0)
312 {
313 rb_snprintf(buffer, sizeof(buffer),
314 "Temporary K-line %d min. - %s (%s)",
315 (int) (tkline_time / 60), reason, current_date);
316 aconf->passwd = rb_strdup(buffer);
317 apply_tkline(source_p, aconf, reason, oper_reason, current_date, tkline_time);
318 }
319 else
320 {
321 rb_snprintf(buffer, sizeof(buffer), "%s (%s)", reason, current_date);
322 aconf->passwd = rb_strdup(buffer);
323 apply_kline(source_p, aconf, reason, oper_reason, current_date);
324 }
325
326 if(ConfigFileEntry.kline_delay)
327 {
328 if(kline_queued == 0)
329 {
330 rb_event_addonce("check_klines", check_klines_event, NULL,
331 ConfigFileEntry.kline_delay);
332 kline_queued = 1;
333 }
334 }
335 else
336 check_klines();
337
338 return;
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 int
348 mo_unkline(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
356 if(!IsOperUnkline(source_p))
357 {
358 sendto_one(source_p, form_str(ERR_NOPRIVS),
359 me.name, source_p->name, "unkline");
360 return 0;
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 0;
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 0;
401 }
402
403 propagate_generic(source_p, "UNKLINE", parv[3], CAP_UNKLN,
404 "%s %s", user, host);
405
406 if(match(parv[3], me.name) == 0)
407 return 0;
408 }
409 else if(rb_dlink_list_length(&cluster_conf_list) > 0)
410 cluster_generic(source_p, "UNKLINE", SHARED_UNKLINE, CAP_UNKLN,
411 "%s %s", user, host);
412
413 aconf = find_exact_conf_by_address(host, CONF_KILL, user);
414 if(aconf == NULL)
415 {
416 sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
417 return 0;
418 }
419
420 if(remove_temp_kline(source_p, aconf))
421 return 0;
422
423 remove_permkline_match(source_p, aconf);
424
425 return 0;
426 }
427
428 /* ms_unkline()
429 *
430 * parv[1] - target server
431 * parv[2] - user to unkline
432 * parv[3] - host to unkline
433 */
434 static int
435 ms_unkline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
436 {
437 /* parv[0] parv[1] parv[2] parv[3]
438 * oper target server user host */
439 propagate_generic(source_p, "UNKLINE", parv[1], CAP_UNKLN,
440 "%s %s", parv[2], parv[3]);
441
442 if(!match(parv[1], me.name))
443 return 0;
444
445 if(!IsPerson(source_p))
446 return 0;
447
448 handle_remote_unkline(source_p, parv[2], parv[3]);
449 return 0;
450 }
451
452 static int
453 me_unkline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
454 {
455 /* user host */
456 if(!IsPerson(source_p))
457 return 0;
458
459 handle_remote_unkline(source_p, parv[1], parv[2]);
460 return 0;
461 }
462
463 static void
464 handle_remote_unkline(struct Client *source_p, const char *user, const char *host)
465 {
466 struct ConfItem *aconf;
467
468 if(!find_shared_conf(source_p->username, source_p->host,
469 source_p->servptr->name, SHARED_UNKLINE))
470 return;
471
472 aconf = find_exact_conf_by_address(host, CONF_KILL, user);
473 if(aconf == NULL)
474 {
475 sendto_one_notice(source_p, ":No K-Line for %s@%s", user, host);
476 return;
477 }
478
479 if(remove_temp_kline(source_p, aconf))
480 return;
481
482 remove_permkline_match(source_p, aconf);
483 }
484
485 /* apply_kline()
486 *
487 * inputs -
488 * output - NONE
489 * side effects - kline as given, is added to the hashtable
490 * and conf file
491 */
492 static void
493 apply_kline(struct Client *source_p, struct ConfItem *aconf,
494 const char *reason, const char *oper_reason, const char *current_date)
495 {
496 add_conf_by_address(aconf->host, CONF_KILL, aconf->user, aconf);
497 write_confitem(KLINE_TYPE, source_p, aconf->user, aconf->host,
498 reason, oper_reason, current_date, 0);
499 }
500
501 /* apply_tkline()
502 *
503 * inputs -
504 * output - NONE
505 * side effects - tkline as given is placed
506 */
507 static void
508 apply_tkline(struct Client *source_p, struct ConfItem *aconf,
509 const char *reason, const char *oper_reason, const char *current_date, int tkline_time)
510 {
511 aconf->hold = CurrentTime + tkline_time;
512 add_temp_kline(aconf);
513
514 /* no oper reason.. */
515 if(EmptyString(oper_reason))
516 {
517 sendto_realops_snomask(SNO_GENERAL, L_ALL,
518 "%s added temporary %d min. K-Line for [%s@%s] [%s]",
519 get_oper_name(source_p), tkline_time / 60,
520 aconf->user, aconf->host, reason);
521 ilog(L_KLINE, "K %s %d %s %s %s",
522 get_oper_name(source_p), tkline_time / 60,
523 aconf->user, aconf->host, reason);
524 }
525 else
526 {
527 sendto_realops_snomask(SNO_GENERAL, L_ALL,
528 "%s added temporary %d min. K-Line for [%s@%s] [%s|%s]",
529 get_oper_name(source_p), tkline_time / 60,
530 aconf->user, aconf->host, reason, oper_reason);
531 ilog(L_KLINE, "K %s %d %s %s %s|%s",
532 get_oper_name(source_p), tkline_time / 60,
533 aconf->user, aconf->host, reason, oper_reason);
534 }
535
536 sendto_one_notice(source_p, ":Added temporary %d min. K-Line [%s@%s]",
537 tkline_time / 60, aconf->user, aconf->host);
538 }
539
540 /* find_user_host()
541 *
542 * inputs - client placing kline, user@host, user buffer, host buffer
543 * output - 0 if not ok to kline, 1 to kline i.e. if valid user host
544 * side effects -
545 */
546 static int
547 find_user_host(struct Client *source_p, const char *userhost, char *luser, char *lhost)
548 {
549 char *hostp;
550
551 hostp = strchr(userhost, '@');
552
553 if(hostp != NULL) /* I'm a little user@host */
554 {
555 *(hostp++) = '\0'; /* short and squat */
556 if(*userhost)
557 strlcpy(luser, userhost, USERLEN + 1); /* here is my user */
558 else
559 strcpy(luser, "*");
560 if(*hostp)
561 strlcpy(lhost, hostp, HOSTLEN + 1); /* here is my host */
562 else
563 strcpy(lhost, "*");
564 }
565 else
566 {
567 /* no '@', no '.', so its not a user@host or host, therefore
568 * its a nick, which support was removed for.
569 */
570 if(strchr(userhost, '.') == NULL && strchr(userhost, ':') == NULL)
571 return 0;
572
573 luser[0] = '*'; /* no @ found, assume its *@somehost */
574 luser[1] = '\0';
575 strlcpy(lhost, userhost, HOSTLEN + 1);
576 }
577
578 return 1;
579 }
580
581 /* valid_user_host()
582 *
583 * inputs - user buffer, host buffer
584 * output - 0 if invalid, 1 if valid
585 * side effects -
586 */
587 static int
588 valid_user_host(struct Client *source_p, const char *luser, const char *lhost)
589 {
590 /* # is invalid, as is '!' (n!u@h kline) */
591 if(strchr(lhost, '#') || strchr(luser, '#') || strchr(luser, '!'))
592 {
593 sendto_one_notice(source_p, ":Invalid K-Line");
594 return 0;
595 }
596
597 return 1;
598 }
599
600 /* valid_wild_card()
601 *
602 * input - user buffer, host buffer
603 * output - 0 if invalid, 1 if valid
604 * side effects -
605 */
606 static int
607 valid_wild_card(struct Client *source_p, const char *luser, const char *lhost)
608 {
609 const char *p;
610 char tmpch;
611 int nonwild = 0;
612 int bitlen;
613
614 /* user has no wildcards, always accept -- jilles */
615 if (!strchr(luser, '?') && !strchr(luser, '*'))
616 return 1;
617
618 /* check there are enough non wildcard chars */
619 p = luser;
620 while ((tmpch = *p++))
621 {
622 if(!IsKWildChar(tmpch))
623 {
624 /* found enough chars, return */
625 if(++nonwild >= ConfigFileEntry.min_nonwildcard)
626 return 1;
627 }
628 }
629
630 /* try host, as user didnt contain enough */
631 /* special case for cidr masks -- jilles */
632 if ((p = strrchr(lhost, '/')) != NULL && IsDigit(p[1]))
633 {
634 bitlen = atoi(p + 1);
635 /* much like non-cidr for ipv6, rather arbitrary for ipv4 */
636 if (bitlen > 0 && bitlen >= (strchr(lhost, ':') ? 4 * (ConfigFileEntry.min_nonwildcard - nonwild) : 6 - 2 * nonwild))
637 return 1;
638 }
639 else
640 {
641 p = lhost;
642 while ((tmpch = *p++))
643 {
644 if(!IsKWildChar(tmpch))
645 if(++nonwild >= ConfigFileEntry.min_nonwildcard)
646 return 1;
647 }
648 }
649
650 sendto_one_notice(source_p,
651 ":Please include at least %d non-wildcard "
652 "characters with the user@host",
653 ConfigFileEntry.min_nonwildcard);
654 return 0;
655 }
656
657 /*
658 * valid_comment
659 * inputs - pointer to client
660 * - pointer to comment
661 * output - 0 if no valid comment, 1 if valid
662 * side effects - NONE
663 */
664 static int
665 valid_comment(struct Client *source_p, char *comment)
666 {
667 if(strchr(comment, '"'))
668 {
669 sendto_one_notice(source_p, ":Invalid character '\"' in comment");
670 return 0;
671 }
672
673 if(strlen(comment) > BANREASONLEN)
674 comment[BANREASONLEN] = '\0';
675
676 return 1;
677 }
678
679 /* already_placed_kline()
680 *
681 * inputs - source to notify, user@host to check, tkline time
682 * outputs - 1 if a perm kline or a tkline when a tkline is being
683 * set exists, else 0
684 * side effects - notifies source_p kline exists
685 */
686 /* Note: This currently works if the new K-line is a special case of an
687 * existing K-line, but not the other way round. To do that we would
688 * have to walk the hash and check every existing K-line. -A1kmm.
689 */
690 static int
691 already_placed_kline(struct Client *source_p, const char *luser, const char *lhost, int tkline)
692 {
693 const char *reason, *p;
694 struct irc_sockaddr_storage iphost, *piphost;
695 struct ConfItem *aconf;
696 int t, bits;
697
698 aconf = find_exact_conf_by_address(lhost, CONF_KILL, luser);
699 if (aconf == NULL && ConfigFileEntry.non_redundant_klines)
700 {
701 bits = 0;
702 if((t = parse_netmask(lhost, (struct sockaddr *)&iphost, &bits)) != HM_HOST)
703 {
704 #ifdef IPV6
705 if(t == HM_IPV6)
706 t = AF_INET6;
707 else
708 #endif
709 t = AF_INET;
710
711 piphost = &iphost;
712 }
713 else
714 piphost = NULL;
715
716 aconf = find_conf_by_address(lhost, NULL, NULL, (struct sockaddr *)piphost, CONF_KILL, t, luser);
717 if (aconf != NULL)
718 {
719 /* The above was really a lookup of a single IP,
720 * so check if the new kline is wider than the
721 * existing one.
722 * -- jilles
723 */
724 p = strchr(aconf->host, '/');
725 if (bits > 0 && (p == NULL || bits < atoi(p + 1)))
726 aconf = NULL;
727 }
728 }
729 if (aconf != NULL)
730 {
731 /* setting a tkline, or existing one is perm */
732 if(tkline || ((aconf->flags & CONF_FLAGS_TEMPORARY) == 0))
733 {
734 reason = aconf->passwd ? aconf->passwd : "<No Reason>";
735
736 sendto_one_notice(source_p,
737 ":[%s@%s] already K-Lined by [%s@%s] - %s",
738 luser, lhost, aconf->user,
739 aconf->host, reason);
740 return 1;
741 }
742 }
743
744 return 0;
745 }
746
747 /* remove_permkline_match()
748 *
749 * hunts for a permanent kline, and removes it.
750 */
751 static void
752 remove_permkline_match(struct Client *source_p, struct ConfItem *aconf)
753 {
754 FILE *in, *out;
755 int pairme = 0;
756 int error_on_write = NO;
757 char buf[BUFSIZE];
758 char matchbuf[BUFSIZE];
759 char temppath[BUFSIZE];
760 const char *filename;
761 const char *host, *user;
762 mode_t oldumask;
763 int matchlen;
764
765 host = aconf->host;
766 user = aconf->user;
767
768 rb_snprintf(temppath, sizeof(temppath),
769 "%s.tmp", ConfigFileEntry.klinefile);
770
771 filename = get_conf_name(KLINE_TYPE);
772
773 if((in = fopen(filename, "r")) == 0)
774 {
775 sendto_one_notice(source_p, ":Cannot open %s", filename);
776 return;
777 }
778
779 oldumask = umask(0);
780 if((out = fopen(temppath, "w")) == 0)
781 {
782 sendto_one_notice(source_p, ":Cannot open %s", temppath);
783 fclose(in);
784 umask(oldumask);
785 return;
786 }
787
788 umask(oldumask);
789
790 snprintf(matchbuf, sizeof(matchbuf), "\"%s\",\"%s\"", user, host);
791 matchlen = strlen(matchbuf);
792
793 while (fgets(buf, sizeof(buf), in))
794 {
795 if(error_on_write)
796 break;
797
798 if(!strncasecmp(buf, matchbuf, matchlen))
799 {
800 pairme++;
801 break;
802 }
803 else
804 error_on_write = flush_write(source_p, out, buf, temppath);
805 }
806
807 /* we dropped out of the loop early because we found a match,
808 * to drop into this somewhat faster loop as we presume we'll never
809 * have two matching klines --anfl
810 */
811 if(pairme && !error_on_write)
812 {
813 while(fgets(buf, sizeof(buf), in))
814 {
815 if(error_on_write)
816 break;
817
818 error_on_write = flush_write(source_p, out, buf, temppath);
819 }
820 }
821
822 fclose(in);
823 if (fclose(out))
824 error_on_write = YES;
825
826 /* The result of the rename should be checked too... oh well */
827 /* If there was an error on a write above, then its been reported
828 * and I am not going to trash the original kline /conf file
829 */
830 if(error_on_write)
831 {
832 sendto_one_notice(source_p, ":Couldn't write temp kline file, aborted");
833 return;
834 }
835 else if(!pairme)
836 {
837 sendto_one_notice(source_p, ":Cannot find K-Line for %s@%s in file",
838 user, host);
839
840 if(temppath != NULL)
841 (void) unlink(temppath);
842
843 return;
844 }
845
846 if (rename(temppath, filename))
847 {
848 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
849 return;
850 }
851
852 sendto_one_notice(source_p, ":K-Line for [%s@%s] is removed",
853 user, host);
854
855 sendto_realops_snomask(SNO_GENERAL, L_ALL,
856 "%s has removed the K-Line for: [%s@%s]",
857 get_oper_name(source_p), user, host);
858
859 ilog(L_KLINE, "UK %s %s %s",
860 get_oper_name(source_p), user, host);
861
862 remove_reject_mask(aconf->user, aconf->host);
863 delete_one_address_conf(aconf->host, aconf);
864
865 return;
866 }
867
868 /*
869 * flush_write()
870 *
871 * inputs - pointer to client structure of oper requesting unkline
872 * - out is the file descriptor
873 * - buf is the buffer to write
874 * - ntowrite is the expected number of character to be written
875 * - temppath is the temporary file name to be written
876 * output - YES for error on write
877 * - NO for success
878 * side effects - if successful, the buf is written to output file
879 * if a write failure happesn, and the file pointed to
880 * by temppath, if its non NULL, is removed.
881 *
882 * The idea here is, to be as robust as possible when writing to the
883 * kline file.
884 *
885 * -Dianora
886 */
887
888 static int
889 flush_write(struct Client *source_p, FILE * out, const char *buf, const char *temppath)
890 {
891 int error_on_write = (fputs(buf, out) < 0) ? YES : NO;
892
893 if(error_on_write)
894 {
895 sendto_one_notice(source_p, ":Unable to write to %s",
896 temppath);
897 if(temppath != NULL)
898 (void) unlink(temppath);
899 }
900 return (error_on_write);
901 }
902
903 /* remove_temp_kline()
904 *
905 * inputs - username, hostname to unkline
906 * outputs -
907 * side effects - tries to unkline anything that matches
908 */
909 static int
910 remove_temp_kline(struct Client *source_p, struct ConfItem *aconf)
911 {
912 rb_dlink_node *ptr;
913 int i;
914
915 for (i = 0; i < LAST_TEMP_TYPE; i++)
916 {
917 RB_DLINK_FOREACH(ptr, temp_klines[i].head)
918 {
919 if (aconf == ptr->data)
920 {
921 sendto_one_notice(source_p,
922 ":Un-klined [%s@%s] from temporary k-lines",
923 aconf->user, aconf->host);
924 sendto_realops_snomask(SNO_GENERAL, L_ALL,
925 "%s has removed the temporary K-Line for: [%s@%s]",
926 get_oper_name(source_p), aconf->user, aconf->host);
927
928 ilog(L_KLINE, "UK %s %s %s",
929 get_oper_name(source_p),
930 aconf->user, aconf->host);
931 rb_dlinkDestroy(ptr, &temp_klines[i]);
932 remove_reject_mask(aconf->user, aconf->host);
933 delete_one_address_conf(aconf->host, aconf);
934 return YES;
935 }
936 }
937 }
938
939 return NO;
940 }