]> jfr.im git - irc/quakenet/newserv.git/blob - trusts/trusts_policy.c
trusts_policy: Fix handling socket timeouts and disconnects.
[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
53 struct trustsocket *next;
54 } trustsocket;
55
56 static trustsocket *tslist;
57 static int listenerfd = -1;
58 static FILE *urandom;
59
60 typedef struct trustaccount {
61 int used;
62 char server[SERVERLEN+1];
63 char password[TRUSTPASSLEN+1];
64 } trustaccount;
65
66 trustaccount trustaccounts[MAXSERVERS];
67
68 static int checkconnection(const char *username, struct irc_in_addr *ipaddress, int hooknum, int usercountadjustment, char *message, size_t messagelen, int *unthrottle) {
69 trusthost *th;
70 trustgroup *tg;
71 struct irc_in_addr ipaddress_canonical;
72
73 ip_canonicalize_tunnel(&ipaddress_canonical, ipaddress);
74
75 th = th_getbyhost(&ipaddress_canonical);
76
77 if (unthrottle)
78 *unthrottle = 0;
79
80 if(messagelen>0)
81 message[0] = '\0';
82
83 if(!th || !trustsdbloaded || irc_in_addr_is_loopback(ipaddress))
84 return POLICY_SUCCESS;
85
86 tg = th->group;
87
88 /*
89 * the purpose of this logic is to avoid spam like this:
90 * WARNING: tgX exceeded limit: 11 connected vs 10 max
91 * (goes back down to 10)
92 * WARNING: tgX exceeded limit: 11 connected vs 10 max
93 */
94
95 if(hooknum == HOOK_TRUSTS_NEWNICK) {
96 patricia_node_t *head, *node;
97 int i, nodecount = 0;
98 patricianick_t *pnp;
99 nick *npp;
100
101 head = refnode(iptree, &ipaddress_canonical, th->nodebits);
102 nodecount = head->usercount;
103
104 /* Account for borrowed IP addresses. */
105 PATRICIA_WALK(head, node) {
106 pnp = node->exts[pnode_ext];
107
108 if (pnp)
109 for (i = 0; i < PATRICIANICK_HASHSIZE; i++)
110 for (npp = pnp->identhash[i]; npp; npp=npp->exts[pnick_ext])
111 if (NickOnServiceServer(npp))
112 usercountadjustment--;
113 }
114 PATRICIA_WALK_END;
115
116 derefnode(iptree, head);
117
118 if(th->maxpernode && nodecount + usercountadjustment > th->maxpernode) {
119 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);
120 snprintf(message, messagelen, "Too many connections from your host (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
121 return POLICY_FAILURE_NODECOUNT;
122 }
123
124 if(tg->trustedfor && tg->count + usercountadjustment > tg->trustedfor) {
125 if(tg->count > (long)tg->exts[countext]) {
126 tg->exts[countext] = (void *)(long)tg->count;
127
128 controlwall(NO_OPER, NL_CLONING, "Hard connection limit exceeded (group %s): %d connected, %d max.", tg->name->content, tg->count + usercountadjustment, tg->trustedfor);
129 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
130 }
131
132 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
133 return POLICY_FAILURE_GROUPCOUNT;
134 }
135
136 if((tg->flags & TRUST_ENFORCE_IDENT) && (username[0] == '~')) {
137 controlwall(NO_OPER, NL_CLONING, "Ident required: %s@%s (group: %s).", username, IPtostr(*ipaddress), tg->name->content);
138 snprintf(message, messagelen, "IDENTD required from your host (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
139 return POLICY_FAILURE_IDENTD;
140 }
141
142 if(tg->maxperident > 0) {
143 int identcount = 0;
144 trusthost *th2;
145 nick *tnp;
146
147 for(th2=tg->hosts;th2;th2=th2->next) {
148 for(tnp=th2->users;tnp;tnp=nextbytrust(tnp)) {
149 if(!ircd_strcmp(tnp->ident, username))
150 identcount++;
151 }
152 }
153
154 if(identcount + usercountadjustment > tg->maxperident) {
155 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);
156 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));
157 return POLICY_FAILURE_IDENTCOUNT;
158 }
159 }
160 } else {
161 if(tg->count < tg->maxusage)
162 tg->exts[countext] = (void *)(long)tg->count;
163 }
164
165 if(tg->trustedfor > 0)
166 snprintf(message, messagelen, "Trust has %d out of %d allowed connections.", tg->count + usercountadjustment, tg->trustedfor);
167
168 if(unthrottle && (tg->flags & TRUST_UNTHROTTLE))
169 *unthrottle = 1; /* TODO: Do _some_ kind of rate-limiting */
170
171 return POLICY_SUCCESS;
172 }
173
174 static int trustdowrite(trustsocket *sock, char *format, ...) {
175 char buf[1024];
176 va_list va;
177 int r;
178
179 va_start(va, format);
180 r = vsnprintf(buf, sizeof(buf), format, va);
181 va_end(va);
182
183 if(r >= sizeof(buf))
184 r = sizeof(buf) - 1;
185
186 buf[r] = '\n';
187
188 if(write(sock->fd, buf, r + 1) != r + 1)
189 return 0;
190 return 1;
191 }
192
193 static int policycheck_auth(trustsocket *sock, const char *sequence_id, const char *username, const char *host) {
194 char message[512];
195 int verdict, unthrottle;
196 struct irc_in_addr ipaddress;
197 unsigned char bits;
198 trustsocket *ts;
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 for (ts = tslist; ts; ts = ts->next)
215 trustdowrite(ts, "UNTHROTTLE %s", IPtostr(ipaddress));
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 if(!trustdowrite(sock, "AUTH %s", hmac_printhex(sock->nonce, buf, NONCELEN))) {
464 Error("trusts_policy", ERR_WARNING, "Error writing auth to fd %d.", newfd);
465 deregisterhandler(newfd, 1);
466 tslist = sock->next;
467 nsfree(POOL_TRUSTS, sock);
468 return;
469 }
470 }
471 }
472 }
473
474 static int createlistenersock(int port) {
475 struct sockaddr_in s;
476 int fd;
477 int optval;
478
479 memset(&s, 0, sizeof(struct sockaddr_in));
480 s.sin_family = AF_INET;
481 s.sin_addr.s_addr = INADDR_ANY;
482 s.sin_port = htons(port);
483
484 fd = socket(PF_INET, SOCK_STREAM, 0);
485 if(fd < 0) {
486 Error("trusts_policy", ERR_WARNING, "Unable to get socket for trustfd.");
487 return -1;
488 }
489
490 optval = 1;
491 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
492
493 if(bind(fd, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0) {
494 Error("trusts_policy", ERR_WARNING, "Unable to bind trustfd.");
495 close(fd);
496 return -1;
497 }
498
499 if(listen(fd, 5) < 0) {
500 Error("trusts_policy", ERR_WARNING, "Unable to listen on trustfd.");
501 close(fd);
502 return -1;
503 }
504
505 registerhandler(fd, POLLIN, processtrustlistener);
506
507 return fd;
508 }
509
510 static void policycheck_irc(int hooknum, void *arg) {
511 void **args = arg;
512 nick *np = args[0];
513 long moving = (long)args[1];
514 char message[512];
515 int verdict, unthrottle;
516 trustsocket *ts;
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 if (unthrottle && hooknum == HOOK_NICK_LOSTNICK && np->timestamp > getnettime() - TRUST_MIN_TIME_RETHROTTLE) {
539 for (ts = tslist; ts; ts = ts->next)
540 trustdowrite(ts, "THROTTLE %s", IPtostr(np->ipaddress));
541 }
542 }
543
544 static int trusts_cmdtrustpolicyirc(void *source, int cargc, char **cargv) {
545 nick *sender = source;
546
547 if(cargc < 1) {
548 controlreply(sender, "Use of glines for trust policy enforcement is currently %s.", enforcepolicy_irc?"enabled":"disabled");
549 return CMD_OK;
550 }
551
552 enforcepolicy_irc = atoi(cargv[0]);
553 controlwall(NO_OPER, NL_TRUSTS, "%s %s use of glines for trust policy enforcement.", controlid(sender), enforcepolicy_irc?"enabled":"disabled");
554 controlreply(sender, "Use of glines for trust policy enforcement is now %s.", enforcepolicy_irc?"enabled":"disabled");
555
556 return CMD_OK;
557 }
558
559 static int trusts_cmdtrustpolicyauth(void *source, int cargc, char **cargv) {
560 nick *sender = source;
561
562 if(cargc < 1) {
563 controlreply(sender, "Trust policy enforcement with IAuth is currently %s.", enforcepolicy_auth?"enabled":"disabled");
564 return CMD_OK;
565 }
566
567 enforcepolicy_auth = atoi(cargv[0]);
568 controlwall(NO_OPER, NL_TRUSTS, "%s %s trust policy enforcement with IAuth.", controlid(sender), enforcepolicy_auth?"enabled":"disabled");
569 controlreply(sender, "Trust policy enforcement with IAuth is now %s.", enforcepolicy_auth?"enabled":"disabled");
570
571 return CMD_OK;
572 }
573
574
575 static int trusts_cmdtrustsockets(void *source, int cargc, char **cargv) {
576 nick *sender = source;
577 time_t now;
578 trustsocket *sock;
579
580 time(&now);
581
582 controlreply(sender, "Server Connected for Accepted Rejected");
583
584 for(sock=tslist;sock;sock=sock->next)
585 controlreply(sender, "%-35s %-20s %-15d %-15d", sock->authed?sock->authuser:"<unauthenticated connection>", longtoduration(now - sock->connected, 0), sock->accepted, sock->rejected);
586
587 controlreply(sender, "-- End of list.");
588 return CMD_OK;
589 }
590
591 void loadtrustaccounts(void) {
592 array *accts;
593
594 memset(trustaccounts, 0, sizeof(trustaccounts));
595
596 accts = getconfigitems("trusts_policy", "server");
597 if(!accts) {
598 Error("trusts_policy", ERR_INFO, "No servers added.");
599 } else {
600 sstring **servers = (sstring **)(accts->content);
601 int i;
602 for(i=0;i<accts->cursi;i++) {
603 char server[512];
604 char *pos;
605
606 if(i>=MAXSERVERS) {
607 Error("trusts_policy", ERR_INFO, "Too many servers specified.");
608 break;
609 }
610
611 strncpy(server, servers[i]->content, sizeof(server));
612
613 pos = strchr(server, ',');
614
615 if(!pos) {
616 Error("trusts_policy", ERR_INFO, "Server line is missing password: %s", server);
617 continue;
618 }
619
620 *pos = '\0';
621
622 trustaccounts[i].used = 1;
623 strncpy(trustaccounts[i].server, server, SERVERLEN);
624 strncpy(trustaccounts[i].password, pos+1, TRUSTPASSLEN);
625 }
626 }
627 }
628
629 static void trustaccounts_rehash(int hooknum, void *arg) {
630 loadtrustaccounts();
631 }
632
633 void _init(void) {
634 sstring *m;
635 int trustport;
636
637 countext = registertgext("count");
638 if(countext == -1)
639 return;
640
641 m = getconfigitem("trusts_policy", "enforcepolicy_irc");
642 if(m)
643 enforcepolicy_irc = atoi(m->content);
644
645 m = getconfigitem("trusts_policy", "enforcepolicy_auth");
646 if(m)
647 enforcepolicy_auth = atoi(m->content);
648
649 m = getconfigitem("trusts_policy", "trustport");
650 if(m)
651 trustport = atoi(m->content);
652 else
653 trustport = DEFAULT_TRUSTPORT;
654
655 if(trustport)
656 listenerfd = createlistenersock(trustport);
657
658 loadtrustaccounts();
659
660 registerhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
661 registerhook(HOOK_TRUSTS_LOSTNICK, &policycheck_irc);
662 registerhook(HOOK_CORE_REHASH, trustaccounts_rehash);
663
664 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.");
665 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.");
666 registercontrolhelpcmd("trustsockets", NO_DEVELOPER, 0, trusts_cmdtrustsockets, "Usage: trustsockets\nLists all currently active TRUST sockets.");
667
668 schedulerecurring(time(NULL)+1, 0, 5, trustdotimeout, NULL);
669
670 urandom = fopen("/dev/urandom", "rb");
671 if(!urandom)
672 Error("trusts_policy", ERR_ERROR, "Couldn't open /dev/urandom.");
673 }
674
675 void _fini(void) {
676 trustsocket *sock, *next;
677
678 if(countext == -1)
679 return;
680
681 releasetgext(countext);
682
683 deregisterhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
684 deregisterhook(HOOK_TRUSTS_LOSTNICK, policycheck_irc);
685 deregisterhook(HOOK_CORE_REHASH, trustaccounts_rehash);
686
687 deregistercontrolcmd("trustpolicyirc", trusts_cmdtrustpolicyirc);
688 deregistercontrolcmd("trustpolicyauth", trusts_cmdtrustpolicyauth);
689 deregistercontrolcmd("trustsockets", trusts_cmdtrustsockets);
690
691 deleteallschedules(trustdotimeout);
692
693 if (urandom)
694 fclose(urandom);
695
696 if (listenerfd != -1)
697 deregisterhandler(listenerfd, 1);
698
699 for(sock=tslist;sock;) {
700 next = sock->next;
701
702 trustkillconnection(sock, "Unloading module.");
703 trustfreeconnection(sock, 0);
704
705 sock = next;
706 }
707 }