]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_dline.c
Remove windows newlines (^M).
[irc/rqf/shadowircd.git] / modules / m_dline.c
CommitLineData
212380e3 1/*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_dline.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 *
61569b65 24 * $Id: m_dline.c 3225 2007-03-04 23:42:55Z jilles $
212380e3 25 */
26
27#include "stdinc.h"
212380e3 28#include "channel.h"
29#include "class.h"
30#include "client.h"
31#include "common.h"
13ae2f4b 32#include "match.h"
212380e3 33#include "ircd.h"
34#include "hostmask.h"
35#include "numeric.h"
212380e3 36#include "s_conf.h"
37#include "s_newconf.h"
d3455e2c 38#include "logger.h"
212380e3 39#include "send.h"
40#include "hash.h"
41#include "s_serv.h"
42#include "msg.h"
43#include "parse.h"
44#include "modules.h"
45
46static int mo_dline(struct Client *, struct Client *, int, const char **);
45be325c 47static int me_dline(struct Client *, struct Client *, int, const char **);
212380e3 48static int mo_undline(struct Client *, struct Client *, int, const char **);
45be325c 49static int me_undline(struct Client *, struct Client *, int, const char **);
212380e3 50
51struct Message dline_msgtab = {
52 "DLINE", 0, 0, 0, MFLG_SLOW,
45be325c 53 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_dline, 3}, {mo_dline, 2}}
212380e3 54};
55struct Message undline_msgtab = {
56 "UNDLINE", 0, 0, 0, MFLG_SLOW,
45be325c 57 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, {me_undline, 1}, {mo_undline, 2}}
212380e3 58};
59
60mapi_clist_av1 dline_clist[] = { &dline_msgtab, &undline_msgtab, NULL };
61569b65 61DECLARE_MODULE_AV1(dline, NULL, NULL, dline_clist, NULL, NULL, "$Revision: 3225 $");
212380e3 62
63static int valid_comment(char *comment);
64static int flush_write(struct Client *, FILE *, char *, char *);
6f3a09ff 65static int remove_temp_dline(struct ConfItem *);
e26306d3 66static int apply_dline(struct Client *, const char *, int, char *);
45be325c 67static int apply_undline(struct Client *, const char *);
212380e3 68
69/* mo_dline()
70 *
71 * parv[1] - dline to add
72 * parv[2] - reason
73 */
74static int
75mo_dline(struct Client *client_p, struct Client *source_p,
76 int parc, const char *parv[])
77{
78 char def[] = "No Reason";
79 const char *dlhost;
212380e3 80 char *reason = def;
212380e3 81 char cidr_form_host[HOSTLEN + 1];
212380e3 82 int tdline_time = 0;
45be325c 83 const char *target_server = NULL;
212380e3 84 int loc = 1;
85
86 if(!IsOperK(source_p))
87 {
88 sendto_one(source_p, form_str(ERR_NOPRIVS),
89 me.name, source_p->name, "kline");
90 return 0;
91 }
92
93 if((tdline_time = valid_temp_time(parv[loc])) >= 0)
94 loc++;
95
212380e3 96 dlhost = parv[loc];
907468c4 97 rb_strlcpy(cidr_form_host, dlhost, sizeof(cidr_form_host));
212380e3 98
45be325c
VY
99 loc++;
100
101 if(parc >= loc+2 && !irccmp(parv[loc], "ON"))
102 {
103 target_server = parv[loc+1];
104 loc += 2;
105 }
106
107 if(parc >= loc + 1 && !EmptyString(parv[loc]))
108 reason = LOCAL_COPY(parv[loc]);
109
110 if(target_server != NULL)
212380e3 111 {
45be325c
VY
112 sendto_match_servs(source_p, target_server,
113 CAP_ENCAP, NOCAPS,
114 "ENCAP %s DLINE %d %s :%s",
115 target_server, tdline_time, dlhost, reason);
116
117 if(!match(target_server, me.name))
118 return 0;
212380e3 119 }
120
45be325c
VY
121 apply_dline(source_p, dlhost, tdline_time, reason);
122
123 check_dlines();
124 return 0;
125}
212380e3 126
45be325c
VY
127/* mo_undline()
128 *
129 * parv[1] = dline to remove
130 */
131static int
132mo_undline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
133{
134 const char *cidr;
135 const char *target_server = NULL;
136
137 if(!IsOperK(source_p))
138 {
139 sendto_one(source_p, form_str(ERR_NOPRIVS),
140 me.name, source_p->name, "unkline");
141 return 0;
142 }
143
144 cidr = parv[1];
145
146 if(parc >= 4 && !irccmp(parv[2], "ON"))
212380e3 147 {
45be325c
VY
148 target_server = parv[3];
149 sendto_match_servs(source_p, target_server,
150 CAP_ENCAP, NOCAPS,
151 "ENCAP %s UNDLINE %s",
152 target_server, cidr);
212380e3 153
45be325c 154 if(!match(target_server, me.name))
212380e3 155 return 0;
212380e3 156 }
157
45be325c
VY
158 apply_undline(source_p, cidr);
159
160 return 0;
161}
162
e26306d3
JT
163static int
164me_dline(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
165{
166 int tdline_time = atoi(parv[1]);
167 /* Since this is coming over a server link, assume that the originating
168 * server did the relevant permission/sanity checks...
169 */
170
171 if(!IsPerson(source_p))
172 return 0;
173
174 if(!find_shared_conf(source_p->username, source_p->host,
175 source_p->servptr->name, tdline_time > 0 ? SHARED_TDLINE : SHARED_PDLINE))
176 {
177 sendto_realops_snomask(SNO_DEBUG, L_NETWIDE, "undline failed %s %s %s",
178 source_p->name, parv[1], parv[2]);
179 return 0;
180 }
181
182 apply_dline(source_p, parv[2], tdline_time, LOCAL_COPY(parv[3]));
183
184 check_dlines();
185 return 0;
186}
187
188static int
189me_undline(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
190{
191 if(!IsPerson(source_p))
192 return 0;
193
194 if(!find_shared_conf(source_p->username, source_p->host,
195 source_p->servptr->name, SHARED_UNDLINE))
196 return 0;
197
198 apply_undline(source_p, parv[1]);
199
200 return 0;
45be325c
VY
201}
202
203static int
204apply_dline(struct Client *source_p, const char *dlhost, int tdline_time, char *reason)
205{
206 struct ConfItem *aconf;
207 char *oper_reason;
208 char dlbuffer[IRCD_BUFSIZE];
209 const char *current_date;
210 struct rb_sockaddr_storage daddr;
211 int t = AF_INET, ty, b;
212 const char *creason;
213
214 ty = parse_netmask(dlhost, (struct sockaddr *)&daddr, &b);
215 if(ty == HM_HOST)
216 {
217 sendto_one(source_p, ":%s NOTICE %s :Invalid D-Line",
218 me.name, source_p->name);
219 return 0;
220 }
221#ifdef RB_IPV6
222 if(ty == HM_IPV6)
223 t = AF_INET6;
224 else
225#endif
226 t = AF_INET;
227
228 /* This means dlines wider than /16 cannot be set remotely */
212380e3 229 if(IsOperAdmin(source_p))
230 {
45be325c 231 if(b < 8)
212380e3 232 {
45be325c
VY
233 sendto_one_notice(source_p,
234 ":For safety, bitmasks less than 8 require conf access.");
212380e3 235 return 0;
236 }
237 }
238 else
239 {
45be325c 240 if(b < 16)
212380e3 241 {
45be325c
VY
242 sendto_one_notice(source_p,
243 ":Dline bitmasks less than 16 are for admins only.");
212380e3 244 return 0;
245 }
246 }
247
45be325c
VY
248 if(!valid_comment(reason))
249 {
250 sendto_one(source_p,
251 ":%s NOTICE %s :Invalid character '\"' in comment",
252 me.name, source_p->name);
253 return 0;
254 }
255
256 /* Look for an oper reason */
257 if((oper_reason = strchr(reason, '|')) != NULL)
258 {
259 *oper_reason = '\0';
260 oper_reason++;
261
262 if(!EmptyString(oper_reason))
263 aconf->spasswd = rb_strdup(oper_reason);
264 }
265
21c9d815
VY
266 if(ConfigFileEntry.non_redundant_klines)
267 {
21c9d815
VY
268 if((aconf = find_dline((struct sockaddr *)&daddr, t)) != NULL)
269 {
270 int bx;
271 parse_netmask(aconf->host, NULL, &bx);
272 if(b >= bx)
273 {
274 creason = aconf->passwd ? aconf->passwd : "<No Reason>";
275 if(IsConfExemptKline(aconf))
276 sendto_one(source_p,
277 ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
45be325c 278 me.name, source_p->name, dlhost, aconf->host, creason);
21c9d815
VY
279 else
280 sendto_one(source_p,
281 ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
45be325c 282 me.name, source_p->name, dlhost, aconf->host, creason);
21c9d815
VY
283 return 0;
284 }
285 }
212380e3 286 }
287
4362b282 288 rb_set_time();
212380e3 289 current_date = smalldate();
290
291 aconf = make_conf();
292 aconf->status = CONF_DLINE;
62d28946 293 aconf->host = rb_strdup(dlhost);
212380e3 294
212380e3 295 if(tdline_time > 0)
296 {
581fa5c4 297 rb_snprintf(dlbuffer, sizeof(dlbuffer),
212380e3 298 "Temporary D-line %d min. - %s (%s)",
299 (int) (tdline_time / 60), reason, current_date);
62d28946 300 aconf->passwd = rb_strdup(dlbuffer);
9f6bbe3c 301 aconf->hold = rb_current_time() + tdline_time;
212380e3 302 add_temp_dline(aconf);
303
304 if(EmptyString(oper_reason))
305 {
45be325c 306 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
212380e3 307 "%s added temporary %d min. D-Line for [%s] [%s]",
308 get_oper_name(source_p), tdline_time / 60,
309 aconf->host, reason);
310 ilog(L_KLINE, "D %s %d %s %s",
311 get_oper_name(source_p), tdline_time / 60,
312 aconf->host, reason);
313 }
314 else
315 {
45be325c 316 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
212380e3 317 "%s added temporary %d min. D-Line for [%s] [%s|%s]",
318 get_oper_name(source_p), tdline_time / 60,
319 aconf->host, reason, oper_reason);
320 ilog(L_KLINE, "D %s %d %s %s|%s",
321 get_oper_name(source_p), tdline_time / 60,
322 aconf->host, reason, oper_reason);
323 }
324
325 sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. D-Line for [%s]",
326 me.name, source_p->name, tdline_time / 60, aconf->host);
327 }
328 else
329 {
581fa5c4 330 rb_snprintf(dlbuffer, sizeof(dlbuffer), "%s (%s)", reason, current_date);
62d28946 331 aconf->passwd = rb_strdup(dlbuffer);
212380e3 332 add_conf_by_address(aconf->host, CONF_DLINE, NULL, aconf);
333 write_confitem(DLINE_TYPE, source_p, NULL, aconf->host, reason,
334 oper_reason, current_date, 0);
335 }
336
212380e3 337 return 0;
338}
339
212380e3 340static int
45be325c 341apply_undline(struct Client *source_p, const char *cidr)
212380e3 342{
343 FILE *in;
344 FILE *out;
345 char buf[BUFSIZE], buff[BUFSIZE], temppath[BUFSIZE], *p;
346 const char *filename, *found_cidr;
212380e3 347 int pairme = NO, error_on_write = NO;
348 mode_t oldumask;
45be325c 349 struct ConfItem *aconf;
212380e3 350
351 if(parse_netmask(cidr, NULL, NULL) == HM_HOST)
352 {
5366977b 353 sendto_one_notice(source_p, ":Invalid D-Line");
212380e3 354 return 0;
355 }
356
45be325c
VY
357 rb_snprintf(temppath, sizeof(temppath), "%s.tmp", ConfigFileEntry.dlinefile);
358
6f3a09ff
JT
359 aconf = find_exact_conf_by_address(cidr, CONF_DLINE, NULL);
360 if(aconf == NULL)
361 {
362 sendto_one_notice(source_p, ":No D-Line for %s", cidr);
363 return 0;
364 }
365
907468c4 366 rb_strlcpy(buf, aconf->host, sizeof buf);
6f3a09ff 367 if(remove_temp_dline(aconf))
212380e3 368 {
369 sendto_one(source_p,
370 ":%s NOTICE %s :Un-dlined [%s] from temporary D-lines",
45be325c 371 me.name, source_p->name, buf);
212380e3 372 sendto_realops_snomask(SNO_GENERAL, L_ALL,
373 "%s has removed the temporary D-Line for: [%s]",
6f3a09ff
JT
374 get_oper_name(source_p), buf);
375 ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), buf);
212380e3 376 return 0;
377 }
378
379 filename = get_conf_name(DLINE_TYPE);
380
381 if((in = fopen(filename, "r")) == 0)
382 {
45be325c 383 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, source_p->name, filename);
212380e3 384 return 0;
385 }
386
387 oldumask = umask(0);
388 if((out = fopen(temppath, "w")) == 0)
389 {
45be325c 390 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, source_p->name, temppath);
212380e3 391 fclose(in);
392 umask(oldumask);
393 return 0;
394 }
395
396 umask(oldumask);
397
398 while (fgets(buf, sizeof(buf), in))
399 {
907468c4 400 rb_strlcpy(buff, buf, sizeof(buff));
212380e3 401
402 if((p = strchr(buff, '\n')) != NULL)
403 *p = '\0';
404
405 if((*buff == '\0') || (*buff == '#'))
406 {
407 if(!error_on_write)
408 flush_write(source_p, out, buf, temppath);
409 continue;
410 }
411
412 if((found_cidr = getfield(buff)) == NULL)
413 {
414 if(!error_on_write)
415 flush_write(source_p, out, buf, temppath);
416 continue;
417 }
418
45be325c 419 if(irccmp(found_cidr, cidr) == 0)
212380e3 420 {
421 pairme++;
422 }
423 else
424 {
425 if(!error_on_write)
426 flush_write(source_p, out, buf, temppath);
427 continue;
428 }
429 }
430
431 fclose(in);
432 if (fclose(out))
433 error_on_write = YES;
434
435 if(error_on_write)
436 {
437 sendto_one(source_p,
438 ":%s NOTICE %s :Couldn't write D-line file, aborted",
45be325c 439 me.name, source_p->name);
212380e3 440 return 0;
441 }
442 else if(!pairme)
443 {
45be325c
VY
444 sendto_one(source_p, ":%s NOTICE %s :No D-Line for %s",
445 me.name, source_p->name, cidr);
212380e3 446
447 if(temppath != NULL)
448 (void) unlink(temppath);
449
450 return 0;
451 }
452
453 if (rename(temppath, filename))
454 {
455 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
456 return 0;
457 }
45be325c 458 rehash_bans(0);
212380e3 459
6f3a09ff 460
45be325c
VY
461 sendto_one(source_p, ":%s NOTICE %s :D-Line for [%s] is removed", me.name, source_p->name, cidr);
462 sendto_realops_snomask(SNO_GENERAL, L_NETWIDE,
463 "%s has removed the D-Line for: [%s]", get_oper_name(source_p), cidr);
464 ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), cidr);
212380e3 465
466 return 0;
467}
468
469/*
470 * valid_comment
471 * inputs - pointer to client
472 * - pointer to comment
473 * output - 0 if no valid comment, 1 if valid
474 * side effects - NONE
475 */
476static int
477valid_comment(char *comment)
478{
479 if(strchr(comment, '"'))
480 return 0;
481
61569b65 482 if(strlen(comment) > BANREASONLEN)
483 comment[BANREASONLEN] = '\0';
212380e3 484
485 return 1;
486}
487
488/*
489 * flush_write()
490 *
491 * inputs - pointer to client structure of oper requesting unkline
492 * - out is the file descriptor
493 * - buf is the buffer to write
494 * - ntowrite is the expected number of character to be written
495 * - temppath is the temporary file name to be written
496 * output - YES for error on write
497 * - NO for success
498 * side effects - if successful, the buf is written to output file
499 * if a write failure happesn, and the file pointed to
500 * by temppath, if its non NULL, is removed.
501 *
502 * The idea here is, to be as robust as possible when writing to the
503 * kline file.
504 *
505 * -Dianora
506 */
507static int
508flush_write(struct Client *source_p, FILE * out, char *buf, char *temppath)
509{
510 int error_on_write = (fputs(buf, out) < 0) ? YES : NO;
511
512 if(error_on_write)
513 {
5366977b 514 sendto_one_notice(source_p, ":Unable to write to %s", temppath);
212380e3 515 fclose(out);
516 if(temppath != NULL)
517 (void) unlink(temppath);
518 }
519 return (error_on_write);
520}
521
522/* remove_temp_dline()
523 *
6f3a09ff 524 * inputs - confitem to undline
212380e3 525 * outputs -
526 * side effects - tries to undline anything that matches
527 */
528static int
6f3a09ff 529remove_temp_dline(struct ConfItem *aconf)
212380e3 530{
08d11e34 531 rb_dlink_node *ptr;
212380e3 532 int i;
533
212380e3 534 for (i = 0; i < LAST_TEMP_TYPE; i++)
535 {
08d11e34 536 RB_DLINK_FOREACH(ptr, temp_dlines[i].head)
212380e3 537 {
6f3a09ff 538 if (aconf == ptr->data)
212380e3 539 {
9f6c3353 540 rb_dlinkDestroy(ptr, &temp_dlines[i]);
212380e3 541 delete_one_address_conf(aconf->host, aconf);
542 return YES;
543 }
544 }
545 }
546
547 return NO;
548}