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