]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_management.c
trusthostmodify: Make sure nodebits are valid.
[irc/quakenet/newserv.git] / trusts / trusts_management.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "../control/control.h"
4 #include "../lib/version.h"
5 #include "../lib/irc_string.h"
6 #include "../lib/strlfunc.h"
7 #include "../core/config.h"
8 #include "../core/schedule.h"
9 #include "../irc/irc.h"
10 #include "../lib/stringbuf.h"
11 #include "../noperserv/noperserv.h"
12 #include "../noperserv/noperserv_policy.h"
13 #include "trusts.h"
14
15 MODULE_VERSION("");
16
17 static void registercommands(int, void *);
18 static void deregistercommands(int, void *);
19
20 typedef int (*trustmodificationfn)(void *, char *arg, nick *, int);
21
22 struct trustmodification {
23 char name[50];
24 trustmodificationfn fn;
25 };
26
27 static int trusts_cmdtrustadd(void *source, int cargc, char **cargv) {
28 trustgroup *tg;
29 nick *sender = source;
30 char *host;
31 struct irc_in_addr ip;
32 unsigned char bits;
33 trusthost *th, *superset, *subset;
34
35 if(cargc < 2)
36 return CMD_USAGE;
37
38 tg = tg_strtotg(cargv[0]);
39 if(!tg) {
40 controlreply(sender, "Couldn't look up trustgroup.");
41 return CMD_ERROR;
42 }
43
44 host = cargv[1];
45 if(!ipmask_parse(host, &ip, &bits)) {
46 controlreply(sender, "Invalid host.");
47 return CMD_ERROR;
48 }
49
50 if(!is_normalized_ipmask(&ip, bits)) {
51 controlreply(sender, "Invalid IP Mask.");
52 return CMD_ERROR;
53 }
54
55 /* Don't allow non-developers to add trusts for large subnets or modify protected groups. */
56 if (!noperserv_policy_command_permitted(NO_DEVELOPER, sender)) {
57 int minbits = irc_in_addr_is_ipv4(&ip)?TRUST_MIN_UNPRIVILEGED_BITS_IPV4:TRUST_MIN_UNPRIVILEGED_BITS_IPV6;
58 if(bits < minbits) {
59 controlreply(sender, "You don't have the necessary privileges to add a subnet larger than /%d.", irc_bitlen(&ip, minbits));
60 return CMD_ERROR;
61 }
62
63 if(tg->flags & TRUST_PROTECTED) {
64 controlreply(sender, "You don't have the necessary privileges to modify a protected trust group.");
65 return CMD_ERROR;
66 }
67 }
68
69 /* OKAY! Lots of checking here!
70 *
71 * Need to check:
72 * - host isn't already covered by given group (reject if it is)
73 * - host doesn't already exist exactly already (reject if it does)
74 * - host is more specific than an existing one (warn if it is, fix up later)
75 * - host is less specific than an existing one (warn if it is, don't need to do anything special)
76 */
77
78 for(th=tg->hosts;th;th=th->next) {
79 if(ipmask_check(&ip, &th->ip, th->bits)) {
80 controlreply(sender, "This host (or part of it) is already covered in the given group.");
81 return CMD_ERROR;
82 }
83 }
84
85 if(th_getbyhostandmask(&ip, bits)) {
86 controlreply(sender, "This host already exists in another group with the same mask.");
87 return CMD_ERROR;
88 }
89
90 /* this function will set both to NULL if it's equal, hence the check above */
91 th_getsuperandsubsets(&ip, bits, &superset, &subset);
92 if(superset) {
93 /* a superset exists for us, we will be more specific than one existing host */
94
95 controlreply(sender, "Note: This host already exists in another group, but this new host will override it as it has a smaller prefix.");
96 }
97 if(subset) {
98 /* a subset of us exists, we will be less specific than some existing hosts */
99
100 controlreply(sender, "Note: This host already exists in at least one other group, the new host has a larger prefix and therefore will not override those hosts.");
101 }
102
103 th = th_new(tg, host);
104 if(!th) {
105 controlreply(sender, "An error occured adding the host to the group.");
106 return CMD_ERROR;
107 }
108
109 controlreply(sender, "Host added.");
110 triggerhook(HOOK_TRUSTS_ADDHOST, th);
111
112 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTADD'ed host %s to group '%s'", controlid(sender), host, th->group->name->content);
113 trustlog(tg, sender->authname, "Added host '%s'.", host);
114
115 return CMD_OK;
116 }
117
118 static int trusts_cmdtrustgroupadd(void *source, int cargc, char **cargv) {
119 nick *sender = source;
120 char *name, *contact, *comment, createdby[ACCOUNTLEN + 2];
121 long howmany, maxperident, enforceident;
122 trustgroup *tg, itg;
123 int override, flags;
124
125 if(cargc < 5)
126 return CMD_USAGE;
127
128 override = noperserv_policy_command_permitted(NO_DEVELOPER, sender);
129
130 name = cargv[0];
131 howmany = strtol(cargv[1], NULL, 10);
132 if(!override && (!howmany || (howmany > MAXTRUSTEDFOR))) {
133 controlreply(sender, "Bad value maximum number of clients.");
134 return CMD_ERROR;
135 }
136
137 maxperident = strtol(cargv[2], NULL, 10);
138 if(maxperident < 0 || (maxperident > MAXPERIDENT)) {
139 controlreply(sender, "Bad value for max per ident.");
140 return CMD_ERROR;
141 }
142
143 if(cargv[3][0] != '1' && cargv[3][0] != '0') {
144 controlreply(sender, "Bad value for enforce ident (use 0 or 1).");
145 return CMD_ERROR;
146 }
147 enforceident = cargv[3][0] == '1';
148
149 contact = cargv[4];
150
151 if(cargc < 6) {
152 comment = "(no comment)";
153 } else {
154 comment = cargv[5];
155 }
156
157 /* don't allow #id or id forms */
158 if((name[0] == '#') || strtol(name, NULL, 10)) {
159 controlreply(sender, "Invalid trustgroup name.");
160 return CMD_ERROR;
161 }
162
163 tg = tg_strtotg(name);
164 if(tg) {
165 controlreply(sender, "A group with that name already exists.");
166 return CMD_ERROR;
167 }
168
169 snprintf(createdby, sizeof(createdby), "#%s", sender->authname);
170
171 flags = 0;
172
173 if(maxperident > 0)
174 flags |= TRUST_RELIABLE_USERNAME;
175
176 if(enforceident)
177 flags |= TRUST_ENFORCE_IDENT;
178
179 itg.trustedfor = howmany;
180 itg.flags = flags;
181 itg.maxperident = maxperident;
182 itg.expires = 0;
183 itg.createdby = getsstring(createdby, CREATEDBYLEN);
184 itg.contact = getsstring(contact, CONTACTLEN);
185 itg.comment = getsstring(comment, COMMENTLEN);
186 itg.name = getsstring(name, TRUSTNAMELEN);
187
188 if(itg.createdby && itg.contact && itg.comment && itg.name) {
189 tg = tg_new(&itg);
190 } else {
191 tg = NULL;
192 }
193
194 freesstring(itg.createdby);
195 freesstring(itg.comment);
196 freesstring(itg.name);
197 freesstring(itg.contact);
198
199 if(!tg) {
200 controlreply(sender, "An error occured adding the trustgroup.");
201 return CMD_ERROR;
202 }
203
204 controlreply(sender, "Group added.");
205 triggerhook(HOOK_TRUSTS_ADDGROUP, tg);
206
207 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPADD'ed '%s'", controlid(sender), tg->name->content);
208 trustlog(tg, sender->authname, "Created trust group '%s' (ID #%d): howmany=%d, enforceident=%d, maxperident=%d, "
209 "createdby=%s, contact=%s, comment=%s",
210 tg->name->content, howmany, tg->id, enforceident, maxperident, createdby, contact, comment);
211
212 return CMD_OK;
213 }
214
215 static int trusts_cmdtrustgroupdel(void *source, int cargc, char **cargv) {
216 trustgroup *tg;
217 nick *sender = source;
218
219 if(cargc < 1)
220 return CMD_USAGE;
221
222 tg = tg_strtotg(cargv[0]);
223 if(!tg) {
224 controlreply(sender, "Couldn't look up trustgroup.");
225 return CMD_ERROR;
226 }
227
228 /* Don't allow non-developers to delete protected groups. */
229 if (!noperserv_policy_command_permitted(NO_DEVELOPER, sender)) {
230 if(tg->flags & TRUST_PROTECTED) {
231 controlreply(sender, "You don't have the necessary privileges to modify a protected trust group.");
232 return CMD_ERROR;
233 }
234 }
235
236 if(tg->hosts) {
237 controlreply(sender, "Delete all hosts before deleting the group.");
238 return CMD_ERROR;
239 }
240
241 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTGROUPDEL'ed '%s'.", controlid(sender), tg->name->content);
242 trustlog(tg, sender->authname, "Deleted group '%s'.", tg->name->content);
243
244 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
245 tg_delete(tg);
246 controlreply(sender, "Group deleted.");
247
248 return CMD_OK;
249 }
250
251 static int trusts_cmdtrustdel(void *source, int cargc, char **cargv) {
252 trustgroup *tg;
253 trusthost *th;
254 struct irc_in_addr ip;
255 unsigned char bits;
256 nick *sender = source;
257 char *host;
258
259 if(cargc < 2)
260 return CMD_USAGE;
261
262 tg = tg_strtotg(cargv[0]);
263 if(!tg) {
264 controlreply(sender, "Couldn't look up trustgroup.");
265 return CMD_ERROR;
266 }
267
268 host = cargv[1];
269 if(!ipmask_parse(host, &ip, &bits)) {
270 controlreply(sender, "Invalid IP/mask.");
271 return CMD_ERROR;
272 }
273
274 /* Don't allow non-developers to remove trusts for large subnets or modify protected groups. */
275 if (!noperserv_policy_command_permitted(NO_DEVELOPER, sender)) {
276 int minbits = irc_in_addr_is_ipv4(&ip)?TRUST_MIN_UNPRIVILEGED_BITS_IPV4:TRUST_MIN_UNPRIVILEGED_BITS_IPV6;
277 if(bits < minbits) {
278 controlreply(sender, "You don't have the necessary privileges to remove a subnet larger than /%d.", irc_bitlen(&ip, minbits));
279 return CMD_ERROR;
280 }
281
282 if(tg->flags & TRUST_PROTECTED) {
283 controlreply(sender, "You don't have the necessary privileges to modify a protected trust group.");
284 return CMD_ERROR;
285 }
286 }
287
288 for(th=tg->hosts;th;th=th->next)
289 if(ipmask_check(&ip, &th->ip, th->bits) && th->bits == bits)
290 break;
291
292 if(!th) {
293 controlreply(sender, "Couldn't find that host in that group.");
294 return CMD_ERROR;
295 }
296
297 triggerhook(HOOK_TRUSTS_DELHOST, th);
298 th_delete(th);
299 controlreply(sender, "Host deleted.");
300
301 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTDEL'ed %s from group '%s'.", controlid(sender), host, tg->name->content);
302 trustlog(tg, sender->authname, "Removed host '%s'.", host);
303
304 return CMD_OK;
305 }
306
307 static int modifycomment(void *arg, char *comment, nick *source, int override) {
308 trustgroup *tg = arg;
309 sstring *n = getsstring(comment, COMMENTLEN);
310 if(!n)
311 return 0;
312
313 freesstring(tg->comment);
314 tg->comment = n;
315
316 return 1;
317 }
318
319 static int modifycontact(void *arg, char *contact, nick *source, int override) {
320 trustgroup *tg = arg;
321 sstring *n = getsstring(contact, CONTACTLEN);
322 if(!n)
323 return 0;
324
325 freesstring(tg->contact);
326 tg->contact = n;
327
328 return 1;
329 }
330
331 static int modifytrustedfor(void *arg, char *num, nick *source, int override) {
332 trustgroup *tg = arg;
333 long trustedfor = strtol(num, NULL, 10);
334
335 if(trustedfor < 0) {
336 controlreply(source, "The clone limit must not be negative.");
337 return 0;
338 }
339
340 if(!override) {
341 if (trustedfor == 0) {
342 controlreply(source, "You don't have the necessary privileges to set an unlimited clone limit.");
343 return 0;
344 }
345
346 if (trustedfor > MAXTRUSTEDFOR) {
347 controlreply(source, "You don't have the necessary privileges to set the clone limit to a value higher than %d.", MAXTRUSTEDFOR);
348 return 0;
349 }
350 }
351
352 tg->trustedfor = trustedfor;
353
354 return 1;
355 }
356
357 static int modifymaxperident(void *arg, char *num, nick *source, int override) {
358 trustgroup *tg = arg;
359 long maxperident = strtol(num, NULL, 10);
360
361 if(maxperident < 0) {
362 controlreply(source, "Ident limit must not be negative.");
363 return 0;
364 }
365
366 if(maxperident > MAXPERIDENT) {
367 controlreply(source, "Ident limit must not be higher than %d. Consider setting it to 0 (unlimited) instead.", MAXPERIDENT);
368 return 0;
369 }
370
371 tg->maxperident = maxperident;
372
373 return 1;
374 }
375
376 static int modifyenforceident(void *arg, char *num, nick *source, int override) {
377 trustgroup *tg = arg;
378
379 if(num[0] == '1') {
380 tg->flags |= TRUST_ENFORCE_IDENT;
381 } else if(num[0] == '0') {
382 tg->flags &= ~TRUST_ENFORCE_IDENT;
383 } else {
384 return 0;
385 }
386
387 return 1;
388 }
389
390 static int modifyreliableusername(void *arg, char *num, nick *source, int override) {
391 trustgroup *tg = arg;
392
393 if(num[0] == '1') {
394 tg->flags |= TRUST_RELIABLE_USERNAME;
395 } else if(num[0] == '0') {
396 tg->flags &= ~TRUST_RELIABLE_USERNAME;
397 } else {
398 return 0;
399 }
400
401 return 1;
402 }
403
404 static int modifyexpires(void *arg, char *expires, nick *source, int override) {
405 trustgroup *tg = arg;
406 int howlong = durationtolong(expires);
407
408 if((howlong < 0) || (howlong > MAXDURATION)) {
409 controlreply(source, "Duration cannot be negative or greater than %s (use 0 instead if you don't want the group to expire).", longtoduration(MAXDURATION, 0));
410 return 0;
411 }
412
413 if(howlong)
414 tg->expires = getnettime() + howlong;
415 else
416 tg->expires = 0; /* never */
417
418 return 1;
419 }
420
421 static int modifycleanup(void *arg, char *num, nick *source, int override) {
422 trustgroup *tg = arg;
423
424 if(!override) {
425 controlreply(source, "You don't have the necessary privileges to modify this attribute.");
426 return 0;
427 }
428
429 if(num[0] == '1') {
430 tg->flags &= ~TRUST_NO_CLEANUP;
431 } else if(num[0] == '0') {
432 tg->flags |= TRUST_NO_CLEANUP;
433 } else {
434 return 0;
435 }
436
437 return 1;
438 }
439
440 static int modifyprotected(void *arg, char *num, nick *source, int override) {
441 trustgroup *tg = arg;
442
443 if(!override) {
444 controlreply(source, "You don't have the necessary privileges to modify this attribute.");
445 return 0;
446 }
447
448 if(num[0] == '1') {
449 tg->flags |= TRUST_PROTECTED;
450 } else if(num[0] == '0') {
451 tg->flags &= ~TRUST_PROTECTED;
452 } else {
453 return 0;
454 }
455
456 return 1;
457 }
458
459 static int modifymaxpernode(void *arg, char *num, nick *source, int override) {
460 trusthost *th = arg;
461 int maxpernode = strtol(num, NULL, 10);
462
463 if(maxpernode < 0) {
464 controlreply(source, "Node limit must not be negative.");
465 return 0;
466 }
467
468 if(maxpernode>MAXPERNODE) {
469 controlreply(source, "Node limit must not be higher than %d. Consider setting it to 0 (unlimited) instead.", MAXPERNODE);
470 return 0;
471 }
472
473 th->maxpernode = maxpernode;
474
475 return 1;
476 }
477
478 static int modifynodebits(void *arg, char *num, nick *source, int override) {
479 trusthost *th = arg;
480 int nodebits = strtol(num, NULL, 10);
481
482 if(nodebits < 0) {
483 controlreply(source, "Node bits must not be negative.");
484 return 0;
485 }
486
487 if(irc_in_addr_is_ipv4(&th->ip))
488 nodebits += 96;
489
490 if(nodebits > 128) {
491 controlreply(source, "Node bits is invalid.");
492 return 0;
493 }
494
495 if(!override) {
496 int minbits = irc_in_addr_is_ipv4(&th->ip)?TRUST_MIN_UNPRIVILEGED_NODEBITS_IPV4:TRUST_MIN_UNPRIVILEGED_NODEBITS_IPV6;
497
498 if(nodebits < minbits) {
499 controlreply(source, "You don't have the necessary privileges to set node bits to a subnet larger than /%d.", irc_bitlen(&th->ip, minbits));
500 return 0;
501 }
502 }
503
504 if(nodebits<th->bits) {
505 controlreply(source, "Node bits must be smaller or equal to the trusted CIDR's subnet size.");
506 return 0;
507 }
508
509 th->nodebits = nodebits;
510
511 return 1;
512 }
513
514 static array trustgroupmods_a;
515 static struct trustmodification *trustgroupmods;
516 static array trusthostmods_a;
517 static struct trustmodification *trusthostmods;
518
519 static int trusts_cmdtrustgroupmodify(void *source, int cargc, char **cargv) {
520 trustgroup *tg;
521 nick *sender = source;
522 char *what, *to;
523 int i, override;
524
525 if(cargc < 3)
526 return CMD_USAGE;
527
528 tg = tg_strtotg(cargv[0]);
529 if(!tg) {
530 controlreply(sender, "Couldn't look up trustgroup.");
531 return CMD_ERROR;
532 }
533
534 what = cargv[1];
535 to = cargv[2];
536
537 override = noperserv_policy_command_permitted(NO_DEVELOPER, sender);
538
539 /* Don't allow non-developers to modify protected groups. */
540 if (!override && tg->flags & TRUST_PROTECTED) {
541 controlreply(sender, "You don't have the necessary privileges to modify a protected trust group.");
542 return CMD_ERROR;
543 }
544
545 for(i=0;i<trustgroupmods_a.cursi;i++) {
546 if(!strcmp(what, trustgroupmods[i].name)) {
547 if(!(trustgroupmods[i].fn)(tg, to, sender, override)) {
548 controlreply(sender, "An error occured changing that property, check the syntax.");
549 return CMD_ERROR;
550 }
551 break;
552 }
553 }
554
555 if(i == trustgroupmods_a.cursi)
556 return CMD_USAGE;
557
558 triggerhook(HOOK_TRUSTS_MODIFYGROUP, tg);
559 tg_update(tg);
560 controlreply(sender, "Group modified.");
561
562 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed group '%s' (field: %s, value: %s)", controlid(sender), tg->name->content, what, to);
563 trustlog(tg, sender->authname, "Modified %s: %s", what, to);
564
565 return CMD_OK;
566 }
567
568 static int trusts_cmdtrusthostmodify(void *source, int cargc, char **cargv) {
569 trustgroup *tg;
570 trusthost *th;
571 nick *sender = source;
572 char *what, *to;
573 int i, override;
574 struct irc_in_addr ip;
575 unsigned char bits;
576
577 if(cargc < 4)
578 return CMD_USAGE;
579
580 tg = tg_strtotg(cargv[0]);
581 if(!tg) {
582 controlreply(sender, "Couldn't look up trustgroup.");
583 return CMD_ERROR;
584 }
585
586 if(!ipmask_parse(cargv[1], &ip, &bits)) {
587 controlreply(sender, "Invalid host.");
588 return CMD_ERROR;
589 }
590
591 /* Don't allow non-developers to modify trusts for large subnets or modify protected groups. */
592 if (!noperserv_policy_command_permitted(NO_DEVELOPER, sender)) {
593 int minbits = irc_in_addr_is_ipv4(&ip)?TRUST_MIN_UNPRIVILEGED_BITS_IPV4:TRUST_MIN_UNPRIVILEGED_BITS_IPV6;
594 if(bits < minbits) {
595 controlreply(sender, "You don't have the necessary privileges to modify a subnet larger than /%d.", irc_bitlen(&ip, minbits));
596 return CMD_ERROR;
597 }
598
599 if(tg->flags & TRUST_PROTECTED) {
600 controlreply(sender, "You don't have the necessary privileges to modify a protected trust group.");
601 return CMD_ERROR;
602 }
603 }
604
605 th = th_getbyhostandmask(&ip, bits);
606
607 if(!th || th->group != tg) {
608 controlreply(sender, "Host does not belong to the specified group.");
609 return CMD_ERROR;
610 }
611
612 what = cargv[2];
613 to = cargv[3];
614
615 override = noperserv_policy_command_permitted(NO_DEVELOPER, sender);
616
617 for(i=0;i<trusthostmods_a.cursi;i++) {
618 if(!strcmp(what, trusthostmods[i].name)) {
619 if(!(trusthostmods[i].fn)(th, to, sender, override)) {
620 controlreply(sender, "An error occured changing that property, check the syntax.");
621 return CMD_ERROR;
622 }
623 break;
624 }
625 }
626
627 if(i == trusthostmods_a.cursi)
628 return CMD_USAGE;
629
630 triggerhook(HOOK_TRUSTS_MODIFYHOST, th);
631 th_update(th);
632 controlreply(sender, "Host modified.");
633
634 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTMODIFIED'ed host '%s' in group '%s' (field: %s, value: %s)", controlid(sender), CIDRtostr(ip, bits), tg->name->content, what, to);
635 trustlog(tg, sender->authname, "Modified %s for host '%s': %s", what, CIDRtostr(ip, bits), to);
636
637 return CMD_OK;
638 }
639
640 static int trusts_cmdtrustlog(void *source, int cargc, char **cargv) {
641 nick *sender = source;
642 char *name;
643 int groupid;
644 long limit = 0;
645
646 if(cargc < 1)
647 return CMD_USAGE;
648
649 if(cargc>1)
650 limit = strtol(cargv[1], NULL, 10);
651
652 if(limit==0)
653 limit = 100;
654
655 name = cargv[0];
656
657 if (name[0] == '#') {
658 groupid = strtol(name + 1, NULL, 10);
659 trustlogspewid(sender, groupid, limit);
660 } else {
661 trustlogspewname(sender, name, limit);
662 }
663
664 return CMD_OK;
665 }
666
667 static int trusts_cmdtrustloggrep(void *source, int cargc, char **cargv) {
668 nick *sender = source;
669 char *pattern;
670 long limit = 0;
671
672 if(cargc < 1)
673 return CMD_USAGE;
674
675 pattern = cargv[0];
676
677 if(cargc>1)
678 limit = strtol(cargv[1], NULL, 10);
679
680 if(limit==0)
681 limit = 100;
682
683 trustloggrep(sender, pattern, limit);
684
685 return CMD_OK;
686 }
687
688 static int trusts_cmdtrustcomment(void *source, int cargc, char **cargv) {
689 nick *sender = source;
690 trustgroup *tg = NULL;
691 char *name, *comment;
692
693 if(cargc < 2)
694 return CMD_USAGE;
695
696 name = cargv[0];
697 comment = cargv[1];
698
699 if(strlen(comment)>TRUSTLOGLEN) {
700 controlreply(sender, "Your comment is too long (max: %d characters).", TRUSTLOGLEN);
701 return CMD_OK;
702 }
703
704 tg = tg_strtotg(name);
705
706 if(!tg) {
707 controlreply(sender, "Invalid trust group name or ID.");
708 return CMD_OK;
709 }
710
711 controlwall(NO_OPER, NL_TRUSTS, "%s TRUSTCOMMENT'ed group '%s': %s", controlid(sender), tg->name->content, comment);
712 trustlog(tg, sender->authname, "Comment: %s", comment);
713
714 return CMD_OK;
715 }
716
717 static void cleanuptrusts(void *arg);
718
719 static int trusts_cmdtrustcleanup(void *source, int cargc, char **cargv) {
720 cleanuptrusts(source);
721
722 controlreply(source, "Done.");
723
724 return CMD_OK;
725 }
726
727
728 static int commandsregistered;
729
730 static void registercommands(int hooknum, void *arg) {
731 static char tgmhelp[512], thmhelp[512];
732 char validfields[512];
733 StringBuf b;
734 int i;
735
736 if(commandsregistered)
737 return;
738 commandsregistered = 1;
739
740 registercontrolhelpcmd("trustgroupadd", NO_OPER, 6, trusts_cmdtrustgroupadd, "Usage: trustgroupadd <name> <howmany> <maxperident> <enforceident> <contact> ?comment?");
741 registercontrolhelpcmd("trustadd", NO_OPER, 2, trusts_cmdtrustadd, "Usage: trustadd <#id|name|id> <host>");
742 registercontrolhelpcmd("trustgroupdel", NO_OPER, 1, trusts_cmdtrustgroupdel, "Usage: trustgroupdel <#id|name|id>");
743 registercontrolhelpcmd("trustdel", NO_OPER, 2, trusts_cmdtrustdel, "Usage: trustdel <#id|name|id> <ip/mask>");
744
745 sbinit(&b, validfields, sizeof(validfields));
746 for(i=0;i<trustgroupmods_a.cursi;i++) {
747 if(i > 0)
748 sbaddstr(&b, ", ");
749 sbaddstr(&b, trustgroupmods[i].name);
750 }
751 sbterminate(&b);
752
753 snprintf(tgmhelp, sizeof(tgmhelp), "Usage: trustgroupmodify <#id|name|id> <field> <new value>\nModifies a trust group.\nValid fields: %s", validfields);
754 registercontrolhelpcmd("trustgroupmodify", NO_OPER, 3, trusts_cmdtrustgroupmodify, tgmhelp);
755
756 sbinit(&b, validfields, sizeof(validfields));
757 for(i=0;i<trusthostmods_a.cursi;i++) {
758 if(i > 0)
759 sbaddstr(&b, ", ");
760 sbaddstr(&b, trusthostmods[i].name);
761 }
762 sbterminate(&b);
763
764 snprintf(thmhelp, sizeof(thmhelp), "Usage: trusthostmodify <#id|name|id> <host> <field> <new value>\nModifies a trust host\nValid fields: %s", validfields);
765 registercontrolhelpcmd("trusthostmodify", NO_OPER, 4, trusts_cmdtrusthostmodify, thmhelp);
766
767 registercontrolhelpcmd("trustlog", NO_OPER, 2, trusts_cmdtrustlog, "Usage: trustlog <#id|name> ?limit?\nShows log for the specified trust group.");
768 registercontrolhelpcmd("trustloggrep", NO_OPER, 2, trusts_cmdtrustloggrep, "Usage trustloggrep <pattern> ?limit?\nShows maching log entries.");
769 registercontrolhelpcmd("trustcomment", NO_OPER, 2, trusts_cmdtrustcomment, "Usage: trustcomment <#id|name> <comment>\nLogs a comment for a trust.");
770 registercontrolhelpcmd("trustcleanup", NO_DEVELOPER, 0, trusts_cmdtrustcleanup, "Usage: trustcleanup\nCleans up unused trusts.");
771 }
772
773 static void deregistercommands(int hooknum, void *arg) {
774 if(!commandsregistered)
775 return;
776 commandsregistered = 0;
777
778 deregistercontrolcmd("trustgroupadd", trusts_cmdtrustgroupadd);
779 deregistercontrolcmd("trustadd", trusts_cmdtrustadd);
780 deregistercontrolcmd("trustgroupdel", trusts_cmdtrustgroupdel);
781 deregistercontrolcmd("trustdel", trusts_cmdtrustdel);
782 deregistercontrolcmd("trustgroupmodify", trusts_cmdtrustgroupmodify);
783 deregistercontrolcmd("trusthostmodify", trusts_cmdtrusthostmodify);
784 deregistercontrolcmd("trustlog", trusts_cmdtrustlog);
785 deregistercontrolcmd("trustloggrep", trusts_cmdtrustloggrep);
786 deregistercontrolcmd("trustcomment", trusts_cmdtrustcomment);
787 deregistercontrolcmd("trustcleanup", trusts_cmdtrustcleanup);
788 }
789
790 static int loaded;
791
792 #define _ms_(x) (struct trustmodification){ .name = # x, .fn = modify ## x }
793 #define MSGROUP(x) { int slot = array_getfreeslot(&trustgroupmods_a); trustgroupmods = (struct trustmodification *)trustgroupmods_a.content; memcpy(&trustgroupmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
794 #define MSHOST(x) { int slot = array_getfreeslot(&trusthostmods_a); trusthostmods = (struct trustmodification *)trusthostmods_a.content; memcpy(&trusthostmods[slot], &_ms_(x), sizeof(struct trustmodification)); }
795
796 static void setupmods(void) {
797 MSGROUP(expires);
798 MSGROUP(enforceident);
799 MSGROUP(reliableusername);
800 MSGROUP(maxperident);
801 MSGROUP(contact);
802 MSGROUP(comment);
803 MSGROUP(trustedfor);
804 MSGROUP(cleanup);
805 MSGROUP(protected);
806
807 MSHOST(maxpernode);
808 MSHOST(nodebits);
809 }
810
811 static int cleanuptrusts_active;
812
813 static void cleanuptrusts(void *arg) {
814 unsigned int now, to_age;
815 nick *np = (nick *)arg;
816 trustgroup *tg;
817 trusthost *th;
818 int thcount = 0, tgcount = 0;
819 int i;
820 array expiredths, expiredtgs;
821
822 now = getnettime();
823 to_age = now - (CLEANUP_TH_INACTIVE * 3600 * 24);
824
825 if(np) {
826 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Manually started by %s.", np->nick);
827 } else {
828 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Automatically started.");
829 }
830
831 if (cleanuptrusts_active) {
832 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: ABORTED! Cleanup already in progress! BUG BUG BUG!");
833 return;
834 }
835
836 cleanuptrusts_active=1;
837
838 array_init(&expiredtgs, sizeof(trustgroup *));
839
840 for(tg=tglist;tg;tg=tg->next) {
841 array_init(&expiredths, sizeof(trusthost *));
842
843 if(tg->flags & TRUST_NO_CLEANUP)
844 continue;
845
846 for(th=tg->hosts;th;th=th->next) {
847 if((th->count == 0 && th->created < to_age && th->lastseen < to_age) || (tg->expires && tg->expires < now)) {
848 int pos = array_getfreeslot(&expiredths);
849 ((trusthost **)(expiredths.content))[pos] = th;
850 }
851 }
852
853 for(i=0;i<expiredths.cursi;i++) {
854 const char *cidrstr;
855
856 th = ((trusthost **)(expiredths.content))[i];
857 triggerhook(HOOK_TRUSTS_DELHOST, th);
858
859 cidrstr = CIDRtostr(th->ip, th->bits);
860 trustlog(tg, "cleanuptrusts", "Removed host '%s' because it was unused for %d days.", cidrstr, CLEANUP_TH_INACTIVE);
861
862 th_delete(th);
863
864 thcount++;
865 }
866
867 if(!tg->hosts) {
868 int pos = array_getfreeslot(&expiredtgs);
869 ((trustgroup **)(expiredtgs.content))[pos] = tg;
870 }
871 }
872
873 for(i=0;i<expiredtgs.cursi;i++) {
874 tg = ((trustgroup **)(expiredtgs.content))[i];
875 triggerhook(HOOK_TRUSTS_DELGROUP, tg);
876 trustlog(tg, "cleanuptrusts", "Deleted group '%s' because it had no hosts left.", tg->name->content);
877 tg_delete(tg);
878 tgcount++;
879 }
880
881 controlwall(NO_OPER, NL_TRUSTS, "CLEANUPTRUSTS: Removed %d trust hosts (inactive for %d days) and %d empty trust groups.", thcount, CLEANUP_TH_INACTIVE, tgcount);
882
883 cleanuptrusts_active=0;
884 }
885
886 static void schedulecleanup(int hooknum, void *arg) {
887 /* run at 1am but only if we're more than 15m away from it, otherwise run tomorrow */
888
889 time_t t = time(NULL);
890 time_t next_run = ((t / 86400) * 86400 + 86400) + 3600;
891 if(next_run - t < 900)
892 next_run+=86400;
893
894 schedulerecurring(next_run,0,86400,cleanuptrusts,NULL);
895 }
896
897 void _init(void) {
898 sstring *m;
899
900 array_init(&trustgroupmods_a, sizeof(struct trustmodification));
901 array_init(&trusthostmods_a, sizeof(struct trustmodification));
902 setupmods();
903
904 m = getconfigitem("trusts", "master");
905 if(!m || (atoi(m->content) != 1)) {
906 Error("trusts_management", ERR_ERROR, "Not a master server, not loaded.");
907 return;
908 }
909
910 loaded = 1;
911
912 registerhook(HOOK_TRUSTS_DB_LOADED, registercommands);
913 registerhook(HOOK_TRUSTS_DB_LOADED, schedulecleanup);
914 registerhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
915
916 if(trustsdbloaded)
917 registercommands(0, NULL);
918 }
919
920 void _fini(void) {
921 array_free(&trustgroupmods_a);
922 array_free(&trusthostmods_a);
923
924 if(!loaded)
925 return;
926
927 deregisterhook(HOOK_TRUSTS_DB_LOADED, registercommands);
928 deregisterhook(HOOK_TRUSTS_DB_CLOSED, deregistercommands);
929
930 deregistercommands(0, NULL);
931
932 deleteallschedules(cleanuptrusts);
933 }