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