]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_policy.c
TRUSTS: use correct socket opt...
[irc/quakenet/newserv.git] / trusts / trusts_policy.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <unistd.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <netinet/tcp.h>
9
10 #ifndef __USE_MISC
11 #define __USE_MISC /* inet_aton */
12 #endif
13
14 #include <arpa/inet.h>
15 #include <sys/un.h>
16 #include <sys/poll.h>
17 #include <errno.h>
18 #include <fcntl.h>
19
20 #include "../lib/version.h"
21 #include "../lib/hmac.h"
22 #include "../core/events.h"
23 #include "../core/schedule.h"
24 #include "../core/nsmalloc.h"
25 #include "../core/hooks.h"
26 #include "../core/config.h"
27 #include "../control/control.h"
28 #include "../lib/irc_string.h"
29 #include "../irc/irc.h"
30 #include "../glines/glines.h"
31 #include "../patricianick/patricianick.h"
32 #include "trusts.h"
33
34 MODULE_VERSION("");
35
36 static int countext, enforcepolicy_irc, enforcepolicy_auth;
37
38 #define TRUSTBUFSIZE 8192
39 #define TRUSTPASSLEN 128
40 #define NONCELEN 16
41
42 typedef struct trustsocket {
43 int fd;
44 int authed;
45 char authuser[SERVERLEN+1];
46 char buf[TRUSTBUFSIZE];
47 unsigned char nonce[NONCELEN];
48 int size;
49 time_t connected;
50 time_t timeout;
51 int accepted;
52 int rejected;
53 int unthrottled;
54
55 struct trustsocket *next;
56 } trustsocket;
57
58 static trustsocket *tslist;
59 static int listenerfd = -1;
60 static FILE *urandom;
61
62 typedef struct trustaccount {
63 int used;
64 char server[SERVERLEN+1];
65 char password[TRUSTPASSLEN+1];
66 } trustaccount;
67
68 trustaccount trustaccounts[MAXSERVERS];
69
70 static int checkconnection(const char *username, struct irc_in_addr *ipaddress, int hooknum, int usercountadjustment, char *message, size_t messagelen, int *unthrottle) {
71 trusthost *th;
72 trustgroup *tg;
73 struct irc_in_addr ipaddress_canonical;
74
75 ip_canonicalize_tunnel(&ipaddress_canonical, ipaddress);
76
77 th = th_getbyhost(&ipaddress_canonical);
78
79 if (unthrottle)
80 *unthrottle = 0;
81
82 if(messagelen>0)
83 message[0] = '\0';
84
85 if(!th || !trustsdbloaded || irc_in_addr_is_loopback(ipaddress))
86 return POLICY_SUCCESS;
87
88 tg = th->group;
89
90 /*
91 * the purpose of this logic is to avoid spam like this:
92 * WARNING: tgX exceeded limit: 11 connected vs 10 max
93 * (goes back down to 10)
94 * WARNING: tgX exceeded limit: 11 connected vs 10 max
95 */
96
97 if(hooknum == HOOK_TRUSTS_NEWNICK) {
98 patricia_node_t *head, *node;
99 int i, nodecount = 0;
100 patricianick_t *pnp;
101 nick *npp;
102
103 head = refnode(iptree, &ipaddress_canonical, th->nodebits);
104 nodecount = head->usercount;
105
106 /* Account for borrowed IP addresses. */
107 PATRICIA_WALK(head, node) {
108 pnp = node->exts[pnode_ext];
109
110 if (pnp)
111 for (i = 0; i < PATRICIANICK_HASHSIZE; i++)
112 for (npp = pnp->identhash[i]; npp; npp=npp->exts[pnick_ext])
113 if (NickOnServiceServer(npp))
114 usercountadjustment--;
115 }
116 PATRICIA_WALK_END;
117
118 derefnode(iptree, head);
119
120 if(th->maxpernode && nodecount + usercountadjustment > th->maxpernode) {
121 controlwall(NO_OPER, NL_CLONING, "Hard connection limit exceeded on subnet: %s (group: %s): %d connected, %d max.", CIDRtostr(*ipaddress, th->nodebits), tg->name->content, nodecount + usercountadjustment, th->maxpernode);
122 snprintf(message, messagelen, "Too many connections from your host (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
123 return POLICY_FAILURE_NODECOUNT;
124 }
125
126 if(tg->trustedfor && tg->count + usercountadjustment > tg->trustedfor) {
127 if(tg->count > (long)tg->exts[countext]) {
128 tg->exts[countext] = (void *)(long)tg->count;
129
130 controlwall(NO_OPER, NL_CLONING, "Hard connection limit exceeded (group %s): %d connected, %d max.", tg->name->content, tg->count + usercountadjustment, tg->trustedfor);
131 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
132 }
133
134 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
135 return POLICY_FAILURE_GROUPCOUNT;
136 }
137
138 if((tg->flags & TRUST_ENFORCE_IDENT) && (username[0] == '~')) {
139 controlwall(NO_OPER, NL_CLONING, "Ident required: %s@%s (group: %s).", username, IPtostr(*ipaddress), tg->name->content);
140 snprintf(message, messagelen, "IDENTD required from your host (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
141 return POLICY_FAILURE_IDENTD;
142 }
143
144 if(tg->maxperident > 0) {
145 int identcount = 0;
146 trusthost *th2;
147 nick *tnp;
148
149 for(th2=tg->hosts;th2;th2=th2->next) {
150 for(tnp=th2->users;tnp;tnp=nextbytrust(tnp)) {
151 if(!ircd_strcmp(tnp->ident, username))
152 identcount++;
153 }
154 }
155
156 if(identcount + usercountadjustment > tg->maxperident) {
157 controlwall(NO_OPER, NL_CLONING, "Hard ident limit exceeded: %s@%s (group: %s): %d connected, %d max.", username, IPtostr(*ipaddress), tg->name->content, identcount + usercountadjustment, tg->maxperident);
158 snprintf(message, messagelen, "Too many connections from your username (%s@%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", username, IPtostr(*ipaddress));
159 return POLICY_FAILURE_IDENTCOUNT;
160 }
161 }
162 } else {
163 if(tg->count < tg->maxusage)
164 tg->exts[countext] = (void *)(long)tg->count;
165 }
166
167 if(tg->trustedfor > 0)
168 snprintf(message, messagelen, "Trust has %d out of %d allowed connections.", tg->count + usercountadjustment, tg->trustedfor);
169
170 if(unthrottle && (tg->flags & TRUST_UNTHROTTLE))
171 *unthrottle = 1;
172
173 return POLICY_SUCCESS;
174 }
175
176 static int trustdowrite(trustsocket *sock, char *format, ...) {
177 char buf[1024];
178 va_list va;
179 int r;
180
181 va_start(va, format);
182 r = vsnprintf(buf, sizeof(buf), format, va);
183 va_end(va);
184
185 if(r >= sizeof(buf))
186 r = sizeof(buf) - 1;
187
188 buf[r] = '\n';
189
190 if(write(sock->fd, buf, r + 1) != r + 1)
191 return 0;
192 return 1;
193 }
194
195 static int policycheck_auth(trustsocket *sock, const char *sequence_id, const char *username, const char *host) {
196 char message[512];
197 int verdict, unthrottle;
198 struct irc_in_addr ipaddress;
199 unsigned char bits;
200
201 if(!ipmask_parse(host, &ipaddress, &bits)) {
202 sock->accepted++;
203 return trustdowrite(sock, "PASS %s", sequence_id);
204 }
205
206 verdict = checkconnection(username, &ipaddress, HOOK_TRUSTS_NEWNICK, 1, message, sizeof(message), &unthrottle);
207
208 if(!enforcepolicy_auth)
209 verdict = POLICY_SUCCESS;
210
211 if (verdict == POLICY_SUCCESS) {
212 sock->accepted++;
213
214 if (unthrottle) {
215 sock->unthrottled++;
216 trustdowrite(sock, "UNTHROTTLE %s", sequence_id);
217 }
218
219 if(message[0])
220 return trustdowrite(sock, "PASS %s %s", sequence_id, message);
221 else
222 return trustdowrite(sock, "PASS %s", sequence_id);
223 } else {
224 sock->rejected++;
225
226 controlwall(NO_OPER, NL_CLONING, "Rejected connection from %s@%s using IAuth: %s", username, host, message);
227 return trustdowrite(sock, "KILL %s %s", sequence_id, message);
228 }
229 }
230
231 static int trustkillconnection(trustsocket *sock, char *reason) {
232 trustdowrite(sock, "QUIT %s", reason);
233 return 0;
234 }
235
236 static void trustfreeconnection(trustsocket *sock, int unlink) {
237 trustsocket **pnext, *ts;
238
239 if(!unlink) {
240 controlwall(NO_OPER, NL_TRUSTS, "Lost connection on policy socket for '%s'.", sock->authed?sock->authuser:"<unauthenticated connection>");
241
242 deregisterhandler(sock->fd, 1);
243 nsfree(POOL_TRUSTS, sock);
244 return;
245 }
246
247 for(pnext=&tslist;*pnext;pnext=&((*pnext)->next)) {
248 ts=*pnext;
249 if(ts == sock) {
250 *pnext = sock->next;
251 trustfreeconnection(sock, 0);
252 break;
253 }
254 }
255 }
256
257 static int handletrustauth(trustsocket *sock, char *server_name, char *mac) {
258 int i;
259 char *password = NULL;
260 unsigned char digest[16];
261 char noncehexbuf[NONCELEN * 2 + 1];
262 char hexbuf[sizeof(digest) * 2 + 1];
263 trustsocket *ts, **pnext;
264
265 for(i=0;i<MAXSERVERS;i++) {
266 if(trustaccounts[i].used && strcmp(trustaccounts[i].server, server_name) == 0) {
267 password = trustaccounts[i].password;
268 break;
269 }
270 }
271
272 if (!password) {
273 controlwall(NO_OPER, NL_TRUSTS, "Invalid servername for policy socket: '%s'", server_name);
274 return trustkillconnection(sock, "Invalid servername.");
275 }
276
277 hmacmd5 h;
278 hmacmd5_init(&h, (unsigned char *)password, strlen(password));
279 hmacmd5_update(&h, (unsigned char *)hmac_printhex(sock->nonce, noncehexbuf, NONCELEN), NONCELEN * 2);
280 hmacmd5_final(&h, digest);
281 if(hmac_strcmp(mac, hmac_printhex(digest, hexbuf, sizeof(digest)))) {
282 controlwall(NO_OPER, NL_TRUSTS, "Invalid password for policy socket with servername '%s'.", server_name);
283 return trustkillconnection(sock, "Bad MAC.");
284 }
285
286 for(pnext=&tslist;*pnext;pnext=&((*pnext)->next)) {
287 ts = *pnext;
288 if(ts->authed && strcmp(ts->authuser, server_name) == 0) {
289 trustkillconnection(ts, "New connection with same server name.");
290 *pnext = ts->next;
291 trustfreeconnection(ts, 0);
292 break;
293 }
294 }
295
296 sock->authed = 1;
297 strncpy(sock->authuser, server_name, SERVERLEN);
298
299 controlwall(NO_OPER, NL_TRUSTS, "Successful authentication for policy socket with servername '%s'.", server_name);
300 return trustdowrite(sock, "AUTHOK");
301 }
302
303 #define MAXTOKENS 10
304 static int handletrustline(trustsocket *sock, char *line) {
305 char *command, *p, *lastpos;
306 char *tokens[MAXTOKENS];
307 int tokensfound = -1;
308
309 for(command=lastpos=p=line;*p;p++) {
310 if(*p == ' ') {
311 *p = '\0';
312 if(tokensfound == MAXTOKENS)
313 return trustkillconnection(sock, "too many tokens");
314
315 if(tokensfound >= 0) {
316 tokens[tokensfound++] = lastpos;
317 } else {
318 tokensfound++;
319 }
320 lastpos = p + 1;
321 }
322 }
323 if(lastpos != p) {
324 if(tokensfound == MAXTOKENS)
325 return trustkillconnection(sock, "too many tokens");
326 tokens[tokensfound++] = lastpos;
327 }
328
329 if(!sock->authed && !strcmp("AUTH", command)) {
330 if(tokensfound != 2)
331 return trustkillconnection(sock, "incorrect arg count for command.");
332
333 return handletrustauth(sock, tokens[0], tokens[1]);
334 } else if(sock->authed && !strcmp("CHECK", command)) {
335 if(tokensfound != 3)
336 return trustkillconnection(sock, "incorrect arg count for command.");
337
338 policycheck_auth(sock, tokens[0], tokens[1], tokens[2]);
339 return 1;
340 } else if(!strcmp("VERSION", command)) {
341 /* Ignore this command for now. */
342 return 1;
343 } else {
344 Error("trusts_policy", ERR_WARNING, "Bad command: %s", command);
345 return 0;
346 }
347 }
348
349 static trustsocket *findtrustsocketbyfd(int fd) {
350 for(trustsocket *ts=tslist;ts;ts=ts->next)
351 if(ts->fd==fd)
352 return ts;
353
354 return NULL;
355 }
356
357 static int handletrustclient(trustsocket *sock) {
358 int r, remaining = TRUSTBUFSIZE - sock->size, i;
359 char *lastpos, *c;
360
361 if(!remaining) {
362 trustkillconnection(sock, "Buffer overflow.");
363 return 0;
364 }
365
366 r = read(sock->fd, sock->buf + sock->size, remaining);
367 if(r <= 0)
368 return 0;
369
370 sock->size+=r;
371 lastpos = sock->buf;
372
373 for(c=sock->buf,i=0;i<sock->size;i++,c++) {
374 if(*c != '\n')
375 continue;
376 *c = '\0';
377 if(!handletrustline(sock, lastpos))
378 return 0;
379
380 lastpos = c + 1; /* is this ok? */
381 }
382 sock->size-=lastpos - sock->buf;
383 memmove(sock->buf, lastpos, sock->size);
384
385 return 1;
386 }
387
388 static void processtrustclient(int fd, short events) {
389 trustsocket *sock = findtrustsocketbyfd(fd);
390
391 if(!sock)
392 return;
393
394 if (events & (POLLPRI | POLLERR | POLLHUP | POLLNVAL)) {
395 trustfreeconnection(sock, 1);
396 return;
397 }
398
399 if(events & POLLIN)
400 if(!handletrustclient(sock))
401 trustfreeconnection(sock, 1);
402 }
403
404 static void trustdotimeout(void *arg) {
405 time_t t = time(NULL);
406 trustsocket **pnext, *sock;
407
408 for(pnext=&tslist;*pnext;pnext=&((*pnext)->next)) {
409 sock = *pnext;
410 if(!sock->authed && t >= sock->timeout) {
411 trustkillconnection(sock, "Auth timeout.");
412 *pnext = sock->next;
413 trustfreeconnection(sock, 0);
414 }
415 }
416 }
417
418 static void processtrustlistener(int fd, short events) {
419 if(events & POLLIN) {
420 trustsocket *sock;
421 char buf[NONCELEN * 2 + 1];
422 int optval;
423
424 int newfd = accept(fd, NULL, NULL), flags;
425 if(newfd == -1)
426 return;
427
428 flags = fcntl(newfd, F_GETFL, 0);
429 if(flags < 0) {
430 Error("trusts_policy", ERR_WARNING, "Unable to set socket non-blocking.");
431 close(newfd);
432 return;
433 }
434
435 if(fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0) {
436 Error("trusts_policy", ERR_WARNING, "Unable to set socket non-blocking.");
437 close(newfd);
438 return;
439 }
440
441 optval = 1;
442 setsockopt(newfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
443 optval = 10;
444 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
445 optval = 3;
446 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
447 optval = 10;
448 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
449
450 registerhandler(newfd, POLLIN|POLLERR|POLLHUP, processtrustclient);
451
452 sock = nsmalloc(POOL_TRUSTS, sizeof(trustsocket));
453 if(!sock) {
454 deregisterhandler(newfd, 1);
455 return;
456 }
457
458 sock->fd = newfd;
459 sock->next = tslist;
460 tslist = sock;
461
462 if(fread((char *)sock->nonce, 1, NONCELEN, urandom) != NONCELEN) {
463 Error("trusts_policy", ERR_WARNING, "Error getting random bytes.");
464 deregisterhandler(newfd, 1);
465 tslist = sock->next;
466 nsfree(POOL_TRUSTS, sock);
467 } else {
468 sock->authed = 0;
469 sock->size = 0;
470 sock->connected = time(NULL);
471 sock->timeout = time(NULL) + 30;
472 sock->accepted = 0;
473 sock->rejected = 0;
474 sock->unthrottled = 0;
475 if(!trustdowrite(sock, "AUTH %s", hmac_printhex(sock->nonce, buf, NONCELEN))) {
476 Error("trusts_policy", ERR_WARNING, "Error writing auth to fd %d.", newfd);
477 deregisterhandler(newfd, 1);
478 tslist = sock->next;
479 nsfree(POOL_TRUSTS, sock);
480 return;
481 }
482 }
483 }
484 }
485
486 static int createlistenersock(int port) {
487 struct sockaddr_in s;
488 int fd;
489 int optval;
490
491 memset(&s, 0, sizeof(struct sockaddr_in));
492 s.sin_family = AF_INET;
493 s.sin_addr.s_addr = INADDR_ANY;
494 s.sin_port = htons(port);
495
496 fd = socket(PF_INET, SOCK_STREAM, 0);
497 if(fd < 0) {
498 Error("trusts_policy", ERR_WARNING, "Unable to get socket for trustfd.");
499 return -1;
500 }
501
502 optval = 1;
503 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
504
505 if(bind(fd, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0) {
506 Error("trusts_policy", ERR_WARNING, "Unable to bind trustfd.");
507 close(fd);
508 return -1;
509 }
510
511 if(listen(fd, 5) < 0) {
512 Error("trusts_policy", ERR_WARNING, "Unable to listen on trustfd.");
513 close(fd);
514 return -1;
515 }
516
517 registerhandler(fd, POLLIN, processtrustlistener);
518
519 return fd;
520 }
521
522 static void policycheck_irc(int hooknum, void *arg) {
523 void **args = arg;
524 nick *np = args[0];
525 long moving = (long)args[1];
526 char message[512];
527 int verdict, unthrottle;
528
529 if(moving)
530 return;
531
532 verdict = checkconnection(np->ident, &np->ipaddress, hooknum, 0, message, sizeof(message), &unthrottle);
533
534 if(!enforcepolicy_irc)
535 verdict = POLICY_SUCCESS;
536
537 switch (verdict) {
538 case POLICY_FAILURE_NODECOUNT:
539 glinebynick(np, POLICY_GLINE_DURATION, message, GLINE_IGNORE_TRUST, "trusts_policy");
540 break;
541 case POLICY_FAILURE_IDENTD:
542 glinebyip("~*", &np->ipaddress, 128, POLICY_GLINE_DURATION, message, GLINE_ALWAYS_USER|GLINE_IGNORE_TRUST, "trusts_policy");
543 break;
544 case POLICY_FAILURE_IDENTCOUNT:
545 glinebynick(np, POLICY_GLINE_DURATION, message, GLINE_ALWAYS_USER|GLINE_IGNORE_TRUST, "trusts_policy");
546 break;
547 }
548
549 }
550
551 static int trusts_cmdtrustpolicyirc(void *source, int cargc, char **cargv) {
552 nick *sender = source;
553
554 if(cargc < 1) {
555 controlreply(sender, "Use of glines for trust policy enforcement is currently %s.", enforcepolicy_irc?"enabled":"disabled");
556 return CMD_OK;
557 }
558
559 enforcepolicy_irc = atoi(cargv[0]);
560 controlwall(NO_OPER, NL_TRUSTS, "%s %s use of glines for trust policy enforcement.", controlid(sender), enforcepolicy_irc?"enabled":"disabled");
561 controlreply(sender, "Use of glines for trust policy enforcement is now %s.", enforcepolicy_irc?"enabled":"disabled");
562
563 return CMD_OK;
564 }
565
566 static int trusts_cmdtrustpolicyauth(void *source, int cargc, char **cargv) {
567 nick *sender = source;
568
569 if(cargc < 1) {
570 controlreply(sender, "Trust policy enforcement with IAuth is currently %s.", enforcepolicy_auth?"enabled":"disabled");
571 return CMD_OK;
572 }
573
574 enforcepolicy_auth = atoi(cargv[0]);
575 controlwall(NO_OPER, NL_TRUSTS, "%s %s trust policy enforcement with IAuth.", controlid(sender), enforcepolicy_auth?"enabled":"disabled");
576 controlreply(sender, "Trust policy enforcement with IAuth is now %s.", enforcepolicy_auth?"enabled":"disabled");
577
578 return CMD_OK;
579 }
580
581
582 static int trusts_cmdtrustsockets(void *source, int cargc, char **cargv) {
583 nick *sender = source;
584 time_t now;
585 trustsocket *sock;
586
587 time(&now);
588
589 controlreply(sender, "Server Connected for Accepted Rejected Unthrottled");
590
591 for(sock=tslist;sock;sock=sock->next)
592 controlreply(sender, "%-35s %-20s %-15d %-15d %-15d", sock->authed?sock->authuser:"<unauthenticated connection>", longtoduration(now - sock->connected, 0), sock->accepted, sock->rejected, sock->unthrottled);
593
594 controlreply(sender, "-- End of list.");
595 return CMD_OK;
596 }
597
598 void loadtrustaccounts(void) {
599 array *accts;
600
601 memset(trustaccounts, 0, sizeof(trustaccounts));
602
603 accts = getconfigitems("trusts_policy", "server");
604 if(!accts) {
605 Error("trusts_policy", ERR_INFO, "No servers added.");
606 } else {
607 sstring **servers = (sstring **)(accts->content);
608 int i;
609 for(i=0;i<accts->cursi;i++) {
610 char server[512];
611 char *pos;
612
613 if(i>=MAXSERVERS) {
614 Error("trusts_policy", ERR_INFO, "Too many servers specified.");
615 break;
616 }
617
618 strncpy(server, servers[i]->content, sizeof(server));
619
620 pos = strchr(server, ',');
621
622 if(!pos) {
623 Error("trusts_policy", ERR_INFO, "Server line is missing password: %s", server);
624 continue;
625 }
626
627 *pos = '\0';
628
629 trustaccounts[i].used = 1;
630 strncpy(trustaccounts[i].server, server, SERVERLEN);
631 strncpy(trustaccounts[i].password, pos+1, TRUSTPASSLEN);
632 }
633 }
634 }
635
636 static void trustaccounts_rehash(int hooknum, void *arg) {
637 loadtrustaccounts();
638 }
639
640 void _init(void) {
641 sstring *m;
642 int trustport;
643
644 countext = registertgext("count");
645 if(countext == -1)
646 return;
647
648 m = getconfigitem("trusts_policy", "enforcepolicy_irc");
649 if(m)
650 enforcepolicy_irc = atoi(m->content);
651
652 m = getconfigitem("trusts_policy", "enforcepolicy_auth");
653 if(m)
654 enforcepolicy_auth = atoi(m->content);
655
656 m = getconfigitem("trusts_policy", "trustport");
657 if(m)
658 trustport = atoi(m->content);
659 else
660 trustport = DEFAULT_TRUSTPORT;
661
662 if(trustport)
663 listenerfd = createlistenersock(trustport);
664
665 loadtrustaccounts();
666
667 registerhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
668 registerhook(HOOK_TRUSTS_LOSTNICK, &policycheck_irc);
669 registerhook(HOOK_CORE_REHASH, trustaccounts_rehash);
670
671 registercontrolhelpcmd("trustpolicyirc", NO_DEVELOPER, 1, trusts_cmdtrustpolicyirc, "Usage: trustpolicyirc ?1|0?\nEnables or disables policy enforcement (IRC). Shows current status when no parameter is specified.");
672 registercontrolhelpcmd("trustpolicyauth", NO_DEVELOPER, 1, trusts_cmdtrustpolicyauth, "Usage: trustpolicyauth ?1|0?\nEnables or disables policy enforcement (IAuth). Shows current status when no parameter is specified.");
673 registercontrolhelpcmd("trustsockets", NO_DEVELOPER, 0, trusts_cmdtrustsockets, "Usage: trustsockets\nLists all currently active TRUST sockets.");
674
675 schedulerecurring(time(NULL)+1, 0, 5, trustdotimeout, NULL);
676
677 urandom = fopen("/dev/urandom", "rb");
678 if(!urandom)
679 Error("trusts_policy", ERR_ERROR, "Couldn't open /dev/urandom.");
680 }
681
682 void _fini(void) {
683 trustsocket *sock, *next;
684
685 if(countext == -1)
686 return;
687
688 releasetgext(countext);
689
690 deregisterhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
691 deregisterhook(HOOK_TRUSTS_LOSTNICK, policycheck_irc);
692 deregisterhook(HOOK_CORE_REHASH, trustaccounts_rehash);
693
694 deregistercontrolcmd("trustpolicyirc", trusts_cmdtrustpolicyirc);
695 deregistercontrolcmd("trustpolicyauth", trusts_cmdtrustpolicyauth);
696 deregistercontrolcmd("trustsockets", trusts_cmdtrustsockets);
697
698 deleteallschedules(trustdotimeout);
699
700 if (urandom)
701 fclose(urandom);
702
703 if (listenerfd != -1)
704 deregisterhandler(listenerfd, 1);
705
706 for(sock=tslist;sock;) {
707 next = sock->next;
708
709 trustkillconnection(sock, "Unloading module.");
710 trustfreeconnection(sock, 0);
711
712 sock = next;
713 }
714 }