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