]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_management.c
Implement the trust log.
[irc/quakenet/newserv.git] / trusts / trusts_management.c
CommitLineData
35449aa5
CP
1#include <stdio.h>
2#include <string.h>
3#include "../control/control.h"
4#include "../lib/irc_string.h"
5#include "../lib/strlfunc.h"
82a316e7 6#include "../core/config.h"
2ab0a1e7 7#include "../lib/stringbuf.h"
35449aa5
CP
8#include "trusts.h"
9
10static void registercommands(int, void *);
11static void deregistercommands(int, void *);
12
2ab0a1e7
CP
13typedef int (*trustmodificationfn)(trustgroup *, char *arg);
14
15struct trustmodification {
1d9ccd69 16 char name[50];
2ab0a1e7
CP
17 trustmodificationfn fn;
18};
19
35449aa5
CP
20static int trusts_cmdtrustadd(void *source, int cargc, char **cargv) {
21 trustgroup *tg;
22 nick *sender = source;
23 char *host;
24 uint32_t ip, mask;
25 trusthost *th, *superset, *subset;
26
27 if(cargc < 2)
28 return CMD_USAGE;
29
30 tg = tg_strtotg(cargv[0]);
31 if(!tg) {
32 controlreply(sender, "Couldn't look up trustgroup.");
33 return CMD_ERROR;
34 }
35
36 host = cargv[1];
37 if(!trusts_str2cidr(host, &ip, &mask)) {
38 controlreply(sender, "Invalid host.");
39 return CMD_ERROR;
40 }
41
42 /* OKAY! Lots of checking here!
43 *
44 * Need to check:
45 * - host isn't already covered by given group (reject if it is)
46 * - host doesn't already exist exactly already (reject if it does)
47 * - host is more specific than an existing one (warn if it is, fix up later)
48 * - host is less specific than an existing one (warn if it is, don't need to do anything special)
49 */
50
51 for(th=tg->hosts;th;th=th->next) {
52 if(th->ip == (ip & th->mask)) {
53 controlreply(sender, "This host (or part of it) is already covered in the given group.");
54 return CMD_ERROR;
55 }
56 }
57
58 if(th_getbyhostandmask(ip, mask)) {
59 controlreply(sender, "This host already exists in another group with the same mask.");
60 return CMD_ERROR;
61 }
62
63 /* this function will set both to NULL if it's equal, hence the check above */
64 th_getsuperandsubsets(ip, mask, &superset, &subset);
65 if(superset) {
66 /* a superset exists for us, we will be more specific than one existing host */
67
68 controlreply(sender, "Warning: this host already exists in another group, but this new host will override it as it has a smaller prefix.");
69 }
70 if(subset) {
71 /* a subset of us exists, we will be less specific than some existing hosts */
72
73 controlreply(sender, "Warning: this host already exists in at least one other group, the new host has a larger prefix and therefore will not override those hosts.");
74 }
75 if(superset || subset)
76 controlreply(sender, "Adding anyway...");
77
78 th = th_new(tg, host);
79 if(!th) {
80 controlreply(sender, "An error occured adding the host to the group.");
81 return CMD_ERROR;
82 }
83
84 controlreply(sender, "Host added.");
82a316e7
CP
85 triggerhook(HOOK_TRUSTS_ADDHOST, th);
86
7e11a2c6 87 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTADD'ed host %s to group '%s'", controlid(sender), host, th->group->name->content);
01bd21d3 88 trustlog(tg->id, controlid(sender), "Added host '%s'.", host);
35449aa5
CP
89
90 return CMD_OK;
91}
92
93static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
94 nick *sender = source;
95 char *name, *contact, *comment, createdby[ACCOUNTLEN + 2];
96 unsigned int howmany, maxperident, enforceident;
97 time_t howlong;
82a316e7 98 trustgroup *tg, itg;
35449aa5
CP
99
100 if(cargc < 6)
101 return CMD_USAGE;
102
103 name = cargv[0];
104 howmany = strtoul(cargv[1], NULL, 10);
2ab0a1e7 105 if(!howmany || (howmany > MAXTRUSTEDFOR)) {
35449aa5
CP
106 controlreply(sender, "Bad value maximum number of clients.");
107 return CMD_ERROR;
108 }
109
110 howlong = durationtolong(cargv[2]);
2ab0a1e7 111 if((howlong <= 0) || (howlong > MAXDURATION)) {
35449aa5
CP
112 controlreply(sender, "Invalid duration supplied.");
113 return CMD_ERROR;
114 }
115
116 maxperident = strtoul(cargv[3], NULL, 10);
2ab0a1e7 117 if(!howmany || (maxperident > MAXPERIDENT)) {
35449aa5
CP
118 controlreply(sender, "Bad value for max per ident.");
119 return CMD_ERROR;
120 }
121
122 if(cargv[4][0] != '1' && cargv[4][0] != '0') {
123 controlreply(sender, "Bad value for enforce ident (use 0 or 1).");
124 return CMD_ERROR;
125 }
126 enforceident = cargv[4][0] == '1';
127
128 contact = cargv[5];
129
130 if(cargc < 7) {
131 comment = "(no comment)";
132 } else {
133 comment = cargv[6];
134 }
135
136 /* don't allow #id or id forms */
137 if((name[0] == '#') || strtoul(name, NULL, 10)) {
138 controlreply(sender, "Invalid trustgroup name.");
139 return CMD_ERROR;
140 }
141
142 tg = tg_strtotg(name);
143 if(tg) {
144 controlreply(sender, "A group with that name already exists");
145 return CMD_ERROR;
146 }
147
148 snprintf(createdby, sizeof(createdby), "#%s", sender->authname);
149
82a316e7
CP
150 itg.trustedfor = howmany;
151 itg.mode = enforceident;
152 itg.maxperident = maxperident;
153 itg.expires = howlong + time(NULL);
1f685425 154 itg.createdby = getsstring(createdby, CREATEDBYLEN);
82a316e7
CP
155 itg.contact = getsstring(contact, CONTACTLEN);
156 itg.comment = getsstring(comment, COMMENTLEN);
157 itg.name = getsstring(name, TRUSTNAMELEN);
158
159 if(itg.createdby && itg.contact && itg.comment && itg.name) {
160 tg = tg_new(&itg);
161 } else {
162 tg = NULL;
163 }
164
165 freesstring(itg.createdby);
166 freesstring(itg.comment);
167 freesstring(itg.name);
168 freesstring(itg.contact);
169
35449aa5
CP
170 if(!tg) {
171 controlreply(sender, "An error occured adding the trustgroup.");
172 return CMD_ERROR;
173 }
174
175 controlreply(sender, "Group added.");
82a316e7
CP
176 triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
177
7e11a2c6 178 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
01bd21d3
GB
179 trustlog(tg->id, controlid(sender), "Created trust group '%s' (ID #%d): howmany=%d, enforceident=%d, maxperident=%d, "
180 "expires=%d, createdby=%s, contact=%s, comment=%s",
181 tg->name->content, howmany, tg->id, enforceident, maxperident, howlong + time(NULL), createdby, contact, comment);
35449aa5
CP
182
183 return CMD_OK;
184}
185
2ab0a1e7
CP
186static int trusts_cmdtrustgroupdel(void *source, int cargc, char **cargv) {
187 trustgroup *tg;
188 nick *sender = source;
189
190 if(cargc < 1)
191 return CMD_USAGE;
192
193 tg = tg_strtotg(cargv[0]);
194 if(!tg) {
195 controlreply(sender, "Couldn't look up trustgroup.");
196 return CMD_ERROR;
197 }
198
199 if(tg->hosts) {
200 controlreply(sender, "Delete all hosts before deleting the group.");
201 return CMD_ERROR;
202 }
203
7e11a2c6 204 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPDEL'ed '%s'.", controlid(sender), tg->name->content);
01bd21d3 205 trustlog(tg->id, controlid(sender), "Deleted group '%s'.", tg->name->content);
7e11a2c6 206
2ab0a1e7
CP
207 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
208 tg_delete(tg);
209 controlreply(sender, "Group deleted.");
210
2ab0a1e7
CP
211 return CMD_OK;
212}
213
214static int trusts_cmdtrustdel(void *source, int cargc, char **cargv) {
215 trustgroup *tg;
216 trusthost *th;
217 uint32_t ip, mask;
218 nick *sender = source;
7e11a2c6 219 char *host;
2ab0a1e7
CP
220
221 if(cargc < 2)
222 return CMD_USAGE;
223
224 tg = tg_strtotg(cargv[0]);
225 if(!tg) {
226 controlreply(sender, "Couldn't look up trustgroup.");
227 return CMD_ERROR;
228 }
229
7e11a2c6
CP
230 host = cargv[1];
231 if(!trusts_str2cidr(host, &ip, &mask)) {
2ab0a1e7
CP
232 controlreply(sender, "Invalid IP/mask.");
233 return CMD_ERROR;
234 }
235
236 for(th=tg->hosts;th;th=th->next)
237 if((th->ip == ip) && (th->mask == mask))
238 break;
239
240 if(!th) {
241 controlreply(sender, "Couldn't find that host in that group.");
242 return CMD_ERROR;
243 }
244
245 triggerhook(HOOK_TRUSTS_DELHOST, th);
246 th_delete(th);
247 controlreply(sender, "Host deleted.");
248
7e11a2c6 249 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTDEL'ed %s from group '%s'.", controlid(sender), host, tg->name->content);
01bd21d3 250 trustlog(tg->id, controlid(sender), "Removed host '%s'.", host);
2ab0a1e7 251
7e11a2c6 252 return CMD_OK;
2ab0a1e7
CP
253}
254
255static int modifycomment(trustgroup *tg, char *comment) {
256 sstring *n = getsstring(comment, COMMENTLEN);
257 if(!n)
258 return 0;
259
260 freesstring(tg->comment);
261 tg->comment = n;
262
263 return 1;
264}
265
266static int modifycontact(trustgroup *tg, char *contact) {
267 sstring *n = getsstring(contact, CONTACTLEN);
268 if(!n)
269 return 0;
270
271 freesstring(tg->contact);
272 tg->contact = n;
273
274 return 1;
275}
276
277static int modifytrustedfor(trustgroup *tg, char *num) {
278 unsigned int trustedfor = strtoul(num, NULL, 10);
279
280 if(trustedfor > MAXTRUSTEDFOR)
281 return 0;
282
283 tg->trustedfor = trustedfor;
284
285 return 1;
286}
287
1f685425
CP
288static int modifymaxperident(trustgroup *tg, char *num) {
289 unsigned int maxperident = strtoul(num, NULL, 10);
2ab0a1e7 290
1f685425 291 if(maxperident > MAXPERIDENT)
2ab0a1e7
CP
292 return 0;
293
1f685425 294 tg->maxperident = maxperident;
2ab0a1e7
CP
295
296 return 1;
297}
298
299static int modifyenforceident(trustgroup *tg, char *num) {
300 if(num[0] == '1') {
301 tg->mode = 1;
302 } else if(num[0] == '0') {
303 tg->mode = 0;
304 } else {
305 return 0;
306 }
307
308 return 1;
309}
310
311static int modifyexpires(trustgroup *tg, char *expires) {
312 int howlong = durationtolong(expires);
313
314 if((howlong <= 0) || (howlong > MAXDURATION))
315 return 0;
316
317 tg->expires = time(NULL) + howlong;
318
319 return 1;
320}
321
1d9ccd69
CP
322static array trustmods_a;
323static struct trustmodification *trustmods;
2ab0a1e7
CP
324
325static int trusts_cmdtrustgroupmodify(void *source, int cargc, char **cargv) {
326 trustgroup *tg;
327 nick *sender = source;
328 char *what, *to, validfields[512];
2ab0a1e7
CP
329 int i;
330 StringBuf b;
2ab0a1e7
CP
331
332 if(cargc < 3)
333 return CMD_USAGE;
334
335 tg = tg_strtotg(cargv[0]);
336 if(!tg) {
337 controlreply(sender, "Couldn't look up trustgroup.");
338 return CMD_ERROR;
339 }
340
341 what = cargv[1];
342 to = cargv[2];
343
344 sbinit(&b, validfields, sizeof(validfields));
1d9ccd69
CP
345 for(i=0;i<trustmods_a.cursi;i++) {
346 if(!strcmp(what, trustmods[i].name)) {
347 if(!(trustmods[i].fn)(tg, to)) {
2ab0a1e7
CP
348 controlreply(sender, "An error occured changing that property, check the syntax.");
349 return CMD_ERROR;
350 }
351 break;
352 }
353
354 if(i > 0)
355 sbaddstr(&b, ", ");
1d9ccd69 356 sbaddstr(&b, trustmods[i].name);
2ab0a1e7
CP
357 }
358
1d9ccd69 359 if(i == trustmods_a.cursi) {
2ab0a1e7
CP
360 sbterminate(&b);
361 controlreply(sender, "No such field, valid fields are: %s", validfields);
362 return CMD_ERROR;
363 }
364
365 triggerhook(HOOK_TRUSTS_MODIFYGROUP, tg);
366 tg_update(tg);
367 controlreply(sender, "Group modified.");
368
7e11a2c6 369 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed group '%s' (field: %s, value: %s)", controlid(sender), tg->name->content, what, to);
01bd21d3 370 trustlog(tg->id, controlid(sender), "Modified %s: %s", what, to);
7e11a2c6 371
2ab0a1e7
CP
372 return CMD_OK;
373}
374
01bd21d3
GB
375static int trusts_cmdtrustlogspew(void *source, int cargc, char **cargv) {
376 nick *sender = source;
377 trustgroup *tg = NULL;
378 char *name;
379 int groupid;
380 int limit = 0;
381
382 if(cargc < 1)
383 return CMD_USAGE;
384
385 name = cargv[0];
386
387 tg = tg_strtotg(name);
388
389 if(tg)
390 groupid = tg->id;
391 else if (name[0] == '#')
392 groupid = strtoul(name + 1, NULL, 10);
393 else {
394 controlreply(sender, "Invalid trust group name or ID.");
395 return CMD_OK;
396 }
397
398 if(cargc>1)
399 limit = strtoul(cargv[1], NULL, 10);
400
401 if(limit==0)
402 limit = 100;
403
404 trustlogspew(sender, groupid, limit);
405
406 return CMD_OK;
407}
408
409static int trusts_cmdtrustloggrep(void *source, int cargc, char **cargv) {
410 nick *sender = source;
411 char *pattern;
412 int limit = 0;
413
414 if(cargc < 1)
415 return CMD_USAGE;
416
417 pattern = cargv[0];
418
419 if(cargc>1)
420 limit = strtoul(cargv[1], NULL, 10);
421
422 if(limit==0)
423 limit = 100;
424
425 trustloggrep(sender, pattern, limit);
426
427 return CMD_OK;
428}
429
430static int trusts_cmdtrustcomment(void *source, int cargc, char **cargv) {
431 nick *sender = source;
432 trustgroup *tg = NULL;
433 char *name, *comment;
434
435 if(cargc < 2)
436 return CMD_USAGE;
437
438 name = cargv[0];
439 comment = cargv[1];
440
441 tg = tg_strtotg(name);
442
443 if(!tg) {
444 controlreply(sender, "Invalid trust group name or ID.");
445 return CMD_OK;
446 }
447
448 trustlog(tg->id, controlid(sender), "Comment: %s", comment);
449
450 return CMD_OK;
451}
452
453
35449aa5
CP
454static int commandsregistered;
455
456static void registercommands(int hooknum, void *arg) {
457 if(commandsregistered)
458 return;
459 commandsregistered = 1;
460
56f4ec56 461 registercontrolhelpcmd("trustgroupadd", NO_OPER, 7, trusts_cmdtrustgroupadd, "Usage: trustgroupadd <name> <howmany> <howlong> <maxperident> <enforceident> <contact> ?comment?");
35449aa5 462 registercontrolhelpcmd("trustadd", NO_OPER, 2, trusts_cmdtrustadd, "Usage: trustadd <#id|name|id> <host>");
2ab0a1e7
CP
463 registercontrolhelpcmd("trustgroupdel", NO_OPER, 1, trusts_cmdtrustgroupdel, "Usage: trustgroupdel <#id|name|id>");
464 registercontrolhelpcmd("trustdel", NO_OPER, 2, trusts_cmdtrustdel, "Usage: trustdel <#id|name|id> <ip/mask>");
465 registercontrolhelpcmd("trustgroupmodify", NO_OPER, 3, trusts_cmdtrustgroupmodify, "Usage: trustgroupmodify <#id|name|id> <field> <new value>");
01bd21d3
GB
466 registercontrolhelpcmd("trustlogspew", NO_OPER, 2, trusts_cmdtrustlogspew, "Usage: trustlogspew <#id|name> [limit]\nShows log for the specified trust group.");
467 registercontrolhelpcmd("trustloggrep", NO_OPER, 2, trusts_cmdtrustloggrep, "Usage trustloggrep <pattern> [limit]\nShows maching log entries.");
468 registercontrolhelpcmd("trustcomment", NO_OPER, 2, trusts_cmdtrustcomment, "Usage: trustcomment <#id|name> <comment>\nLogs a comment for a trust.");
35449aa5
CP
469}
470
471static void deregistercommands(int hooknum, void *arg) {
472 if(!commandsregistered)
473 return;
474 commandsregistered = 0;
475
476 deregistercontrolcmd("trustgroupadd", trusts_cmdtrustgroupadd);
477 deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
2ab0a1e7
CP
478 deregistercontrolcmd("trustgroupdel", trusts_cmdtrustgroupdel);
479 deregistercontrolcmd("trustdel", trusts_cmdtrustdel);
480 deregistercontrolcmd("trustgroupmodify", trusts_cmdtrustgroupmodify);
01bd21d3
GB
481 deregistercontrolcmd("trustlogspew", trusts_cmdtrustlogspew);
482 deregistercontrolcmd("trustloggrep", trusts_cmdtrustloggrep);
483 deregistercontrolcmd("trustcomment", trusts_cmdtrustcomment);
35449aa5
CP
484}
485
82a316e7
CP
486static int loaded;
487
1d9ccd69
CP
488#define _ms_(x) (struct trustmodification){ .name = # x, .fn = modify ## x }
489#define MS(x) { int slot = array_getfreeslot(&trustmods_a); trustmods = (struct trustmodification *)trustmods_a.content; memcpy(&trustmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
490
491static void setupmods(void) {
492 MS(expires);
493 MS(enforceident);
494 MS(maxperident);
495 MS(contact);
496 MS(comment);
497 MS(trustedfor);
498}
499
35449aa5 500void _init(void) {
82a316e7
CP
501 sstring *m;
502
1d9ccd69
CP
503 array_init(&trustmods_a, sizeof(struct trustmodification));
504 setupmods();
505
82a316e7
CP
506 m = getconfigitem("trusts", "master");
507 if(!m || (atoi(m->content) != 1)) {
508 Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
509 return;
510 }
511
512 loaded = 1;
513
35449aa5
CP
514 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
515 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
516
517 if(trustsdbloaded)
518 registercommands(0, NULL);
519}
520
521void _fini(void) {
1d9ccd69
CP
522 array_free(&trustmods_a);
523
82a316e7
CP
524 if(!loaded)
525 return;
526
35449aa5
CP
527 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
528 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
529
530 deregistercommands(0, NULL);
531}