ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/branches/ircd-hybrid-newconf/src/conf/kill.c
Revision: 1027
Committed: Sun Nov 8 13:01:13 2009 UTC (16 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 14578 byte(s)
Log Message:
- Move old 7.3 sources to branches/ircd-hybrid-newconf

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * kill.c: Defines the kill{} block of ircd.conf.
4 *
5 * Copyright (C) 2006 by the Hybrid Development Team.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "conf/conf.h"
27 #include "client.h"
28 #include "numeric.h"
29 #include "send.h"
30 #include "server.h"
31 #include "ircd.h"
32 #include "parse_aline.h"
33 #include "user.h"
34
35 dlink_list rkline_confs = {NULL, NULL, 0};
36 int acb_type_kline;
37
38 static struct KillConf tmpkill = {{0}, 0};
39 static dlink_node *hreset, *hexpire, *hbanned, *hverify;
40 static struct ConfStoreField kline_fields[] =
41 {
42 { "user", CSF_STRING, CSF_MATCH },
43 { "host", CSF_STRING, CSF_MATCH },
44 { "reason", CSF_STRING, CSF_NOMATCH },
45 { "oper_reason", CSF_STRING, CSF_NOMATCH },
46 { NULL, 0 , 0}
47 };
48
49 static int write_perm_kline(struct KillConf *, struct Client *);
50
51 static void do_report_kline(struct KillConf *, struct Client *);
52 static void do_report_tkline(struct KillConf *, struct Client *);
53
54 /*
55 * free_kline()
56 *
57 * Frees a KillConf item.
58 *
59 * inputs: pointer to KillConf
60 * output: none
61 */
62 void
63 free_kline(struct KillConf *conf)
64 {
65 MyFree(conf->regexuser);
66 MyFree(conf->regexhost);
67 MyFree(conf->oper_reason);
68 MyFree(conf->reason);
69 acb_generic_free(&conf->access);
70 }
71
72 /*
73 * free_tmpkill()
74 *
75 * Called before parsing a kill{} block.
76 *
77 * inputs: none
78 * output: none
79 */
80 static void
81 free_tmpkill(void)
82 {
83 MyFree(tmpkill.access.user);
84 MyFree(tmpkill.access.host);
85 MyFree(tmpkill.regexuser);
86 MyFree(tmpkill.regexhost);
87 MyFree(tmpkill.oper_reason);
88 MyFree(tmpkill.reason);
89 memset(&tmpkill, 0, sizeof(tmpkill));
90 tmpkill.access.type = acb_type_kline;
91 }
92
93 static int
94 commit_tmpkill(const char **errptr)
95 {
96 struct KillConf *conf;
97
98 if (!tmpkill.access.user || !tmpkill.access.host)
99 {
100 free_tmpkill();
101 *errptr = "Missing user/host";
102 return 0;
103 }
104
105 if (tmpkill.access.type == -1)
106 if (!(tmpkill.regexuser = ircd_pcre_compile(tmpkill.access.user, errptr))
107 || !(tmpkill.regexhost = ircd_pcre_compile(tmpkill.access.host, errptr)))
108 {
109 free_tmpkill();
110 return 0;
111 }
112
113 conf = MyMalloc(sizeof(*conf));
114 memcpy(conf, &tmpkill, sizeof(*conf));
115
116 if (tmpkill.access.type == acb_type_kline)
117 add_access_conf(&conf->access);
118 else
119 {
120 conf->access.precedence = curprec--;
121 dlinkAddTail(conf, &conf->node, &rkline_confs);
122 }
123
124 memset(&tmpkill, 0, sizeof(tmpkill));
125 return 1;
126 }
127
128
129 /*
130 * kline_type()
131 *
132 * Parses a "type=" field.
133 *
134 * inputs: item list
135 * output: none
136 */
137 static void
138 kline_type(void *list, void *unused)
139 {
140 dlink_node *ptr;
141
142 DLINK_FOREACH(ptr, ((dlink_list *) list)->head)
143 if (!ircncmp(ptr->data, "regex", 5))
144 tmpkill.access.type = -1;
145 else
146 {
147 parse_error("Syntax error");
148 break;
149 }
150 }
151
152 /*
153 * kline_user()
154 *
155 * Parses a "user=" field.
156 *
157 * inputs: user@host mask
158 * output: none
159 */
160 static void
161 kline_user(void *mask, void *unused)
162 {
163 struct split_nuh_item uh;
164 char userbuf[256], hostbuf[256];
165
166 uh.nuhmask = mask;
167 uh.nickptr = NULL;
168 uh.userptr = userbuf;
169 uh.hostptr = hostbuf;
170
171 uh.nicksize = 0;
172 uh.usersize = sizeof(userbuf);
173 uh.hostsize = sizeof(hostbuf);
174
175 split_nuh(&uh);
176
177 MyFree(tmpkill.access.user);
178 MyFree(tmpkill.access.host);
179 DupString(tmpkill.access.user, userbuf);
180 DupString(tmpkill.access.host, hostbuf);
181 }
182
183 /*
184 * after_kline()
185 *
186 * Called after parsing a kill{} block.
187 *
188 * inputs: none
189 * output: none
190 */
191 static void
192 after_kline(void)
193 {
194 const char *errptr = NULL;
195 const char *type = (tmpkill.access.type == -1) ? "RK-line" : "K-line";
196
197 if (! commit_tmpkill(&errptr))
198 parse_error("Failed to add %s: %s", type, errptr);
199 }
200
201 /*
202 * load_klines()
203 *
204 * Loads permanent klines from external storage.
205 *
206 * inputs: none
207 * output: none
208 */
209 static void *
210 load_klines(va_list args)
211 {
212 const char *errptr = NULL;
213 struct ConfStoreHandle *handle;
214
215 if ((handle = open_conf_store(ServerState.klinefile, &kline_fields)) != NULL)
216 {
217 while (read_conf_store(handle, &tmpkill.access.user,
218 &tmpkill.access.host, &tmpkill.reason,
219 &tmpkill.oper_reason))
220 {
221 tmpkill.access.type = acb_type_kline;
222 if (! commit_tmpkill(&errptr))
223 ilog(L_ERROR, "Failed to load K-line from conf store: %s", errptr);
224 }
225
226 close_conf_store(handle);
227 }
228 else
229 ilog(L_ERROR, "Failed to open K-line store: %s", ServerState.klinefile);
230
231 if ((handle = open_conf_store(ServerState.rklinefile, &kline_fields)) != NULL)
232 {
233 while (read_conf_store(handle, &tmpkill.access.user,
234 &tmpkill.access.host, &tmpkill.reason,
235 &tmpkill.oper_reason))
236 {
237 tmpkill.access.type = -1;
238 if (! commit_tmpkill(&errptr))
239 ilog(L_ERROR, "Failed to load RK-line from conf store: %s", errptr);
240 }
241
242 close_conf_store(handle);
243 }
244 else
245 ilog(L_ERROR, "Failed to open RK-line store: %s", ServerState.rklinefile);
246
247 return pass_callback(hverify);
248 }
249
250 static void
251 add_line(struct Client *source_p, char *type, char *user, char *host,
252 char *reason, char *oper_reason, int tkline_time)
253 {
254 const char *errptr = NULL;
255
256 DupString(tmpkill.access.user, user);
257 DupString(tmpkill.access.host, host);
258
259 tmpkill.reason = a_line_format_reason(reason, type, tkline_time);
260 DupString(tmpkill.oper_reason, oper_reason);
261 tmpkill.access.expires = CurrentTime + tkline_time;
262
263 // We have to do this first, as commit_tmpkill() zeroes out tmpkill :/
264 if (!tkline_time && write_perm_kline(&tmpkill, source_p))
265 sendto_one(source_p, ":%s NOTICE %s :Added %s [%s@%s] to storage",
266 me.name, source_p->name, type, user, host);
267
268 if (commit_tmpkill(&errptr))
269 announce_a_line(source_p, type, tkline_time, reason, oper_reason,
270 "%s@%s", user, host);
271 else
272 sendto_one(source_p, ":%s NOTICE %s :Failed to add %s: %s",
273 me.name, source_p->name, type, errptr);
274 }
275
276 void
277 add_rkline(struct Client *source_p, char *user, char *host, char *reason,
278 char *oper_reason, int tkline_time)
279 {
280 tmpkill.access.type = -1;
281 add_line(source_p, "RK-Line", user, host, reason, oper_reason, tkline_time);
282 }
283
284 void
285 add_kline(struct Client *source_p, char *user, char *host, char *reason,
286 char *oper_reason, int tkline_time)
287 {
288 tmpkill.access.type = acb_type_kline;
289 add_line(source_p, "K-Line", user, host, reason, oper_reason, tkline_time);
290 rehashed_klines = 1;
291 }
292
293 /*
294 * write_perm_kline()
295 *
296 * Saves a permanent K-line into an external store.
297 *
298 * inputs:
299 * conf - pointer to struct KillConf
300 * oper - oper who issued the K-line
301 * output: 0 on error
302 */
303 static int
304 write_perm_kline(struct KillConf *conf, struct Client *source_p)
305 {
306 char *filename;
307
308 if (conf->access.type == acb_type_kline)
309 filename = ServerState.klinefile;
310 else if (conf->access.type == -1)
311 filename = ServerState.rklinefile;
312 else
313 return 0;
314
315 return !append_conf_store(filename, &kline_fields, source_p,
316 conf->access.user, conf->access.host,
317 conf->reason, conf->oper_reason);
318 }
319
320 /*
321 * delete_perm_kline()
322 *
323 * Deletes a permanent K-line from an external store.
324 *
325 * inputs: pointer to struct KillConf
326 * output: 0 on error
327 */
328 int
329 delete_perm_kline(struct KillConf *conf)
330 {
331 char *filename;
332
333 if (conf->access.type == acb_type_kline)
334 filename = ServerState.klinefile;
335 else if (conf->access.type == -1)
336 filename = ServerState.rklinefile;
337 else
338 return 0;
339
340 return 0 <= delete_csv(filename, &kline_fields,
341 conf->access.user, conf->access.host);
342 }
343
344 /*
345 * reset_rklines()
346 *
347 * Frees all permanent regex K-lines before a rehash.
348 *
349 * inputs: none
350 * output: none
351 */
352 static void *
353 reset_rklines(va_list args)
354 {
355 dlink_node *ptr, *ptr_next;
356
357 DLINK_FOREACH_SAFE(ptr, ptr_next, rkline_confs.head)
358 {
359 struct KillConf *conf = ptr->data;
360
361 if (!conf->access.expires)
362 {
363 dlinkDelete(&conf->node, &rkline_confs);
364 free_kline(conf);
365 }
366 }
367
368 return pass_callback(hreset);
369 }
370
371 /*
372 * expire_rklines()
373 *
374 * Goes through the regex K-line list and destroys the ones
375 * already expired.
376 *
377 * inputs: none
378 * output: none
379 */
380 static void *
381 expire_rklines(va_list args)
382 {
383 dlink_node *ptr, *ptr_next;
384
385 DLINK_FOREACH_SAFE(ptr, ptr_next, rkline_confs.head)
386 {
387 struct KillConf *conf = ptr->data;
388
389 if (conf->access.expires && conf->access.expires <= CurrentTime)
390 {
391 sendto_realops_flags(UMODE_ALL, L_ALL,
392 "Temporary %s for [%s@%s] expired", "K-line",
393 conf->access.user, conf->access.host);
394 dlinkDelete(&conf->node, &rkline_confs);
395 free_kline(conf);
396 }
397 }
398
399 return pass_callback(hexpire);
400 }
401
402 /*
403 * find_kline()
404 *
405 * Looks for a matching K-line.
406 *
407 * inputs:
408 * user - username part, can be NULL
409 * host - hostname part, can be NULL
410 * sockhost - IP address as string, used in pair with the next argument
411 * ip - IP address (with ss.sin_family set), can be NULL
412 * output: pointer to KillConf
413 */
414 struct KillConf *
415 find_kline(const char *user, const char *host, const char *sockhost,
416 const struct irc_ssaddr *ip)
417 {
418 struct KillConf *best = NULL;
419 dlink_node *ptr;
420
421 best = (struct KillConf *) find_access_conf(acb_type_kline, user, host, ip,
422 NULL, NULL);
423
424 DLINK_FOREACH(ptr, rkline_confs.head)
425 {
426 struct KillConf *rkline = ptr->data;
427
428 if ((!best || rkline->access.precedence > best->access.precedence) &&
429 !ircd_pcre_exec(rkline->regexuser, user) &&
430 (!ircd_pcre_exec(rkline->regexhost, host) ||
431 !ircd_pcre_exec(rkline->regexhost, sockhost)))
432 best = rkline;
433 }
434
435 return best;
436 }
437
438 struct KillConf *
439 find_exact_rkline(const char *user, const char *host)
440 {
441 dlink_node *ptr;
442
443 DLINK_FOREACH(ptr, rkline_confs.head)
444 {
445 struct KillConf *conf = ptr->data;
446 if (!irccmp(conf->access.host, host) && !irccmp(conf->access.user, user))
447 return conf;
448 }
449
450 return NULL;
451 }
452
453 /*
454 * report_klines()
455 *
456 * Sends a list of [Kk]-lines to client_p in /stats format.
457 *
458 * inputs:
459 * client_p - where to send
460 * tkline - YES if we should list temporary klines, NO if permanent ones
461 * output: none
462 */
463 static void
464 do_report_klines(struct Client *client_p, int tkline)
465 {
466 void (* func)(struct KillConf *, struct Client *) = tkline ?
467 do_report_tkline : do_report_kline;
468 struct KillConf *conf;
469 dlink_node *ptr;
470
471 if (General.stats_k_oper_only == 2 && !IsOper(client_p))
472 sendto_one(client_p, form_str(ERR_NOPRIVILEGES),
473 ID_or_name(&me, client_p->from),
474 ID_or_name(client_p, client_p->from));
475 else if (General.stats_k_oper_only == 1 && !IsOper(client_p))
476 {
477 if ((conf = find_kline(client_p->username, client_p->host,
478 client_p->sockhost, MyConnect(client_p) ?
479 &client_p->localClient->ip : NULL)))
480 func(conf, client_p);
481 }
482 else
483 {
484 enum_access_confs((ACB_EXAMINE_HANDLER*) func, client_p);
485 DLINK_FOREACH(ptr, rkline_confs.head)
486 func(ptr->data, client_p);
487 }
488 }
489
490 void report_klines(struct Client *client_p) { do_report_klines(client_p, NO); }
491 void report_tklines(struct Client *client_p) { do_report_klines(client_p, YES); }
492
493 static void
494 do_report_kline(struct KillConf *conf, struct Client *client_p)
495 {
496 if ((conf->access.type == acb_type_kline || conf->access.type == -1) &&
497 !conf->access.expires)
498 sendto_one(client_p, form_str(RPL_STATSKLINE),
499 ID_or_name(&me, client_p->from),
500 ID_or_name(client_p, client_p->from),
501 (conf->access.type < 0) ? "RK" : "K",
502 conf->access.host, conf->access.user, conf->reason,
503 (IsOper(client_p) && conf->oper_reason) ?
504 conf->oper_reason : "");
505 }
506
507 static void
508 do_report_tkline(struct KillConf *conf, struct Client *client_p)
509 {
510 if ((conf->access.type == acb_type_kline || conf->access.type == -1) &&
511 conf->access.expires)
512 sendto_one(client_p, form_str(RPL_STATSKLINE),
513 ID_or_name(&me, client_p->from),
514 ID_or_name(client_p, client_p->from),
515 (conf->access.type < 0) ? "Rk" : "k",
516 conf->access.host, conf->access.user, conf->reason,
517 (IsOper(client_p) && conf->oper_reason) ?
518 conf->oper_reason : "");
519 }
520
521 /*
522 * is_client_klined()
523 *
524 * Hook function for is_client_banned.
525 *
526 * inputs:
527 * client - local client to check
528 * type - we set it to ban type if there's a match
529 * reason - we set it to ban reason (if any)
530 * output: not NULL if they're banned
531 */
532 static void *
533 is_client_klined(va_list args)
534 {
535 struct Client *client = va_arg(args, struct Client *);
536 char **type = va_arg(args, char **);
537 char **reason = va_arg(args, char **);
538 struct KillConf *conf = IsExemptKline(client) ? NULL :
539 find_kline(client->username, client->host, client->sockhost,
540 &client->localClient->ip);
541
542 if (conf)
543 {
544 *type = "K-line";
545 *reason = conf->reason;
546 return conf;
547 }
548
549 return pass_callback(hbanned, client, type, reason);
550 }
551
552 /*
553 * init_kill()
554 *
555 * Defines the kill{} conf section.
556 *
557 * inputs: none
558 * output: none
559 */
560 void
561 init_kill(void)
562 {
563 struct ConfSection *s = add_conf_section("kill", 2);
564
565 acb_type_kline = register_acb_type("K-line", free_kline);
566 hreset = install_hook(reset_conf, reset_rklines);
567 hexpire = install_hook(expire_confs, expire_rklines);
568 hbanned = install_hook(is_client_banned, is_client_klined);
569
570 s->before = free_tmpkill;
571
572 s->def_field = add_conf_field(s, "user", CT_STRING, kline_user, NULL);
573 add_conf_field(s, "type", CT_LIST, kline_type, NULL);
574 add_conf_field(s, "reason", CT_STRING, NULL, &tmpkill.reason);
575
576 s->after = after_kline;
577
578 hverify = install_hook(verify_conf, load_klines);
579 }

Properties

Name Value
svn:eol-style native
svn:keywords "Id Revision"