]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_management.c
Allow developers to override some of the TG/TH limits.
[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"
caf2d02a 7#include "../core/schedule.h"
2ab0a1e7 8#include "../lib/stringbuf.h"
4a5ce902
GB
9#include "../noperserv/noperserv.h"
10#include "../noperserv/noperserv_policy.h"
35449aa5
CP
11#include "trusts.h"
12
13static void registercommands(int, void *);
14static void deregistercommands(int, void *);
15
4a5ce902 16typedef int (*trustmodificationfn)(void *, char *arg, int);
2ab0a1e7
CP
17
18struct trustmodification {
1d9ccd69 19 char name[50];
2ab0a1e7
CP
20 trustmodificationfn fn;
21};
22
35449aa5
CP
23static int trusts_cmdtrustadd(void *source, int cargc, char **cargv) {
24 trustgroup *tg;
25 nick *sender = source;
26 char *host;
6e6e98da
GB
27 struct irc_in_addr ip;
28 unsigned char bits;
35449aa5
CP
29 trusthost *th, *superset, *subset;
30
31 if(cargc < 2)
32 return CMD_USAGE;
33
34 tg = tg_strtotg(cargv[0]);
35 if(!tg) {
36 controlreply(sender, "Couldn't look up trustgroup.");
37 return CMD_ERROR;
38 }
39
40 host = cargv[1];
6e6e98da 41 if(!ipmask_parse(host, &ip, &bits)) {
35449aa5
CP
42 controlreply(sender, "Invalid host.");
43 return CMD_ERROR;
44 }
45
46 /* OKAY! Lots of checking here!
47 *
48 * Need to check:
49 * - host isn't already covered by given group (reject if it is)
50 * - host doesn't already exist exactly already (reject if it does)
51 * - host is more specific than an existing one (warn if it is, fix up later)
52 * - host is less specific than an existing one (warn if it is, don't need to do anything special)
53 */
54
55 for(th=tg->hosts;th;th=th->next) {
6e6e98da 56 if(ipmask_check(&ip, &th->ip, th->bits)) {
35449aa5
CP
57 controlreply(sender, "This host (or part of it) is already covered in the given group.");
58 return CMD_ERROR;
59 }
60 }
61
6e6e98da 62 if(th_getbyhostandmask(&ip, bits)) {
35449aa5
CP
63 controlreply(sender, "This host already exists in another group with the same mask.");
64 return CMD_ERROR;
65 }
66
67 /* this function will set both to NULL if it's equal, hence the check above */
6e6e98da 68 th_getsuperandsubsets(&ip, bits, &superset, &subset);
35449aa5
CP
69 if(superset) {
70 /* a superset exists for us, we will be more specific than one existing host */
71
72 controlreply(sender, "Warning: this host already exists in another group, but this new host will override it as it has a smaller prefix.");
73 }
74 if(subset) {
75 /* a subset of us exists, we will be less specific than some existing hosts */
76
77 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.");
78 }
79 if(superset || subset)
80 controlreply(sender, "Adding anyway...");
81
82 th = th_new(tg, host);
83 if(!th) {
84 controlreply(sender, "An error occured adding the host to the group.");
85 return CMD_ERROR;
86 }
87
88 controlreply(sender, "Host added.");
82a316e7
CP
89 triggerhook(HOOK_TRUSTS_ADDHOST, th);
90
7e11a2c6 91 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTADD'ed host %s to group '%s'", controlid(sender), host, th->group->name->content);
7db61652 92 trustlog(tg, sender->authname, "Added host '%s'.", host);
35449aa5
CP
93
94 return CMD_OK;
95}
96
97static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
98 nick *sender = source;
99 char *name, *contact, *comment, createdby[ACCOUNTLEN + 2];
100 unsigned int howmany, maxperident, enforceident;
1467e9a4 101 time_t howlong, expires;
82a316e7 102 trustgroup *tg, itg;
35449aa5
CP
103
104 if(cargc < 6)
105 return CMD_USAGE;
106
107 name = cargv[0];
108 howmany = strtoul(cargv[1], NULL, 10);
2ab0a1e7 109 if(!howmany || (howmany > MAXTRUSTEDFOR)) {
35449aa5
CP
110 controlreply(sender, "Bad value maximum number of clients.");
111 return CMD_ERROR;
112 }
113
114 howlong = durationtolong(cargv[2]);
ad3fd5ee 115 if((howlong < 0) || (howlong > MAXDURATION)) {
35449aa5
CP
116 controlreply(sender, "Invalid duration supplied.");
117 return CMD_ERROR;
118 }
119
1467e9a4
GB
120 if(howlong)
121 expires = howlong + time(NULL);
122 else
123 expires = 0;
124
35449aa5 125 maxperident = strtoul(cargv[3], NULL, 10);
2ab0a1e7 126 if(!howmany || (maxperident > MAXPERIDENT)) {
35449aa5
CP
127 controlreply(sender, "Bad value for max per ident.");
128 return CMD_ERROR;
129 }
130
131 if(cargv[4][0] != '1' && cargv[4][0] != '0') {
132 controlreply(sender, "Bad value for enforce ident (use 0 or 1).");
133 return CMD_ERROR;
134 }
135 enforceident = cargv[4][0] == '1';
136
137 contact = cargv[5];
138
139 if(cargc < 7) {
140 comment = "(no comment)";
141 } else {
142 comment = cargv[6];
143 }
144
145 /* don't allow #id or id forms */
146 if((name[0] == '#') || strtoul(name, NULL, 10)) {
147 controlreply(sender, "Invalid trustgroup name.");
148 return CMD_ERROR;
149 }
150
151 tg = tg_strtotg(name);
152 if(tg) {
153 controlreply(sender, "A group with that name already exists");
154 return CMD_ERROR;
155 }
156
157 snprintf(createdby, sizeof(createdby), "#%s", sender->authname);
158
82a316e7
CP
159 itg.trustedfor = howmany;
160 itg.mode = enforceident;
161 itg.maxperident = maxperident;
1467e9a4 162 itg.expires = expires;
1f685425 163 itg.createdby = getsstring(createdby, CREATEDBYLEN);
82a316e7
CP
164 itg.contact = getsstring(contact, CONTACTLEN);
165 itg.comment = getsstring(comment, COMMENTLEN);
166 itg.name = getsstring(name, TRUSTNAMELEN);
167
168 if(itg.createdby && itg.contact && itg.comment && itg.name) {
169 tg = tg_new(&itg);
170 } else {
171 tg = NULL;
172 }
173
174 freesstring(itg.createdby);
175 freesstring(itg.comment);
176 freesstring(itg.name);
177 freesstring(itg.contact);
178
35449aa5
CP
179 if(!tg) {
180 controlreply(sender, "An error occured adding the trustgroup.");
181 return CMD_ERROR;
182 }
183
184 controlreply(sender, "Group added.");
82a316e7
CP
185 triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
186
7e11a2c6 187 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
7db61652 188 trustlog(tg, sender->authname, "Created trust group '%s' (ID #%d): howmany=%d, enforceident=%d, maxperident=%d, "
01bd21d3 189 "expires=%d, createdby=%s, contact=%s, comment=%s",
1467e9a4 190 tg->name->content, howmany, tg->id, enforceident, maxperident, expires, createdby, contact, comment);
35449aa5
CP
191
192 return CMD_OK;
193}
194
2ab0a1e7
CP
195static int trusts_cmdtrustgroupdel(void *source, int cargc, char **cargv) {
196 trustgroup *tg;
197 nick *sender = source;
198
199 if(cargc < 1)
200 return CMD_USAGE;
201
202 tg = tg_strtotg(cargv[0]);
203 if(!tg) {
204 controlreply(sender, "Couldn't look up trustgroup.");
205 return CMD_ERROR;
206 }
207
208 if(tg->hosts) {
209 controlreply(sender, "Delete all hosts before deleting the group.");
210 return CMD_ERROR;
211 }
212
7e11a2c6 213 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPDEL'ed '%s'.", controlid(sender), tg->name->content);
7db61652 214 trustlog(tg, sender->authname, "Deleted group '%s'.", tg->name->content);
7e11a2c6 215
2ab0a1e7
CP
216 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
217 tg_delete(tg);
218 controlreply(sender, "Group deleted.");
219
2ab0a1e7
CP
220 return CMD_OK;
221}
222
223static int trusts_cmdtrustdel(void *source, int cargc, char **cargv) {
224 trustgroup *tg;
225 trusthost *th;
6e6e98da
GB
226 struct irc_in_addr ip;
227 unsigned char bits;
2ab0a1e7 228 nick *sender = source;
7e11a2c6 229 char *host;
2ab0a1e7
CP
230
231 if(cargc < 2)
232 return CMD_USAGE;
233
234 tg = tg_strtotg(cargv[0]);
235 if(!tg) {
236 controlreply(sender, "Couldn't look up trustgroup.");
237 return CMD_ERROR;
238 }
239
7e11a2c6 240 host = cargv[1];
6e6e98da 241 if(!ipmask_parse(host, &ip, &bits)) {
2ab0a1e7
CP
242 controlreply(sender, "Invalid IP/mask.");
243 return CMD_ERROR;
244 }
245
246 for(th=tg->hosts;th;th=th->next)
6e6e98da 247 if(ipmask_check(&ip, &th->ip, th->bits) && th->bits == bits)
2ab0a1e7
CP
248 break;
249
250 if(!th) {
251 controlreply(sender, "Couldn't find that host in that group.");
252 return CMD_ERROR;
253 }
254
255 triggerhook(HOOK_TRUSTS_DELHOST, th);
256 th_delete(th);
257 controlreply(sender, "Host deleted.");
258
7e11a2c6 259 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTDEL'ed %s from group '%s'.", controlid(sender), host, tg->name->content);
7db61652 260 trustlog(tg, sender->authname, "Removed host '%s'.", host);
2ab0a1e7 261
7e11a2c6 262 return CMD_OK;
2ab0a1e7
CP
263}
264
4a5ce902 265static int modifycomment(void *arg, char *comment, int override) {
c1da06f9 266 trustgroup *tg = arg;
2ab0a1e7
CP
267 sstring *n = getsstring(comment, COMMENTLEN);
268 if(!n)
269 return 0;
270
271 freesstring(tg->comment);
272 tg->comment = n;
273
274 return 1;
275}
276
4a5ce902 277static int modifycontact(void *arg, char *contact, int override) {
c1da06f9 278 trustgroup *tg = arg;
2ab0a1e7
CP
279 sstring *n = getsstring(contact, CONTACTLEN);
280 if(!n)
281 return 0;
282
283 freesstring(tg->contact);
284 tg->contact = n;
285
286 return 1;
287}
288
4a5ce902 289static int modifytrustedfor(void *arg, char *num, int override) {
c1da06f9 290 trustgroup *tg = arg;
2ab0a1e7
CP
291 unsigned int trustedfor = strtoul(num, NULL, 10);
292
4a5ce902 293 if(!override && (trustedfor <= 0 || trustedfor > MAXTRUSTEDFOR))
2ab0a1e7
CP
294 return 0;
295
296 tg->trustedfor = trustedfor;
297
298 return 1;
299}
300
4a5ce902 301static int modifymaxperident(void *arg, char *num, int override) {
c1da06f9 302 trustgroup *tg = arg;
1f685425 303 unsigned int maxperident = strtoul(num, NULL, 10);
2ab0a1e7 304
4a5ce902 305 if(!override && (maxperident <= 0 || maxperident > MAXPERIDENT))
2ab0a1e7
CP
306 return 0;
307
1f685425 308 tg->maxperident = maxperident;
2ab0a1e7
CP
309
310 return 1;
311}
312
4a5ce902 313static int modifyenforceident(void *arg, char *num, int override) {
c1da06f9
GB
314 trustgroup *tg = arg;
315
2ab0a1e7
CP
316 if(num[0] == '1') {
317 tg->mode = 1;
318 } else if(num[0] == '0') {
319 tg->mode = 0;
320 } else {
321 return 0;
322 }
323
324 return 1;
325}
326
4a5ce902 327static int modifyexpires(void *arg, char *expires, int override) {
c1da06f9 328 trustgroup *tg = arg;
2ab0a1e7
CP
329 int howlong = durationtolong(expires);
330
ad3fd5ee 331 if((howlong < 0) || (howlong > MAXDURATION))
2ab0a1e7
CP
332 return 0;
333
ad3fd5ee
GB
334 if(howlong)
335 tg->expires = time(NULL) + howlong;
336 else
337 tg->expires = 0; /* never */
2ab0a1e7
CP
338
339 return 1;
340}
341
4a5ce902 342static int modifymaxpernode(void *arg, char *num, int override) {
c1da06f9
GB
343 trusthost *th = arg;
344 int maxpernode = strtol(num, NULL, 10);
345
346 if((maxpernode < 0) || (maxpernode > MAXPERNODE))
347 return 0;
348
349 th->maxpernode = maxpernode;
350
351 return 1;
352}
353
4a5ce902 354static int modifynodebits(void *arg, char *num, int override) {
c1da06f9
GB
355 trusthost *th = arg;
356 int nodebits = strtol(num, NULL, 10);
357
39923206 358 if((nodebits < 0) || (nodebits > ((irc_in_addr_is_ipv4(&th->ip))?32:128)))
c1da06f9
GB
359 return 0;
360
39923206
GB
361 if(irc_in_addr_is_ipv4(&th->ip))
362 nodebits += 96;
363
80cf3d8e
GB
364 if(nodebits<th->bits)
365 return 0;
366
c1da06f9
GB
367 th->nodebits = nodebits;
368
369 return 1;
370}
371
372static array trustgroupmods_a;
373static struct trustmodification *trustgroupmods;
374static array trusthostmods_a;
375static struct trustmodification *trusthostmods;
2ab0a1e7
CP
376
377static int trusts_cmdtrustgroupmodify(void *source, int cargc, char **cargv) {
378 trustgroup *tg;
379 nick *sender = source;
380 char *what, *to, validfields[512];
4a5ce902 381 int i, override;
2ab0a1e7 382 StringBuf b;
2ab0a1e7
CP
383
384 if(cargc < 3)
385 return CMD_USAGE;
386
387 tg = tg_strtotg(cargv[0]);
388 if(!tg) {
389 controlreply(sender, "Couldn't look up trustgroup.");
390 return CMD_ERROR;
391 }
392
393 what = cargv[1];
394 to = cargv[2];
395
4a5ce902
GB
396 override = noperserv_policy_command_permitted(NO_DEVELOPER, sender);
397
2ab0a1e7 398 sbinit(&b, validfields, sizeof(validfields));
c1da06f9
GB
399 for(i=0;i<trustgroupmods_a.cursi;i++) {
400 if(!strcmp(what, trustgroupmods[i].name)) {
4a5ce902 401 if(!(trustgroupmods[i].fn)(tg, to, override)) {
2ab0a1e7
CP
402 controlreply(sender, "An error occured changing that property, check the syntax.");
403 return CMD_ERROR;
404 }
405 break;
406 }
407
408 if(i > 0)
409 sbaddstr(&b, ", ");
c1da06f9 410 sbaddstr(&b, trustgroupmods[i].name);
2ab0a1e7
CP
411 }
412
c1da06f9 413 if(i == trustgroupmods_a.cursi) {
2ab0a1e7
CP
414 sbterminate(&b);
415 controlreply(sender, "No such field, valid fields are: %s", validfields);
416 return CMD_ERROR;
417 }
418
419 triggerhook(HOOK_TRUSTS_MODIFYGROUP, tg);
420 tg_update(tg);
421 controlreply(sender, "Group modified.");
422
7e11a2c6 423 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed group '%s' (field: %s, value: %s)", controlid(sender), tg->name->content, what, to);
7db61652 424 trustlog(tg, sender->authname, "Modified %s: %s", what, to);
7e11a2c6 425
2ab0a1e7
CP
426 return CMD_OK;
427}
428
c1da06f9
GB
429static int trusts_cmdtrusthostmodify(void *source, int cargc, char **cargv) {
430 trustgroup *tg;
431 trusthost *th;
432 nick *sender = source;
433 char *what, *to, validfields[512];
4a5ce902 434 int i, override;
c1da06f9
GB
435 StringBuf b;
436 struct irc_in_addr ip;
437 unsigned char bits;
438
439 if(cargc < 4)
440 return CMD_USAGE;
441
442 tg = tg_strtotg(cargv[0]);
443 if(!tg) {
444 controlreply(sender, "Couldn't look up trustgroup.");
445 return CMD_ERROR;
446 }
447
448 if(!ipmask_parse(cargv[1], &ip, &bits)) {
449 controlreply(sender, "Invalid host.");
450 return CMD_ERROR;
451 }
452
453 th = th_getbyhostandmask(&ip, bits);
454
455 if(th->group != tg) {
456 controlreply(sender, "Host does not belong to the specified group.");
457 return CMD_ERROR;
458 }
459
460 what = cargv[2];
461 to = cargv[3];
462
4a5ce902
GB
463 override = noperserv_policy_command_permitted(NO_DEVELOPER, sender);
464
c1da06f9
GB
465 sbinit(&b, validfields, sizeof(validfields));
466 for(i=0;i<trusthostmods_a.cursi;i++) {
467 if(!strcmp(what, trusthostmods[i].name)) {
4a5ce902 468 if(!(trusthostmods[i].fn)(th, to, override)) {
c1da06f9
GB
469 controlreply(sender, "An error occured changing that property, check the syntax.");
470 return CMD_ERROR;
471 }
472 break;
473 }
474
475 if(i > 0)
476 sbaddstr(&b, ", ");
477 sbaddstr(&b, trusthostmods[i].name);
478 }
479
480 if(i == trusthostmods_a.cursi) {
481 sbterminate(&b);
482 controlreply(sender, "No such field, valid fields are: %s", validfields);
483 return CMD_ERROR;
484 }
485
486 triggerhook(HOOK_TRUSTS_MODIFYHOST, th);
487 th_update(th);
488 controlreply(sender, "Host modified.");
489
490 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed host '%s' in group '%s' (field: %s, value: %s)", controlid(sender), trusts_cidr2str(&ip, bits), tg->name->content, what, to);
8b42365b 491 trustlog(tg, sender->authname, "Modified %s for host '%s': %s", what, tg->name->content, to);
c1da06f9
GB
492
493 return CMD_OK;
494}
495
e5c0bccf 496static int trusts_cmdtrustlog(void *source, int cargc, char **cargv) {
01bd21d3 497 nick *sender = source;
01bd21d3
GB
498 char *name;
499 int groupid;
500 int limit = 0;
501
502 if(cargc < 1)
503 return CMD_USAGE;
504
01bd21d3
GB
505 if(cargc>1)
506 limit = strtoul(cargv[1], NULL, 10);
507
508 if(limit==0)
509 limit = 100;
510
1467e9a4
GB
511 name = cargv[0];
512
513 if (name[0] == '#') {
514 groupid = strtoul(name + 1, NULL, 10);
515 trustlogspewid(sender, groupid, limit);
516 } else {
517 trustlogspewname(sender, name, limit);
518 }
01bd21d3
GB
519
520 return CMD_OK;
521}
522
523static int trusts_cmdtrustloggrep(void *source, int cargc, char **cargv) {
524 nick *sender = source;
525 char *pattern;
526 int limit = 0;
527
528 if(cargc < 1)
529 return CMD_USAGE;
530
531 pattern = cargv[0];
532
533 if(cargc>1)
534 limit = strtoul(cargv[1], NULL, 10);
535
536 if(limit==0)
537 limit = 100;
538
539 trustloggrep(sender, pattern, limit);
540
541 return CMD_OK;
542}
543
544static int trusts_cmdtrustcomment(void *source, int cargc, char **cargv) {
545 nick *sender = source;
546 trustgroup *tg = NULL;
547 char *name, *comment;
548
549 if(cargc < 2)
550 return CMD_USAGE;
551
552 name = cargv[0];
553 comment = cargv[1];
554
555 tg = tg_strtotg(name);
556
557 if(!tg) {
558 controlreply(sender, "Invalid trust group name or ID.");
559 return CMD_OK;
560 }
561
52644481 562 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTCOMMENT'ed group '%s': %s", controlid(sender), tg->name->content, comment);
7db61652 563 trustlog(tg, sender->authname, "Comment: %s", comment);
01bd21d3
GB
564
565 return CMD_OK;
566}
567
caf2d02a
GB
568static void cleanuptrusts(void *arg);
569
570static int trusts_cmdtrustcleanup(void *source, int cargc, char **cargv) {
571 cleanuptrusts(source);
572
573 controlreply(source, "Done.");
574
575 return CMD_OK;
576}
577
01bd21d3 578
35449aa5
CP
579static int commandsregistered;
580
581static void registercommands(int hooknum, void *arg) {
582 if(commandsregistered)
583 return;
584 commandsregistered = 1;
585
56f4ec56 586 registercontrolhelpcmd("trustgroupadd", NO_OPER, 7, trusts_cmdtrustgroupadd, "Usage: trustgroupadd <name> <howmany> <howlong> <maxperident> <enforceident> <contact> ?comment?");
35449aa5 587 registercontrolhelpcmd("trustadd", NO_OPER, 2, trusts_cmdtrustadd, "Usage: trustadd <#id|name|id> <host>");
2ab0a1e7
CP
588 registercontrolhelpcmd("trustgroupdel", NO_OPER, 1, trusts_cmdtrustgroupdel, "Usage: trustgroupdel <#id|name|id>");
589 registercontrolhelpcmd("trustdel", NO_OPER, 2, trusts_cmdtrustdel, "Usage: trustdel <#id|name|id> <ip/mask>");
590 registercontrolhelpcmd("trustgroupmodify", NO_OPER, 3, trusts_cmdtrustgroupmodify, "Usage: trustgroupmodify <#id|name|id> <field> <new value>");
c1da06f9 591 registercontrolhelpcmd("trusthostmodify", NO_OPER, 4, trusts_cmdtrusthostmodify, "Usage: trusthostmodify <#id|name|id> <host> <field> <new value>");
e5c0bccf 592 registercontrolhelpcmd("trustlog", NO_OPER, 2, trusts_cmdtrustlog, "Usage: trustlog <#id|name> ?limit?\nShows log for the specified trust group.");
35c3513c 593 registercontrolhelpcmd("trustloggrep", NO_OPER, 2, trusts_cmdtrustloggrep, "Usage trustloggrep <pattern> ?limit?\nShows maching log entries.");
01bd21d3 594 registercontrolhelpcmd("trustcomment", NO_OPER, 2, trusts_cmdtrustcomment, "Usage: trustcomment <#id|name> <comment>\nLogs a comment for a trust.");
caf2d02a 595 registercontrolhelpcmd("trustcleanup", NO_DEVELOPER, 0, trusts_cmdtrustcleanup, "Usage: trustcleanup\nCleans up unused trusts.");
35449aa5
CP
596}
597
598static void deregistercommands(int hooknum, void *arg) {
599 if(!commandsregistered)
600 return;
601 commandsregistered = 0;
602
603 deregistercontrolcmd("trustgroupadd", trusts_cmdtrustgroupadd);
604 deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
2ab0a1e7
CP
605 deregistercontrolcmd("trustgroupdel", trusts_cmdtrustgroupdel);
606 deregistercontrolcmd("trustdel", trusts_cmdtrustdel);
607 deregistercontrolcmd("trustgroupmodify", trusts_cmdtrustgroupmodify);
c1da06f9 608 deregistercontrolcmd("trusthostmodify", trusts_cmdtrusthostmodify);
e5c0bccf 609 deregistercontrolcmd("trustlog", trusts_cmdtrustlog);
01bd21d3
GB
610 deregistercontrolcmd("trustloggrep", trusts_cmdtrustloggrep);
611 deregistercontrolcmd("trustcomment", trusts_cmdtrustcomment);
caf2d02a 612 deregistercontrolcmd("trustcleanup", trusts_cmdtrustcleanup);
35449aa5
CP
613}
614
82a316e7
CP
615static int loaded;
616
1d9ccd69 617#define _ms_(x) (struct trustmodification){ .name = # x, .fn = modify ## x }
c1da06f9
GB
618#define MSGROUP(x) { int slot = array_getfreeslot(&trustgroupmods_a); trustgroupmods = (struct trustmodification *)trustgroupmods_a.content; memcpy(&trustgroupmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
619#define MSHOST(x) { int slot = array_getfreeslot(&trusthostmods_a); trusthostmods = (struct trustmodification *)trusthostmods_a.content; memcpy(&trusthostmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
1d9ccd69
CP
620
621static void setupmods(void) {
c1da06f9
GB
622 MSGROUP(expires);
623 MSGROUP(enforceident);
624 MSGROUP(maxperident);
625 MSGROUP(contact);
626 MSGROUP(comment);
627 MSGROUP(trustedfor);
628
629 MSHOST(maxpernode);
630 MSHOST(nodebits);
1d9ccd69
CP
631}
632
caf2d02a
GB
633static int cleanuptrusts_active;
634
635static void cleanuptrusts(void *arg) {
636 unsigned int now, to_age;
637 nick *np = (nick *)arg;
638 trustgroup *tg;
639 trusthost *th;
640 int thcount = 0, tgcount = 0;
641 int i;
642 array expiredths, expiredtgs;
643
644 now = time(NULL);
645 to_age = now - (CLEANUP_TH_INACTIVE * 3600 * 24);
646
647 if(np) {
648 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Manually started by %s.", np->nick);
649 } else {
650 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Automatically started.");
651 }
652
653 if (cleanuptrusts_active) {
654 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: ABORTED! Cleanup already in progress! BUG BUG BUG!");
655 return;
656 }
657
658 cleanuptrusts_active=1;
659
660 array_init(&expiredtgs, sizeof(trustgroup *));
661
662 for(tg=tglist;tg;tg=tg->next) {
663 array_init(&expiredths, sizeof(trusthost *));
664
665 for(th=tg->hosts;th;th=th->next) {
666 if((th->count == 0 && th->created < to_age && th->lastseen < to_age) || (tg->expires && tg->expires < now)) {
667 int pos = array_getfreeslot(&expiredths);
668 ((trusthost **)(expiredths.content))[pos] = th;
669 }
670 }
671
672 for(i=0;i<expiredths.cursi;i++) {
673 char *cidrstr;
674
675 th = ((trusthost **)(expiredths.content))[i];
676 triggerhook(HOOK_TRUSTS_DELHOST, th);
677 th_delete(th);
678
6e6e98da 679 cidrstr = trusts_cidr2str(&th->ip, th->bits);
caf2d02a
GB
680 trustlog(tg, "cleanuptrusts", "Removed host '%s' because it was unused for %d days.", cidrstr, CLEANUP_TH_INACTIVE);
681
682 thcount++;
683 }
684
685 if(!tg->hosts) {
686 int pos = array_getfreeslot(&expiredtgs);
687 ((trustgroup **)(expiredtgs.content))[pos] = tg;
688 }
689 }
690
691 for(i=0;i<expiredtgs.cursi;i++) {
692 tg = ((trustgroup **)(expiredtgs.content))[i];
693 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
694 trustlog(tg, "cleanuptrusts", "Deleted group '%s' because it had no hosts left.", tg->name->content);
695 tg_delete(tg);
696 tgcount++;
697 }
698
699 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Removed %d trust hosts (inactive for %d days) and %d trust groups.", thcount, CLEANUP_TH_INACTIVE, tgcount);
700
701 cleanuptrusts_active=0;
702}
703
704static void schedulecleanup(int hooknum, void *arg) {
705 /* run at 1am but only if we're more than 15m away from it, otherwise run tomorrow */
706
707 time_t t = time(NULL);
708 time_t next_run = ((t / 86400) * 86400 + 86400) + 3600;
709 if(next_run - t < 900)
710 next_run+=86400;
711
712 schedulerecurring(next_run,0,86400,cleanuptrusts,NULL);
713}
714
35449aa5 715void _init(void) {
82a316e7
CP
716 sstring *m;
717
c1da06f9
GB
718 array_init(&trustgroupmods_a, sizeof(struct trustmodification));
719 array_init(&trusthostmods_a, sizeof(struct trustmodification));
1d9ccd69
CP
720 setupmods();
721
82a316e7
CP
722 m = getconfigitem("trusts", "master");
723 if(!m || (atoi(m->content) != 1)) {
724 Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
725 return;
726 }
727
728 loaded = 1;
729
35449aa5 730 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
caf2d02a 731 registerhook(HOOK_TRUSTS_DB_LOADED, schedulecleanup);
35449aa5
CP
732 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
733
734 if(trustsdbloaded)
735 registercommands(0, NULL);
736}
737
738void _fini(void) {
c1da06f9
GB
739 array_free(&trustgroupmods_a);
740 array_free(&trusthostmods_a);
1d9ccd69 741
82a316e7
CP
742 if(!loaded)
743 return;
744
35449aa5
CP
745 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
746 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
747
748 deregistercommands(0, NULL);
caf2d02a
GB
749
750 deleteallschedules(cleanuptrusts);
35449aa5 751}