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