1 /*
2 * Copyright (c) 2005-2006 William Pitcock, et al.
3 * Rights to this code are as documented in doc/LICENSE.
4 *
5 * OperServ NOOP command.
6 *
7 */
8
9 #include "atheme.h"
10
11 DECLARE_MODULE_V1
12 (
13 "operserv/noop", true, _modinit, _moddeinit,
14 PACKAGE_STRING,
15 VENDOR_STRING
16 );
17
18 typedef struct noop_ noop_t;
19
20 struct noop_ {
21 char *target;
22 char *added_by;
23 char *reason;
24 };
25
26 mowgli_list_t noop_hostmask_list;
27 mowgli_list_t noop_server_list;
28
29 static void os_cmd_noop(sourceinfo_t *si, int parc, char *parv[]);
30 static void noop_kill_users(void *dummy);
31 static void check_quit(user_t *u);
32 static void check_user(user_t *u);
33 static mowgli_list_t noop_kill_queue;
34 static mowgli_eventloop_timer_t *noop_kill_users_timer = NULL;
35
36 command_t os_noop = { "NOOP", N_("Restricts IRCop access."), PRIV_NOOP, 4, os_cmd_noop, { .path = "oservice/noop" } };
37
_modinit(module_t * m)38 void _modinit(module_t *m)
39 {
40 service_named_bind_command("operserv", &os_noop);
41 hook_add_event("user_oper");
42 hook_add_user_oper(check_user);
43 hook_add_event("user_delete");
44 }
45
_moddeinit(module_unload_intent_t intent)46 void _moddeinit(module_unload_intent_t intent)
47 {
48 mowgli_node_t *n, *tn;
49
50 if (MOWGLI_LIST_LENGTH(&noop_kill_queue) > 0)
51 {
52 /* Cannot safely delete users from here, so just forget
53 * about them.
54 */
55 mowgli_timer_destroy(base_eventloop, noop_kill_users_timer);
56 MOWGLI_ITER_FOREACH_SAFE(n, tn, noop_kill_queue.head)
57 {
58 mowgli_node_delete(n, &noop_kill_queue);
59 mowgli_node_free(n);
60 }
61 hook_del_user_delete(check_quit);
62 }
63 service_named_unbind_command("operserv", &os_noop);
64 hook_del_user_oper(check_user);
65 }
66
noop_kill_users(void * dummy)67 static void noop_kill_users(void *dummy)
68 {
69 service_t *service;
70 mowgli_node_t *n, *tn;
71 user_t *u;
72
73 hook_del_user_delete(check_quit);
74
75 service = service_find("operserv");
76 MOWGLI_ITER_FOREACH_SAFE(n, tn, noop_kill_queue.head)
77 {
78 u = n->data;
79 kill_user(service->me, u, "Operator access denied");
80 mowgli_node_delete(n, &noop_kill_queue);
81 mowgli_node_free(n);
82 }
83 }
84
check_quit(user_t * u)85 static void check_quit(user_t *u)
86 {
87 mowgli_node_t *n;
88
89 n = mowgli_node_find(u, &noop_kill_queue);
90 if (n != NULL)
91 {
92 mowgli_node_delete(n, &noop_kill_queue);
93 mowgli_node_free(n);
94 if (MOWGLI_LIST_LENGTH(&noop_kill_queue) == 0)
95 {
96 mowgli_timer_destroy(base_eventloop, noop_kill_users_timer);
97 hook_del_user_delete(check_quit);
98 }
99 }
100 }
101
check_user(user_t * u)102 static void check_user(user_t *u)
103 {
104 mowgli_node_t *n;
105 char hostbuf[BUFSIZE];
106
107 if (mowgli_node_find(u, &noop_kill_queue))
108 return;
109
110 snprintf(hostbuf, BUFSIZE, "%s!%s@%s", u->nick, u->user, u->host);
111
112 MOWGLI_ITER_FOREACH(n, noop_hostmask_list.head)
113 {
114 noop_t *np = n->data;
115
116 if (!match(np->target, hostbuf))
117 {
118 if (MOWGLI_LIST_LENGTH(&noop_kill_queue) == 0)
119 {
120 noop_kill_users_timer = mowgli_timer_add_once(base_eventloop, "noop_kill_users", noop_kill_users, NULL, 0);
121 hook_add_user_delete(check_quit);
122 }
123 if (!mowgli_node_find(u, &noop_kill_queue))
124 mowgli_node_add(u, mowgli_node_create(), &noop_kill_queue);
125 /* Prevent them using the privs in Atheme. */
126 u->flags &= ~UF_IRCOP;
127 return;
128 }
129 }
130
131 MOWGLI_ITER_FOREACH(n, noop_server_list.head)
132 {
133 noop_t *np = n->data;
134
135 if (!match(np->target, u->server->name))
136 {
137 if (MOWGLI_LIST_LENGTH(&noop_kill_queue) == 0)
138 {
139 noop_kill_users_timer = mowgli_timer_add_once(base_eventloop, "noop_kill_users", noop_kill_users, NULL, 0);
140 hook_add_user_delete(check_quit);
141 }
142 if (!mowgli_node_find(u, &noop_kill_queue))
143 mowgli_node_add(u, mowgli_node_create(), &noop_kill_queue);
144 /* Prevent them using the privs in Atheme. */
145 u->flags &= ~UF_IRCOP;
146 return;
147 }
148 }
149 }
150
noop_find(char * target,mowgli_list_t * list)151 static noop_t *noop_find(char *target, mowgli_list_t *list)
152 {
153 mowgli_node_t *n;
154
155 MOWGLI_ITER_FOREACH(n, list->head)
156 {
157 noop_t *np = n->data;
158
159 if (!match(np->target, target))
160 return np;
161 }
162
163 return NULL;
164 }
165
166 /* NOOP <ADD|DEL|LIST> <HOSTMASK|SERVER> [reason] */
os_cmd_noop(sourceinfo_t * si,int parc,char * parv[])167 static void os_cmd_noop(sourceinfo_t *si, int parc, char *parv[])
168 {
169 mowgli_node_t *n;
170 noop_t *np;
171 char *action = parv[0];
172 enum { type_all, type_hostmask, type_server } type;
173 char *mask = parv[2];
174 char *reason = parv[3];
175
176 if (parc < 1 || (strcasecmp(action, "LIST") && parc < 3))
177 {
178 command_fail(si, fault_needmoreparams, STR_INSUFFICIENT_PARAMS, "NOOP");
179 command_fail(si, fault_needmoreparams, _("Syntax: NOOP <ADD|DEL|LIST> <HOSTMASK|SERVER> <mask> [reason]"));
180 return;
181 }
182 if (parc < 2)
183 type = type_all;
184 else if (!strcasecmp(parv[1], "HOSTMASK"))
185 type = type_hostmask;
186 else if (!strcasecmp(parv[1], "SERVER"))
187 type = type_server;
188 else
189 {
190 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "NOOP");
191 command_fail(si, fault_badparams, _("Syntax: NOOP <ADD|DEL|LIST> <HOSTMASK|SERVER> <mask> [reason]"));
192 return;
193 }
194
195 if (!strcasecmp(action, "ADD"))
196 {
197 if (type == type_hostmask)
198 {
199 if ((np = noop_find(mask, &noop_hostmask_list)))
200 {
201 command_fail(si, fault_nochange, _("There is already a NOOP entry covering this target."));
202 return;
203 }
204
205 np = smalloc(sizeof *np);
206
207 np->target = sstrdup(mask);
208 np->added_by = sstrdup(get_storage_oper_name(si));
209
210 if (reason)
211 np->reason = sstrdup(reason);
212 else
213 np->reason = sstrdup("Abusive operator.");
214
215 n = mowgli_node_create();
216 mowgli_node_add(np, n, &noop_hostmask_list);
217
218 logcommand(si, CMDLOG_ADMIN, "NOOP:ADD:HOSTMASK: \2%s\2 (reason: \2%s\2)", np->target, np->reason);
219 command_success_nodata(si, _("Added \2%s\2 to the hostmask NOOP list."), mask);
220
221 return;
222 }
223 else if (type == type_server)
224 {
225 if ((np = noop_find(mask, &noop_server_list)))
226 {
227 command_fail(si, fault_nochange, _("There is already a NOOP entry covering this target."));
228 return;
229 }
230
231 np = smalloc(sizeof *np);
232
233 np->target = sstrdup(mask);
234 np->added_by = sstrdup(get_storage_oper_name(si));
235
236 if (reason)
237 np->reason = sstrdup(reason);
238 else
239 np->reason = sstrdup("Abusive operator.");
240
241 n = mowgli_node_create();
242 mowgli_node_add(np, n, &noop_server_list);
243
244 logcommand(si, CMDLOG_ADMIN, "NOOP:ADD:SERVER: \2%s\2 (reason: \2%s\2)", np->target, np->reason);
245 command_success_nodata(si, _("Added \2%s\2 to the server NOOP list."), mask);
246
247 return;
248 }
249 }
250 else if (!strcasecmp(action, "DEL"))
251 {
252 if (type == type_hostmask)
253 {
254 if (!(np = noop_find(mask, &noop_hostmask_list)))
255 {
256 command_fail(si, fault_nosuch_target, _("There is no NOOP hostmask entry for this target."));
257 return;
258 }
259
260 logcommand(si, CMDLOG_ADMIN, "NOOP:DEL:HOSTMASK: \2%s\2", np->target);
261 command_success_nodata(si, _("Removed \2%s\2 from the hostmask NOOP list."), np->target);
262
263 n = mowgli_node_find(np, &noop_hostmask_list);
264
265 free(np->target);
266 free(np->added_by);
267 free(np->reason);
268
269 mowgli_node_delete(n, &noop_hostmask_list);
270 mowgli_node_free(n);
271 free(np);
272
273 return;
274 }
275 else if (type == type_server)
276 {
277 if (!(np = noop_find(mask, &noop_server_list)))
278 {
279 command_fail(si, fault_nosuch_target, _("There is no NOOP server entry for this target."));
280 return;
281 }
282
283 logcommand(si, CMDLOG_ADMIN, "NOOP:DEL:SERVER: \2%s\2", np->target);
284 command_success_nodata(si, _("Removed \2%s\2 from the server NOOP list."), np->target);
285
286 n = mowgli_node_find(np, &noop_server_list);
287
288 free(np->target);
289 free(np->added_by);
290 free(np->reason);
291
292 mowgli_node_delete(n, &noop_server_list);
293 mowgli_node_free(n);
294 free(np);
295
296 return;
297 }
298 }
299 else if (!strcasecmp(action, "LIST"))
300 {
301 switch (type)
302 {
303 case type_all:
304 logcommand(si, CMDLOG_GET, "NOOP:LIST");
305 break;
306 case type_hostmask:
307 logcommand(si, CMDLOG_GET, "NOOP:LIST:HOSTMASK");
308 break;
309 case type_server:
310 logcommand(si, CMDLOG_GET, "NOOP:LIST:SERVER");
311 break;
312 }
313 if (type == type_all || type == type_hostmask)
314 {
315 unsigned int i = 1;
316 command_success_nodata(si, _("Hostmask NOOP list (%zu entries):"), noop_hostmask_list.count);
317 command_success_nodata(si, " ");
318 command_success_nodata(si, _("Entry Hostmask Adder Reason"));
319 command_success_nodata(si, "----- ------------------------------- --------------------- --------------------------");
320
321 MOWGLI_ITER_FOREACH(n, noop_hostmask_list.head)
322 {
323 np = n->data;
324
325 command_success_nodata(si, "%-5d %-31s %-21s %s", i, np->target, np->added_by, np->reason);
326 i++;
327 }
328
329 command_success_nodata(si, "----- ------------------------------- --------------------- --------------------------");
330 command_success_nodata(si, _("End of Hostmask NOOP list."));
331 }
332 if (type == type_all || type == type_server)
333 {
334 unsigned int i = 1;
335 command_success_nodata(si, _("Server NOOP list (%zu entries):"), noop_server_list.count);
336 command_success_nodata(si, " ");
337 command_success_nodata(si, _("Entry Hostmask Adder Reason"));
338 command_success_nodata(si, "----- ------------------------------- --------------------- --------------------------");
339
340 MOWGLI_ITER_FOREACH(n, noop_server_list.head)
341 {
342 np = n->data;
343
344 command_success_nodata(si, "%-5d %-31s %-21s %s", i, np->target, np->added_by, np->reason);
345 i++;
346 }
347
348 command_success_nodata(si, "----- ------------------------------- --------------------- --------------------------");
349 command_success_nodata(si, _("End of Server NOOP list."));
350 }
351 }
352 else
353 {
354 command_fail(si, fault_badparams, STR_INVALID_PARAMS, "NOOP");
355 command_fail(si, fault_badparams, _("Syntax: NOOP <ADD|DEL|LIST> <HOSTMASK|SERVER> <mask> [reason]"));
356 }
357 }
358
359 /* vim:cinoptions=>s,e0,n0,f0,{0,}0,^0,=s,ps,t0,c3,+s,(2s,us,)20,*30,gs,hs
360 * vim:ts=8
361 * vim:sw=8
362 * vim:noexpandtab
363 */
364