]> jfr.im git - irc/quakenet/newserv.git/blame - trusts/trusts_policy.c
GLINES: fix null pointer deref in trustgline / trustungline
[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>
04b5f116 8#include <netinet/tcp.h>
543c86ce
GB
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
c4610da5 20#include "../lib/version.h"
543c86ce
GB
21#include "../lib/hmac.h"
22#include "../core/events.h"
23#include "../core/schedule.h"
24#include "../core/nsmalloc.h"
cfe0e8e4 25#include "../core/hooks.h"
1961b117 26#include "../core/config.h"
cfe0e8e4 27#include "../control/control.h"
148db7b8 28#include "../lib/irc_string.h"
1961b117 29#include "../irc/irc.h"
a473a1be 30#include "../glines/glines.h"
0444dc16 31#include "../patricianick/patricianick.h"
cfe0e8e4
CP
32#include "trusts.h"
33
c4610da5
GB
34MODULE_VERSION("");
35
b3a88c21 36static int countext, enforcepolicy_irc, enforcepolicy_auth;
2129448c 37
543c86ce
GB
38#define TRUSTBUFSIZE 8192
39#define TRUSTPASSLEN 128
40#define NONCELEN 16
cfe0e8e4 41
543c86ce
GB
42typedef struct trustsocket {
43 int fd;
6a7133c8
GB
44 int authed;
45 char authuser[SERVERLEN+1];
543c86ce
GB
46 char buf[TRUSTBUFSIZE];
47 unsigned char nonce[NONCELEN];
48 int size;
6a7133c8 49 time_t connected;
543c86ce 50 time_t timeout;
6a7133c8
GB
51 int accepted;
52 int rejected;
08619b6d 53 int unthrottled;
543c86ce
GB
54
55 struct trustsocket *next;
56} trustsocket;
9097ab05 57
543c86ce 58static trustsocket *tslist;
6a7133c8 59static int listenerfd = -1;
543c86ce
GB
60static FILE *urandom;
61
62typedef struct trustaccount {
63 int used;
64 char server[SERVERLEN+1];
65 char password[TRUSTPASSLEN+1];
66} trustaccount;
67
68trustaccount trustaccounts[MAXSERVERS];
69
0444dc16
GB
70static int checkconnection(const char *username, struct irc_in_addr *ipaddress, int hooknum, int usercountadjustment, char *message, size_t messagelen, int *unthrottle) {
71 trusthost *th;
543c86ce 72 trustgroup *tg;
0444dc16
GB
73 struct irc_in_addr ipaddress_canonical;
74
75 ip_canonicalize_tunnel(&ipaddress_canonical, ipaddress);
76
77 th = th_getbyhost(&ipaddress_canonical);
543c86ce 78
4b40d278
GB
79 if (unthrottle)
80 *unthrottle = 0;
81
543c86ce
GB
82 if(messagelen>0)
83 message[0] = '\0';
84
0444dc16 85 if(!th || !trustsdbloaded || irc_in_addr_is_loopback(ipaddress))
543c86ce 86 return POLICY_SUCCESS;
cebc4cab 87
6e6e98da
GB
88 tg = th->group;
89
2129448c
CP
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) {
0444dc16
GB
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;
afe99911 117
0444dc16 118 derefnode(iptree, head);
afe99911 119
6ca057fd 120 if(th->maxpernode && nodecount + usercountadjustment > th->maxpernode) {
0444dc16
GB
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));
543c86ce 123 return POLICY_FAILURE_NODECOUNT;
afe99911
GB
124 }
125
6ca057fd 126 if(tg->trustedfor && tg->count + usercountadjustment > tg->trustedfor) {
2129448c
CP
127 if(tg->count > (long)tg->exts[countext]) {
128 tg->exts[countext] = (void *)(long)tg->count;
afe99911 129
639d4165 130 controlwall(NO_OPER, NL_CLONING, "Hard connection limit exceeded (group %s): %d connected, %d max.", tg->name->content, tg->count + usercountadjustment, tg->trustedfor);
0444dc16 131 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
148db7b8 132 }
61e5ea0a 133
0444dc16 134 snprintf(message, messagelen, "Too many connections from your trust (%s) - see https://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ipaddress));
61e5ea0a 135 return POLICY_FAILURE_GROUPCOUNT;
148db7b8 136 }
afe99911 137
543c86ce 138 if((tg->flags & TRUST_ENFORCE_IDENT) && (username[0] == '~')) {
0444dc16
GB
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));
543c86ce 141 return POLICY_FAILURE_IDENTD;
1961b117
GB
142 }
143
148db7b8
CP
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)) {
543c86ce 151 if(!ircd_strcmp(tnp->ident, username))
148db7b8
CP
152 identcount++;
153 }
2129448c 154 }
148db7b8 155
6ca057fd 156 if(identcount + usercountadjustment > tg->maxperident) {
0444dc16
GB
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));
543c86ce 159 return POLICY_FAILURE_IDENTCOUNT;
1961b117 160 }
2129448c
CP
161 }
162 } else {
163 if(tg->count < tg->maxusage)
164 tg->exts[countext] = (void *)(long)tg->count;
165 }
543c86ce 166
61e5ea0a
GB
167 if(tg->trustedfor > 0)
168 snprintf(message, messagelen, "Trust has %d out of %d allowed connections.", tg->count + usercountadjustment, tg->trustedfor);
169
4b40d278 170 if(unthrottle && (tg->flags & TRUST_UNTHROTTLE))
08619b6d 171 *unthrottle = 1;
543c86ce 172
4b40d278 173 return POLICY_SUCCESS;
543c86ce
GB
174}
175
176static 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
195static int policycheck_auth(trustsocket *sock, const char *sequence_id, const char *username, const char *host) {
196 char message[512];
4b40d278 197 int verdict, unthrottle;
0444dc16 198 struct irc_in_addr ipaddress;
543c86ce 199 unsigned char bits;
08619b6d 200
0444dc16 201 if(!ipmask_parse(host, &ipaddress, &bits)) {
6a7133c8 202 sock->accepted++;
543c86ce 203 return trustdowrite(sock, "PASS %s", sequence_id);
6a7133c8 204 }
4b40d278 205
0444dc16 206 verdict = checkconnection(username, &ipaddress, HOOK_TRUSTS_NEWNICK, 1, message, sizeof(message), &unthrottle);
543c86ce 207
b3a88c21
GB
208 if(!enforcepolicy_auth)
209 verdict = POLICY_SUCCESS;
210
543c86ce 211 if (verdict == POLICY_SUCCESS) {
6a7133c8
GB
212 sock->accepted++;
213
4b40d278 214 if (unthrottle) {
08619b6d
TS
215 sock->unthrottled++;
216 trustdowrite(sock, "UNTHROTTLE %s", sequence_id);
4b40d278
GB
217 }
218
543c86ce
GB
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 {
6a7133c8
GB
224 sock->rejected++;
225
639d4165 226 controlwall(NO_OPER, NL_CLONING, "Rejected connection from %s@%s using IAuth: %s", username, host, message);
543c86ce
GB
227 return trustdowrite(sock, "KILL %s %s", sequence_id, message);
228 }
229}
230
231static int trustkillconnection(trustsocket *sock, char *reason) {
232 trustdowrite(sock, "QUIT %s", reason);
233 return 0;
234}
235
0bd28986 236static void trustfreeconnection(trustsocket *sock, int unlink) {
84978a27 237 trustsocket **pnext, *ts;
0bd28986
GB
238
239 if(!unlink) {
39a628b3
GB
240 controlwall(NO_OPER, NL_TRUSTS, "Lost connection on policy socket for '%s'.", sock->authed?sock->authuser:"<unauthenticated connection>");
241
0bd28986
GB
242 deregisterhandler(sock->fd, 1);
243 nsfree(POOL_TRUSTS, sock);
244 return;
245 }
246
cb2e40cf
GB
247 for(pnext=&tslist;*pnext;pnext=&((*pnext)->next)) {
248 ts=*pnext;
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];
cb2e40cf 263 trustsocket *ts, **pnext;
543c86ce
GB
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
427f6077
GB
272 if (!password) {
273 controlwall(NO_OPER, NL_TRUSTS, "Invalid servername for policy socket: '%s'", server_name);
543c86ce 274 return trustkillconnection(sock, "Invalid servername.");
427f6077 275 }
543c86ce
GB
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);
427f6077
GB
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);
543c86ce 283 return trustkillconnection(sock, "Bad MAC.");
427f6077 284 }
543c86ce 285
cb2e40cf
GB
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
6a7133c8
GB
296 sock->authed = 1;
297 strncpy(sock->authuser, server_name, SERVERLEN);
427f6077
GB
298
299 controlwall(NO_OPER, NL_TRUSTS, "Successful authentication for policy socket with servername '%s'.", server_name);
543c86ce
GB
300 return trustdowrite(sock, "AUTHOK");
301}
302
303#define MAXTOKENS 10
304static 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
6a7133c8 329 if(!sock->authed && !strcmp("AUTH", command)) {
543c86ce
GB
330 if(tokensfound != 2)
331 return trustkillconnection(sock, "incorrect arg count for command.");
332
333 return handletrustauth(sock, tokens[0], tokens[1]);
6a7133c8 334 } else if(sock->authed && !strcmp("CHECK", command)) {
543c86ce
GB
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;
61b0c595
GB
340 } else if(!strcmp("VERSION", command)) {
341 /* Ignore this command for now. */
342 return 1;
543c86ce
GB
343 } else {
344 Error("trusts_policy", ERR_WARNING, "Bad command: %s", command);
345 return 0;
346 }
347}
348
349static 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
357static 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
388static void processtrustclient(int fd, short events) {
389 trustsocket *sock = findtrustsocketbyfd(fd);
390
391 if(!sock)
392 return;
8e8e611b
GB
393
394 if (events & (POLLPRI | POLLERR | POLLHUP | POLLNVAL)) {
395 trustfreeconnection(sock, 1);
396 return;
397 }
398
543c86ce
GB
399 if(events & POLLIN)
400 if(!handletrustclient(sock))
0bd28986 401 trustfreeconnection(sock, 1);
543c86ce
GB
402}
403
404static void trustdotimeout(void *arg) {
405 time_t t = time(NULL);
56c707b6 406 trustsocket **pnext, *sock;
543c86ce 407
cb2e40cf
GB
408 for(pnext=&tslist;*pnext;pnext=&((*pnext)->next)) {
409 sock = *pnext;
6a7133c8 410 if(!sock->authed && t >= sock->timeout) {
543c86ce 411 trustkillconnection(sock, "Auth timeout.");
543c86ce 412 *pnext = sock->next;
0bd28986 413 trustfreeconnection(sock, 0);
543c86ce 414 }
543c86ce
GB
415 }
416}
417
418static void processtrustlistener(int fd, short events) {
419 if(events & POLLIN) {
420 trustsocket *sock;
421 char buf[NONCELEN * 2 + 1];
04b5f116 422 int optval;
543c86ce
GB
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
0d6366b6
CP
441 optval = 1;
442 setsockopt(newfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
04b5f116 443 optval = 10;
0d6366b6 444 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
04b5f116 445 optval = 3;
0d6366b6 446 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
04b5f116 447 optval = 10;
0d6366b6 448 setsockopt(newfd, IPPROTO_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
04b5f116 449
543c86ce
GB
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 {
6a7133c8 468 sock->authed = 0;
543c86ce 469 sock->size = 0;
6a7133c8 470 sock->connected = time(NULL);
543c86ce 471 sock->timeout = time(NULL) + 30;
6a7133c8
GB
472 sock->accepted = 0;
473 sock->rejected = 0;
08619b6d 474 sock->unthrottled = 0;
543c86ce
GB
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
486static 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
522static 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];
ceb2a8bc 527 int verdict, unthrottle;
543c86ce
GB
528
529 if(moving)
530 return;
531
0444dc16 532 verdict = checkconnection(np->ident, &np->ipaddress, hooknum, 0, message, sizeof(message), &unthrottle);
543c86ce 533
b3a88c21
GB
534 if(!enforcepolicy_irc)
535 verdict = POLICY_SUCCESS;
3c5c26a8 536
543c86ce
GB
537 switch (verdict) {
538 case POLICY_FAILURE_NODECOUNT:
3c5c26a8 539 glinebynick(np, POLICY_GLINE_DURATION, message, GLINE_IGNORE_TRUST, "trusts_policy");
543c86ce
GB
540 break;
541 case POLICY_FAILURE_IDENTD:
fdcb5d66 542 glinebyip("~*", &np->ipaddress, 128, POLICY_GLINE_DURATION, message, GLINE_ALWAYS_USER|GLINE_IGNORE_TRUST, "trusts_policy");
543c86ce
GB
543 break;
544 case POLICY_FAILURE_IDENTCOUNT:
3c5c26a8 545 glinebynick(np, POLICY_GLINE_DURATION, message, GLINE_ALWAYS_USER|GLINE_IGNORE_TRUST, "trusts_policy");
543c86ce
GB
546 break;
547 }
ceb2a8bc 548
cfe0e8e4
CP
549}
550
b3a88c21 551static int trusts_cmdtrustpolicyirc(void *source, int cargc, char **cargv) {
24954f63
GB
552 nick *sender = source;
553
554 if(cargc < 1) {
b3a88c21 555 controlreply(sender, "Use of glines for trust policy enforcement is currently %s.", enforcepolicy_irc?"enabled":"disabled");
24954f63
GB
556 return CMD_OK;
557 }
558
b3a88c21
GB
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");
24954f63
GB
562
563 return CMD_OK;
564}
565
b3a88c21
GB
566static 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
6a7133c8
GB
582static 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
08619b6d 589 controlreply(sender, "Server Connected for Accepted Rejected Unthrottled");
6a7133c8
GB
590
591 for(sock=tslist;sock;sock=sock->next)
08619b6d 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);
6a7133c8
GB
593
594 controlreply(sender, "-- End of list.");
595 return CMD_OK;
596}
597
427f6077 598void loadtrustaccounts(void) {
543c86ce 599 array *accts;
3affe49a 600
427f6077 601 memset(trustaccounts, 0, sizeof(trustaccounts));
543c86ce
GB
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 }
427f6077 617
543c86ce 618 strncpy(server, servers[i]->content, sizeof(server));
427f6077 619
543c86ce 620 pos = strchr(server, ',');
427f6077 621
543c86ce
GB
622 if(!pos) {
623 Error("trusts_policy", ERR_INFO, "Server line is missing password: %s", server);
624 continue;
625 }
427f6077 626
543c86ce 627 *pos = '\0';
427f6077 628
543c86ce
GB
629 trustaccounts[i].used = 1;
630 strncpy(trustaccounts[i].server, server, SERVERLEN);
631 strncpy(trustaccounts[i].password, pos+1, TRUSTPASSLEN);
632 }
633 }
427f6077
GB
634}
635
636static void trustaccounts_rehash(int hooknum, void *arg) {
637 loadtrustaccounts();
638}
639
640void _init(void) {
641 sstring *m;
642 int trustport;
643
644 countext = registertgext("count");
645 if(countext == -1)
646 return;
647
b3a88c21
GB
648 m = getconfigitem("trusts_policy", "enforcepolicy_irc");
649 if(m)
650 enforcepolicy_irc = atoi(m->content);
651
652 m = getconfigitem("trusts_policy", "enforcepolicy_auth");
427f6077 653 if(m)
b3a88c21 654 enforcepolicy_auth = atoi(m->content);
427f6077
GB
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
543c86ce 667 registerhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
427f6077
GB
668 registerhook(HOOK_TRUSTS_LOSTNICK, &policycheck_irc);
669 registerhook(HOOK_CORE_REHASH, trustaccounts_rehash);
24954f63 670
b3a88c21
GB
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.");
6a7133c8 673 registercontrolhelpcmd("trustsockets", NO_DEVELOPER, 0, trusts_cmdtrustsockets, "Usage: trustsockets\nLists all currently active TRUST sockets.");
543c86ce
GB
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.");
cfe0e8e4
CP
680}
681
682void _fini(void) {
6a7133c8
GB
683 trustsocket *sock, *next;
684
2129448c
CP
685 if(countext == -1)
686 return;
687
688 releasetgext(countext);
689
543c86ce
GB
690 deregisterhook(HOOK_TRUSTS_NEWNICK, policycheck_irc);
691 deregisterhook(HOOK_TRUSTS_LOSTNICK, policycheck_irc);
427f6077 692 deregisterhook(HOOK_CORE_REHASH, trustaccounts_rehash);
24954f63 693
b3a88c21
GB
694 deregistercontrolcmd("trustpolicyirc", trusts_cmdtrustpolicyirc);
695 deregistercontrolcmd("trustpolicyauth", trusts_cmdtrustpolicyauth);
6a7133c8 696 deregistercontrolcmd("trustsockets", trusts_cmdtrustsockets);
543c86ce 697
6a7133c8
GB
698 deleteallschedules(trustdotimeout);
699
543c86ce
GB
700 if (urandom)
701 fclose(urandom);
6a7133c8
GB
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.");
0bd28986 710 trustfreeconnection(sock, 0);
6a7133c8
GB
711
712 sock = next;
713 }
cfe0e8e4 714}