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