]> jfr.im git - irc/rqf/shadowircd.git/blame - modules/m_dline.c
DubString -> rb_strdup
[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"
32#include "irc_string.h"
33#include "sprintf_irc.h"
34#include "ircd.h"
35#include "hostmask.h"
36#include "numeric.h"
212380e3 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
47static int mo_dline(struct Client *, struct Client *, int, const char **);
48static int mo_undline(struct Client *, struct Client *, int, const char **);
49
50struct Message dline_msgtab = {
51 "DLINE", 0, 0, 0, MFLG_SLOW,
52 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_dline, 2}}
53};
54struct Message undline_msgtab = {
55 "UNDLINE", 0, 0, 0, MFLG_SLOW,
56 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_undline, 2}}
57};
58
59mapi_clist_av1 dline_clist[] = { &dline_msgtab, &undline_msgtab, NULL };
61569b65 60DECLARE_MODULE_AV1(dline, NULL, NULL, dline_clist, NULL, NULL, "$Revision: 3225 $");
212380e3 61
62static int valid_comment(char *comment);
63static int flush_write(struct Client *, FILE *, char *, char *);
6f3a09ff 64static int remove_temp_dline(struct ConfItem *);
212380e3 65
66/* mo_dline()
67 *
68 * parv[1] - dline to add
69 * parv[2] - reason
70 */
71static int
72mo_dline(struct Client *client_p, struct Client *source_p,
73 int parc, const char *parv[])
74{
75 char def[] = "No Reason";
76 const char *dlhost;
77 char *oper_reason;
78 char *reason = def;
79 struct irc_sockaddr_storage daddr;
80 char cidr_form_host[HOSTLEN + 1];
81 struct ConfItem *aconf;
82 int bits;
83 char dlbuffer[IRCD_BUFSIZE];
84 const char *current_date;
85 int tdline_time = 0;
86 int loc = 1;
87
88 if(!IsOperK(source_p))
89 {
90 sendto_one(source_p, form_str(ERR_NOPRIVS),
91 me.name, source_p->name, "kline");
92 return 0;
93 }
94
95 if((tdline_time = valid_temp_time(parv[loc])) >= 0)
96 loc++;
97
98 if(parc < loc + 1)
99 {
100 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
101 me.name, source_p->name, "DLINE");
102 return 0;
103 }
104
105 dlhost = parv[loc];
106 strlcpy(cidr_form_host, dlhost, sizeof(cidr_form_host));
107
108 if(!parse_netmask(dlhost, NULL, &bits))
109 {
110 sendto_one(source_p, ":%s NOTICE %s :Invalid D-Line",
111 me.name, source_p->name);
112 return 0;
113 }
114
115 loc++;
116
117 if(parc >= loc + 1) /* host :reason */
118 {
119 if(!EmptyString(parv[loc]))
120 reason = LOCAL_COPY(parv[loc]);
121
122 if(!valid_comment(reason))
123 {
124 sendto_one(source_p,
125 ":%s NOTICE %s :Invalid character '\"' in comment",
126 me.name, source_p->name);
127 return 0;
128 }
129 }
130
131 if(IsOperAdmin(source_p))
132 {
133 if(bits < 8)
134 {
135 sendto_one(source_p,
136 ":%s NOTICE %s :For safety, bitmasks less than 8 require conf access.",
137 me.name, parv[0]);
138 return 0;
139 }
140 }
141 else
142 {
143 if(bits < 16)
144 {
145 sendto_one(source_p,
146 ":%s NOTICE %s :Dline bitmasks less than 16 are for admins only.",
147 me.name, parv[0]);
148 return 0;
149 }
150 }
151
152 if(ConfigFileEntry.non_redundant_klines)
153 {
154 const char *creason;
155 int t = AF_INET, ty, b;
156 ty = parse_netmask(dlhost, (struct sockaddr *)&daddr, &b);
157#ifdef IPV6
158 if(ty == HM_IPV6)
159 t = AF_INET6;
160 else
161#endif
162 t = AF_INET;
163
164 if((aconf = find_dline((struct sockaddr *)&daddr, t)) != NULL)
165 {
166 int bx;
167 parse_netmask(aconf->host, NULL, &bx);
168 if(b >= bx)
169 {
170 creason = aconf->passwd ? aconf->passwd : "<No Reason>";
171 if(IsConfExemptKline(aconf))
172 sendto_one(source_p,
173 ":%s NOTICE %s :[%s] is (E)d-lined by [%s] - %s",
174 me.name, parv[0], dlhost, aconf->host, creason);
175 else
176 sendto_one(source_p,
177 ":%s NOTICE %s :[%s] already D-lined by [%s] - %s",
178 me.name, parv[0], dlhost, aconf->host, creason);
179 return 0;
180 }
181 }
182 }
183
184 set_time();
185 current_date = smalldate();
186
187 aconf = make_conf();
188 aconf->status = CONF_DLINE;
62d28946 189 aconf->host = rb_strdup(dlhost);
212380e3 190
191 /* Look for an oper reason */
192 if((oper_reason = strchr(reason, '|')) != NULL)
193 {
194 *oper_reason = '\0';
195 oper_reason++;
196
197 if(!EmptyString(oper_reason))
62d28946 198 aconf->spasswd = rb_strdup(oper_reason);
212380e3 199 }
200
201 if(tdline_time > 0)
202 {
581fa5c4 203 rb_snprintf(dlbuffer, sizeof(dlbuffer),
212380e3 204 "Temporary D-line %d min. - %s (%s)",
205 (int) (tdline_time / 60), reason, current_date);
62d28946 206 aconf->passwd = rb_strdup(dlbuffer);
212380e3 207 aconf->hold = CurrentTime + tdline_time;
208 add_temp_dline(aconf);
209
210 if(EmptyString(oper_reason))
211 {
212 sendto_realops_snomask(SNO_GENERAL, L_ALL,
213 "%s added temporary %d min. D-Line for [%s] [%s]",
214 get_oper_name(source_p), tdline_time / 60,
215 aconf->host, reason);
216 ilog(L_KLINE, "D %s %d %s %s",
217 get_oper_name(source_p), tdline_time / 60,
218 aconf->host, reason);
219 }
220 else
221 {
222 sendto_realops_snomask(SNO_GENERAL, L_ALL,
223 "%s added temporary %d min. D-Line for [%s] [%s|%s]",
224 get_oper_name(source_p), tdline_time / 60,
225 aconf->host, reason, oper_reason);
226 ilog(L_KLINE, "D %s %d %s %s|%s",
227 get_oper_name(source_p), tdline_time / 60,
228 aconf->host, reason, oper_reason);
229 }
230
231 sendto_one(source_p, ":%s NOTICE %s :Added temporary %d min. D-Line for [%s]",
232 me.name, source_p->name, tdline_time / 60, aconf->host);
233 }
234 else
235 {
581fa5c4 236 rb_snprintf(dlbuffer, sizeof(dlbuffer), "%s (%s)", reason, current_date);
62d28946 237 aconf->passwd = rb_strdup(dlbuffer);
212380e3 238 add_conf_by_address(aconf->host, CONF_DLINE, NULL, aconf);
239 write_confitem(DLINE_TYPE, source_p, NULL, aconf->host, reason,
240 oper_reason, current_date, 0);
241 }
242
243 check_dlines();
244 return 0;
245}
246
247/* mo_undline()
248 *
249 * parv[1] = dline to remove
250 */
251static int
252mo_undline(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
253{
254 FILE *in;
255 FILE *out;
256 char buf[BUFSIZE], buff[BUFSIZE], temppath[BUFSIZE], *p;
257 const char *filename, *found_cidr;
258 const char *cidr;
6f3a09ff 259 struct ConfItem *aconf;
212380e3 260 int pairme = NO, error_on_write = NO;
261 mode_t oldumask;
262
581fa5c4 263 rb_snprintf(temppath, sizeof(temppath), "%s.tmp", ConfigFileEntry.dlinefile);
212380e3 264
265 if(!IsOperUnkline(source_p))
266 {
267 sendto_one(source_p, form_str(ERR_NOPRIVS),
268 me.name, source_p->name, "unkline");
269 return 0;
270 }
271
272 cidr = parv[1];
273
274 if(parse_netmask(cidr, NULL, NULL) == HM_HOST)
275 {
5366977b 276 sendto_one_notice(source_p, ":Invalid D-Line");
212380e3 277 return 0;
278 }
279
6f3a09ff
JT
280 aconf = find_exact_conf_by_address(cidr, CONF_DLINE, NULL);
281 if(aconf == NULL)
282 {
283 sendto_one_notice(source_p, ":No D-Line for %s", cidr);
284 return 0;
285 }
286
287 strlcpy(buf, aconf->host, sizeof buf);
288 if(remove_temp_dline(aconf))
212380e3 289 {
290 sendto_one(source_p,
291 ":%s NOTICE %s :Un-dlined [%s] from temporary D-lines",
6f3a09ff 292 me.name, parv[0], buf);
212380e3 293 sendto_realops_snomask(SNO_GENERAL, L_ALL,
294 "%s has removed the temporary D-Line for: [%s]",
6f3a09ff
JT
295 get_oper_name(source_p), buf);
296 ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), buf);
212380e3 297 return 0;
298 }
299
300 filename = get_conf_name(DLINE_TYPE);
301
302 if((in = fopen(filename, "r")) == 0)
303 {
304 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, parv[0], filename);
305 return 0;
306 }
307
308 oldumask = umask(0);
309 if((out = fopen(temppath, "w")) == 0)
310 {
311 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name, parv[0], temppath);
312 fclose(in);
313 umask(oldumask);
314 return 0;
315 }
316
317 umask(oldumask);
318
319 while (fgets(buf, sizeof(buf), in))
320 {
321 strlcpy(buff, buf, sizeof(buff));
322
323 if((p = strchr(buff, '\n')) != NULL)
324 *p = '\0';
325
326 if((*buff == '\0') || (*buff == '#'))
327 {
328 if(!error_on_write)
329 flush_write(source_p, out, buf, temppath);
330 continue;
331 }
332
333 if((found_cidr = getfield(buff)) == NULL)
334 {
335 if(!error_on_write)
336 flush_write(source_p, out, buf, temppath);
337 continue;
338 }
339
6f3a09ff 340 if(irccmp(found_cidr, aconf->host) == 0)
212380e3 341 {
342 pairme++;
343 }
344 else
345 {
346 if(!error_on_write)
347 flush_write(source_p, out, buf, temppath);
348 continue;
349 }
350 }
351
352 fclose(in);
353 if (fclose(out))
354 error_on_write = YES;
355
356 if(error_on_write)
357 {
358 sendto_one(source_p,
359 ":%s NOTICE %s :Couldn't write D-line file, aborted",
360 me.name, parv[0]);
361 return 0;
362 }
363 else if(!pairme)
364 {
6f3a09ff
JT
365 sendto_one_notice(source_p, ":Cannot find D-Line for %s in file",
366 aconf->host);
212380e3 367
368 if(temppath != NULL)
369 (void) unlink(temppath);
370
371 return 0;
372 }
373
374 if (rename(temppath, filename))
375 {
376 sendto_one_notice(source_p, ":Couldn't rename temp file, aborted");
377 return 0;
378 }
212380e3 379
6f3a09ff 380 sendto_one(source_p, ":%s NOTICE %s :D-Line for [%s] is removed", me.name, parv[0], aconf->host);
212380e3 381 sendto_realops_snomask(SNO_GENERAL, L_ALL,
6f3a09ff
JT
382 "%s has removed the D-Line for: [%s]", get_oper_name(source_p), aconf->host);
383 ilog(L_KLINE, "UD %s %s", get_oper_name(source_p), aconf->host);
384
385 delete_one_address_conf(aconf->host, aconf);
212380e3 386
387 return 0;
388}
389
390/*
391 * valid_comment
392 * inputs - pointer to client
393 * - pointer to comment
394 * output - 0 if no valid comment, 1 if valid
395 * side effects - NONE
396 */
397static int
398valid_comment(char *comment)
399{
400 if(strchr(comment, '"'))
401 return 0;
402
61569b65 403 if(strlen(comment) > BANREASONLEN)
404 comment[BANREASONLEN] = '\0';
212380e3 405
406 return 1;
407}
408
409/*
410 * flush_write()
411 *
412 * inputs - pointer to client structure of oper requesting unkline
413 * - out is the file descriptor
414 * - buf is the buffer to write
415 * - ntowrite is the expected number of character to be written
416 * - temppath is the temporary file name to be written
417 * output - YES for error on write
418 * - NO for success
419 * side effects - if successful, the buf is written to output file
420 * if a write failure happesn, and the file pointed to
421 * by temppath, if its non NULL, is removed.
422 *
423 * The idea here is, to be as robust as possible when writing to the
424 * kline file.
425 *
426 * -Dianora
427 */
428static int
429flush_write(struct Client *source_p, FILE * out, char *buf, char *temppath)
430{
431 int error_on_write = (fputs(buf, out) < 0) ? YES : NO;
432
433 if(error_on_write)
434 {
5366977b 435 sendto_one_notice(source_p, ":Unable to write to %s", temppath);
212380e3 436 fclose(out);
437 if(temppath != NULL)
438 (void) unlink(temppath);
439 }
440 return (error_on_write);
441}
442
443/* remove_temp_dline()
444 *
6f3a09ff 445 * inputs - confitem to undline
212380e3 446 * outputs -
447 * side effects - tries to undline anything that matches
448 */
449static int
6f3a09ff 450remove_temp_dline(struct ConfItem *aconf)
212380e3 451{
08d11e34 452 rb_dlink_node *ptr;
212380e3 453 int i;
454
212380e3 455 for (i = 0; i < LAST_TEMP_TYPE; i++)
456 {
08d11e34 457 RB_DLINK_FOREACH(ptr, temp_dlines[i].head)
212380e3 458 {
6f3a09ff 459 if (aconf == ptr->data)
212380e3 460 {
9f6c3353 461 rb_dlinkDestroy(ptr, &temp_dlines[i]);
212380e3 462 delete_one_address_conf(aconf->host, aconf);
463 return YES;
464 }
465 }
466 }
467
468 return NO;
469}