ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/modules/operserv/rwatch.C
Revision: 1.7
Committed: Sat Sep 22 14:27:28 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +3 -3 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

File Contents

# Content
1 /**
2 * rwatch.C: This file contains functionality implementing OperServ RWATCH.
3 *
4 * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5 * Rights to this code are as documented in COPYING.
6 *
7 *
8 * Portions of this file were derived from sources bearing the following license:
9 * Copyright © 2006 Atheme Development Group
10 * Rights to this code are documented in doc/LICENCE.
11 *
12 * $Id: rwatch.C,v 1.6 2007-09-16 18:54:44 pippijn Exp $
13 */
14
15 #include "atheme.h"
16 #include <ermyth/module.h>
17
18 static char const rcsid[] = "$Id: rwatch.C,v 1.6 2007-09-16 18:54:44 pippijn Exp $";
19
20 REGISTER_MODULE ("operserv/rwatch", false, "The Ermyth Team <http://ermyth.xinutec.org>");
21
22 static void os_cmd_rwatch (sourceinfo_t *si, int parc, char *parv[]);
23 static void os_cmd_rwatch_list (sourceinfo_t *si, int parc, char *parv[]);
24 static void os_cmd_rwatch_add (sourceinfo_t *si, int parc, char *parv[]);
25 static void os_cmd_rwatch_del (sourceinfo_t *si, int parc, char *parv[]);
26 static void os_cmd_rwatch_set (sourceinfo_t *si, int parc, char *parv[]);
27
28 static void write_rwatchdb (void);
29 static void load_rwatchdb (void);
30
31 E cmdvec os_cmdtree;
32 E helpvec os_helptree;
33 cmdvec os_rwatch_cmds;
34
35 list_t rwatch_list;
36
37 #define RWACT_SNOOP 1
38 #define RWACT_KLINE 2
39
40 typedef struct rwatch_ rwatch_t;
41 struct rwatch_
42 {
43 char *regex;
44 int reflags; /* AREGEX_* */
45 char *reason;
46 int actions; /* RWACT_* */
47 regex_t *re;
48 };
49
50 command_t const os_rwatch = { "RWATCH", N_("Performs actions on connecting clients matching regexes."), PRIV_USER_AUSPEX, 2, os_cmd_rwatch };
51
52 command_t const os_rwatch_add = { "ADD", N_("Adds an entry to the regex watch list."), AC_NONE, 1, os_cmd_rwatch_add };
53 command_t const os_rwatch_del = { "DEL", N_("Removes an entry from the regex watch list."), AC_NONE, 1, os_cmd_rwatch_del };
54 command_t const os_rwatch_list = { "LIST", N_("Displays the regex watch list."), AC_NONE, 1, os_cmd_rwatch_list };
55 command_t const os_rwatch_set = { "SET", N_("Changes actions on an entry in the regex watch list"), AC_NONE, 1, os_cmd_rwatch_set };
56
57 static void
58 write_rwatchdb (void)
59 {
60 FILE *f;
61 node_t *n;
62 rwatch_t *rw;
63
64 if (!(f = fopen (DATADIR "/rwatch.db.new", "w")))
65 {
66 slog (LG_ERROR, "write_rwatchdb(): cannot write rwatch database: %s", strerror (errno));
67 return;
68 }
69
70 LIST_FOREACH (n, rwatch_list.head)
71 {
72 rw = static_cast < rwatch_t * >(n->data);
73 fprintf (f, "RW %d %s\n", rw->reflags, rw->regex);
74 fprintf (f, "RR %d %s\n", rw->actions, rw->reason);
75 }
76
77 fclose (f);
78
79 if ((rename (DATADIR "/rwatch.db.new", DATADIR "/rwatch.db")) < 0)
80 {
81 slog (LG_ERROR, "write_rwatchdb(): couldn't rename rwatch database.");
82 return;
83 }
84 }
85
86 static void
87 load_rwatchdb (void)
88 {
89 FILE *f;
90 char *item, rBuf[BUFSIZE * 2];
91 rwatch_t *rw = NULL;
92
93 if (!(f = fopen (DATADIR "/rwatch.db", "r")))
94 {
95 slog (LG_DEBUG, "load_rwatchdb(): cannot open rwatch database: %s", strerror (errno));
96 return;
97 }
98
99 while (fgets (rBuf, BUFSIZE * 2, f))
100 {
101 item = strtok (rBuf, " ");
102 strip (item);
103
104 if (!strcmp (item, "RW"))
105 {
106 char *reflagsstr = strtok (NULL, " ");
107 char *regex = strtok (NULL, "\n");
108
109 if (!reflagsstr || !regex || rw)
110 ; /* erroneous, don't add */
111 else
112 {
113 rw = new rwatch_t;
114
115 rw->regex = sstrdup (regex);
116 rw->reflags = atoi (reflagsstr);
117 rw->re = regex_create (rw->regex, rw->reflags);
118 }
119 }
120 else if (!strcmp (item, "RR"))
121 {
122 char *actionstr = strtok (NULL, " ");
123 char *reason = strtok (NULL, "\n");
124
125 if (!actionstr || !reason || !rw)
126 ; /* erroneous, don't add */
127 else
128 {
129 rw->actions = atoi (actionstr);
130 rw->reason = sstrdup (reason);
131 node_add (rw, node_create (), &rwatch_list);
132 rw = NULL;
133 }
134 }
135 }
136
137 fclose (f);
138 }
139
140 static void
141 os_cmd_rwatch (sourceinfo_t *si, int parc, char *parv[])
142 {
143 /* Grab args */
144 char *cmd = parv[0];
145 command_t const *c;
146
147 /* Bad/missing arg */
148 if (!cmd)
149 {
150 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH");
151 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH ADD|DEL|LIST|SET"));
152 return;
153 }
154
155 c = os_rwatch_cmds.find (cmd);
156 if (c == NULL)
157 {
158 command_fail (si, fault::badparams, _("Invalid command. Use \2/%s%s help\2 for a command listing."), (ircd->uses_rcommand == false) ? "msg " : "", si->service->disp);
159 return;
160 }
161
162 c->exec (si->service, si, parc - 1, parv + 1);
163 }
164
165 static void
166 os_cmd_rwatch_add (sourceinfo_t *si, int parc, char *parv[])
167 {
168 node_t *n;
169 char *pattern;
170 char *reason;
171 regex_t *regex;
172 rwatch_t *rw;
173 int flags;
174 char *args = parv[0];
175
176 if (args == NULL)
177 {
178 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH ADD");
179 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH ADD /<regex>/[i] <reason>"));
180 return;
181 }
182
183 pattern = regex_extract (args, &args, &flags);
184 if (pattern == NULL)
185 {
186 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "RWATCH ADD");
187 command_fail (si, fault::badparams, _("Syntax: RWATCH ADD /<regex>/[i] <reason>"));
188 return;
189 }
190
191 reason = args;
192 while (*reason == ' ')
193 reason++;
194 if (*reason == '\0')
195 {
196 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH ADD");
197 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH ADD /<regex>/[i] <reason>"));
198 return;
199 }
200
201 LIST_FOREACH (n, rwatch_list.head)
202 {
203 rwatch_t *t = static_cast < rwatch_t * >(n->data);
204
205 if (!strcmp (pattern, t->regex))
206 {
207 command_fail (si, fault::nochange, _("\2%s\2 already found in regex watch list; not adding."), pattern);
208 return;
209 }
210 }
211
212 regex = regex_create (pattern, flags);
213 if (regex == NULL)
214 {
215 command_fail (si, fault::badparams, _("The provided regex \2%s\2 is invalid."), pattern);
216 return;
217 }
218
219 rw = new rwatch_t;
220 rw->regex = sstrdup (pattern);
221 rw->reflags = flags;
222 rw->reason = sstrdup (reason);
223 rw->actions = RWACT_SNOOP;
224 rw->re = regex;
225
226 node_add (rw, node_create (), &rwatch_list);
227 command_success_nodata (si, _("Added \2%s\2 to regex watch list."), pattern);
228 snoop ("RWATCH:ADD: \2%s\2 by \2%s\2", pattern, get_oper_name (si));
229 logcommand (si, CMDLOG_ADMIN, "RWATCH ADD %s %s", pattern, reason);
230 write_rwatchdb ();
231 }
232
233 static void
234 os_cmd_rwatch_del (sourceinfo_t *si, int parc, char *parv[])
235 {
236 node_t *n, *tn;
237 char *pattern;
238 int flags;
239 char *args = parv[0];
240
241 if (args == NULL)
242 {
243 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH DEL");
244 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH DEL /<regex>/[i]"));
245 return;
246 }
247
248 pattern = regex_extract (args, &args, &flags);
249 if (pattern == NULL)
250 {
251 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "RWATCH DEL");
252 command_fail (si, fault::badparams, _("Syntax: RWATCH DEL /<regex>/[i]"));
253 return;
254 }
255
256 LIST_FOREACH_SAFE (n, tn, rwatch_list.head)
257 {
258 rwatch_t *rw = static_cast < rwatch_t * >(n->data);
259
260 if (!strcmp (rw->regex, pattern))
261 {
262 if (rw->actions & RWACT_KLINE)
263 {
264 if (!has_priv (si, PRIV_MASS_AKILL))
265 {
266 command_fail (si, fault::noprivs, _("You do not have %s privilege."), PRIV_MASS_AKILL);
267 return;
268 }
269 wallops ("\2%s\2 disabled kline on regex watch pattern \2%s\2", get_oper_name (si), pattern);
270 }
271 sfree (rw->regex);
272 sfree (rw->reason);
273 if (rw->re != NULL)
274 regex_destroy (rw->re);
275 delete rw;
276 node_del (n, &rwatch_list);
277 node_free (n);
278 command_success_nodata (si, _("Removed \2%s\2 from regex watch list."), pattern);
279 snoop ("RWATCH:DEL: \2%s\2 by \2%s\2", pattern, get_oper_name (si));
280 logcommand (si, CMDLOG_ADMIN, "RWATCH DEL %s", pattern);
281 write_rwatchdb ();
282 return;
283 }
284 }
285
286 command_fail (si, fault::nochange, _("\2%s\2 not found in regex watch list."), pattern);
287 }
288
289 static void
290 os_cmd_rwatch_list (sourceinfo_t *si, int parc, char *parv[])
291 {
292 node_t *n;
293
294 LIST_FOREACH (n, rwatch_list.head)
295 {
296 rwatch_t *rw = static_cast < rwatch_t * >(n->data);
297
298 command_success_nodata (si, "%s (%s%s%s) - %s", rw->regex, rw->reflags & AREGEX_ICASE ? "i" : "", rw->actions & RWACT_SNOOP ? "S" : "", rw->actions & RWACT_KLINE ? "\2K\2" : "", rw->reason);
299 }
300 command_success_nodata (si, _("End of RWATCH LIST"));
301 logcommand (si, CMDLOG_GET, "RWATCH LIST");
302 }
303
304 static void
305 os_cmd_rwatch_set (sourceinfo_t *si, int parc, char *parv[])
306 {
307 node_t *n, *tn;
308 char *pattern;
309 char *opts;
310 int addflags = 0, removeflags = 0;
311 int flags;
312 char *args = parv[0];
313
314 if (args == NULL)
315 {
316 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH SET");
317 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH SET /<regex>/[i] [KLINE] [NOKLINE] [SNOOP] [NOSNOOP]"));
318 return;
319 }
320
321 pattern = regex_extract (args, &args, &flags);
322 if (pattern == NULL)
323 {
324 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "RWATCH SET");
325 command_fail (si, fault::badparams, _("Syntax: RWATCH SET /<regex>/[i] [KLINE] [NOKLINE] [SNOOP] [NOSNOOP]"));
326 return;
327 }
328 while (*args == ' ')
329 args++;
330
331 if (*args == '\0')
332 {
333 command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "RWATCH SET");
334 command_fail (si, fault::needmoreparams, _("Syntax: RWATCH SET /<regex>/[i] [KLINE] [NOKLINE] [SNOOP] [NOSNOOP]"));
335 return;
336 }
337
338 opts = args;
339 while (*args != '\0')
340 {
341 if (!strncasecmp (args, "KLINE", 5))
342 addflags |= RWACT_KLINE, removeflags &= ~RWACT_KLINE, args += 5;
343 else if (!strncasecmp (args, "NOKLINE", 7))
344 removeflags |= RWACT_KLINE, addflags &= ~RWACT_KLINE, args += 7;
345 else if (!strncasecmp (args, "SNOOP", 5))
346 addflags |= RWACT_SNOOP, removeflags &= ~RWACT_SNOOP, args += 5;
347 else if (!strncasecmp (args, "NOSNOOP", 7))
348 removeflags |= RWACT_SNOOP, addflags &= ~RWACT_SNOOP, args += 7;
349
350 if (*args != '\0' && *args != ' ')
351 {
352 command_fail (si, fault::badparams, STR_INVALID_PARAMS, "RWATCH SET");
353 command_fail (si, fault::badparams, _("Syntax: RWATCH SET /<regex>/[i] [KLINE] [NOKLINE] [SNOOP] [NOSNOOP]"));
354 return;
355 }
356 while (*args == ' ')
357 args++;
358 }
359
360 if ((addflags | removeflags) & RWACT_KLINE && !has_priv (si, PRIV_MASS_AKILL))
361 {
362 command_fail (si, fault::noprivs, _("You do not have %s privilege."), PRIV_MASS_AKILL);
363 return;
364 }
365
366 LIST_FOREACH_SAFE (n, tn, rwatch_list.head)
367 {
368 rwatch_t *rw = static_cast < rwatch_t * >(n->data);
369
370 if (!strcmp (rw->regex, pattern))
371 {
372 if (((~rw->actions & addflags) | (rw->actions & removeflags)) == 0)
373 {
374 command_fail (si, fault::nochange, _("Options for \2%s\2 unchanged."), pattern);
375 return;
376 }
377 rw->actions |= addflags;
378 rw->actions &= ~removeflags;
379 command_success_nodata (si, _("Set options \2%s\2 on \2%s\2."), opts, pattern);
380 snoop ("RWATCH:SET: \2%s\2 \2%s\2 by \2%s\2", pattern, opts, get_oper_name (si));
381 if (addflags & RWACT_KLINE)
382 wallops ("\2%s\2 enabled kline on regex watch pattern \2%s\2", get_oper_name (si), pattern);
383 if (removeflags & RWACT_KLINE)
384 wallops ("\2%s\2 disabled kline on regex watch pattern \2%s\2", get_oper_name (si), pattern);
385 logcommand (si, CMDLOG_ADMIN, "RWATCH SET %s %s", pattern, opts);
386 write_rwatchdb ();
387 return;
388 }
389 }
390
391 command_fail (si, fault::nosuch_target, _("\2%s\2 not found in regex watch list."), pattern);
392 }
393
394 static void
395 rwatch_newuser (user_t *u)
396 {
397 char usermask[NICKLEN + USERLEN + HOSTLEN + GECOSLEN];
398 node_t *n;
399 rwatch_t *rw;
400
401 if (is_internal_client (u))
402 return;
403
404 snprintf (usermask, sizeof usermask, "%s!%s@%s %s", u->nick, u->user, u->host, u->gecos);
405
406 LIST_FOREACH (n, rwatch_list.head)
407 {
408 rw = static_cast < rwatch_t * >(n->data);
409 if (!rw->re)
410 continue;
411 if (regex_match (rw->re, usermask))
412 {
413 if (rw->actions & RWACT_SNOOP)
414 {
415 snoop ("RWATCH:%s %s matches \2%s\2 (%s)", rw->actions & RWACT_KLINE ? "KLINE:" : "", usermask, rw->regex, rw->reason);
416 }
417 if (rw->actions & RWACT_KLINE)
418 {
419 slog (LG_INFO, "rwatch_newuser(): klining *@%s (user %s!%s@%s matches %s %s)", u->host, u->nick, u->user, u->host, rw->regex, rw->reason);
420 phandler->kline_sts ("*", "*", u->host, 86400, rw->reason);
421 }
422 }
423 }
424 }
425
426 bool
427 _modinit (module *m)
428 {
429 os_cmdtree << os_rwatch;
430
431 os_rwatch_cmds << os_rwatch_add;
432 os_rwatch_cmds << os_rwatch_del;
433 os_rwatch_cmds << os_rwatch_list;
434 os_rwatch_cmds << os_rwatch_set;
435
436 help_addentry (os_helptree, "RWATCH", "help/operserv/rwatch", NULL);
437
438 user_t::callback.add.attach (rwatch_newuser);
439
440 load_rwatchdb ();
441
442 return true;
443 }
444
445 void
446 _moddeinit (void)
447 {
448 node_t *n, *tn;
449
450 LIST_FOREACH_SAFE (n, tn, rwatch_list.head)
451 {
452 rwatch_t *rw = static_cast < rwatch_t * >(n->data);
453
454 sfree (rw->regex);
455 sfree (rw->reason);
456 if (rw->re != NULL)
457 regex_destroy (rw->re);
458 delete rw;
459
460 node_del (n, &rwatch_list);
461 node_free (n);
462 }
463
464 os_cmdtree >> os_rwatch;
465
466 os_rwatch_cmds >> os_rwatch_add;
467 os_rwatch_cmds >> os_rwatch_del;
468 os_rwatch_cmds >> os_rwatch_list;
469 os_rwatch_cmds >> os_rwatch_set;
470
471 help_delentry (os_helptree, "RWATCH");
472
473 user_t::callback.add.detach (rwatch_newuser);
474 }