6 #include <sys/socket.h>
7 #include <netinet/in.h>
10 #define __USE_MISC /* inet_aton */
13 #include <arpa/inet.h>
19 #include "../lib/hmac.h"
20 #include "../core/events.h"
21 #include "../core/schedule.h"
22 #include "../core/nsmalloc.h"
23 #include "../core/hooks.h"
24 #include "../core/config.h"
25 #include "../control/control.h"
26 #include "../lib/irc_string.h"
27 #include "../irc/irc.h"
28 #include "../glines/glines.h"
31 static int countext
, enforcepolicy
;
33 #define TRUSTBUFSIZE 8192
34 #define TRUSTPASSLEN 128
37 #define STATE_UNAUTHED 0
38 #define STATE_AUTHED 1
40 typedef struct trustsocket
{
43 char buf
[TRUSTBUFSIZE
];
44 unsigned char nonce
[NONCELEN
];
48 struct trustsocket
*next
;
51 static trustsocket
*tslist
;
52 static int listenerfd
;
55 typedef struct trustaccount
{
57 char server
[SERVERLEN
+1];
58 char password
[TRUSTPASSLEN
+1];
61 trustaccount trustaccounts
[MAXSERVERS
];
63 static int checkconnectionth(const char *username
, struct irc_in_addr
*ip
, trusthost
*th
, int hooknum
, int usercountadjustment
, char *message
, size_t messagelen
) {
70 return POLICY_SUCCESS
;
75 * the purpose of this logic is to avoid spam like this:
76 * WARNING: tgX exceeded limit: 11 connected vs 10 max
77 * (goes back down to 10)
78 * WARNING: tgX exceeded limit: 11 connected vs 10 max
81 if(hooknum
== HOOK_TRUSTS_NEWNICK
) {
82 patricia_node_t
*head
, *node
;
85 head
= refnode(iptree
, ip
, th
->nodebits
);
86 PATRICIA_WALK(head
, node
)
88 nodecount
+= node
->usercount
;
91 derefnode(iptree
, head
);
93 if(th
->maxpernode
&& nodecount
+ usercountadjustment
> th
->maxpernode
) {
94 controlwall(NO_OPER
, NL_TRUSTS
, "Hard connection limit exceeded on subnet: %s (group: %s) %d connected, %d max - %senforced.", trusts_cidr2str(ip
, th
->nodebits
), tg
->name
->content
, nodecount
, th
->maxpernode
, enforcepolicy
?"":"not ");
95 snprintf(message
, messagelen
, "Too many connections from your host (%s) - see http://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ip
));
96 return POLICY_FAILURE_NODECOUNT
;
99 if(tg
->trustedfor
&& tg
->count
+ usercountadjustment
> tg
->trustedfor
) {
100 if(tg
->count
> (long)tg
->exts
[countext
]) {
101 tg
->exts
[countext
] = (void *)(long)tg
->count
;
103 controlwall(NO_OPER
, NL_TRUSTS
, "Hard connection limit exceeded: '%s', %d connected, %d max.", tg
->name
->content
, tg
->count
, tg
->trustedfor
);
104 snprintf(message
, messagelen
, "Too many connections from your trust (%s) - see http://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ip
));
105 return POLICY_FAILURE_GROUPCOUNT
;
108 snprintf(message
, messagelen
, "Trust has %d out of %d allowed connections.", tg
->count
+ usercountadjustment
, tg
->trustedfor
);
111 if((tg
->flags
& TRUST_ENFORCE_IDENT
) && (username
[0] == '~')) {
112 controlwall(NO_OPER
, NL_TRUSTS
, "Ident required: %s@%s (group: %s) - %senforced.", username
, IPtostr(*ip
), tg
->name
->content
, enforcepolicy
?"":"not ");
113 snprintf(message
, messagelen
, "IDENTD required from your host (%s) - see http://www.quakenet.org/help/trusts/connection-limit for details.", IPtostr(*ip
));
114 return POLICY_FAILURE_IDENTD
;
117 if(tg
->maxperident
> 0) {
122 for(th2
=tg
->hosts
;th2
;th2
=th2
->next
) {
123 for(tnp
=th2
->users
;tnp
;tnp
=nextbytrust(tnp
)) {
124 if(!ircd_strcmp(tnp
->ident
, username
))
129 if(identcount
+ usercountadjustment
> tg
->maxperident
) {
130 controlwall(NO_OPER
, NL_TRUSTS
, "Hard ident limit exceeded: %s@%s (group: %s), %d connected, %d max - %senforced.", username
, IPtostr(*ip
), tg
->name
->content
, identcount
, tg
->maxperident
, enforcepolicy
?"":"not ");
131 snprintf(message
, messagelen
, "Too many connections from your username (%s@%s) - see http://www.quakenet.org/help/trusts/connection-limit for details.", username
, IPtostr(*ip
));
132 return POLICY_FAILURE_IDENTCOUNT
;
136 if(tg
->count
< tg
->maxusage
)
137 tg
->exts
[countext
] = (void *)(long)tg
->count
;
140 return POLICY_SUCCESS
;
143 static int checkconnection(const char *username
, struct irc_in_addr
*ip
, int hooknum
, int cloneadjustment
, char *message
, size_t messagelen
) {
144 struct irc_in_addr ip_canonicalized
;
145 ip_canonicalize_tunnel(&ip_canonicalized
, ip
);
147 return checkconnectionth(username
, &ip_canonicalized
, th_getbyhost(ip
), hooknum
, cloneadjustment
, message
, messagelen
);
150 static int trustdowrite(trustsocket
*sock
, char *format
, ...) {
155 va_start(va
, format
);
156 r
= vsnprintf(buf
, sizeof(buf
), format
, va
);
164 if(write(sock
->fd
, buf
, r
+ 1) != r
+ 1)
169 static int policycheck_auth(trustsocket
*sock
, const char *sequence_id
, const char *username
, const char *host
) {
172 struct irc_in_addr ip
;
175 if(!ipmask_parse(host
, &ip
, &bits
))
176 return trustdowrite(sock
, "PASS %s", sequence_id
);
178 verdict
= checkconnection(username
, &ip
, HOOK_TRUSTS_NEWNICK
, 1, message
, sizeof(message
));
180 if (verdict
== POLICY_SUCCESS
) {
182 return trustdowrite(sock
, "PASS %s %s", sequence_id
, message
);
184 return trustdowrite(sock
, "PASS %s", sequence_id
);
186 return trustdowrite(sock
, "KILL %s %s", sequence_id
, message
);
190 static int trustkillconnection(trustsocket
*sock
, char *reason
) {
191 trustdowrite(sock
, "QUIT %s", reason
);
195 static void trustfreeconnection(trustsocket
*sock
) {
196 trustsocket
**pnext
= &tslist
;
198 for(trustsocket
*ts
=tslist
;ts
;ts
=ts
->next
) {
200 deregisterhandler(sock
->fd
, 1);
202 nsfree(POOL_TRUSTS
, sock
);
206 pnext
= &(sock
->next
);
210 static int handletrustauth(trustsocket
*sock
, char *server_name
, char *mac
) {
212 char *password
= NULL
;
213 unsigned char digest
[16];
214 char noncehexbuf
[NONCELEN
* 2 + 1];
215 char hexbuf
[sizeof(digest
) * 2 + 1];
217 for(i
=0;i
<MAXSERVERS
;i
++) {
218 if(trustaccounts
[i
].used
&& strcmp(trustaccounts
[i
].server
, server_name
) == 0) {
219 password
= trustaccounts
[i
].password
;
225 return trustkillconnection(sock
, "Invalid servername.");
228 hmacmd5_init(&h
, (unsigned char *)password
, strlen(password
));
229 hmacmd5_update(&h
, (unsigned char *)hmac_printhex(sock
->nonce
, noncehexbuf
, NONCELEN
), NONCELEN
* 2);
230 hmacmd5_final(&h
, digest
);
231 if(hmac_strcmp(mac
, hmac_printhex(digest
, hexbuf
, sizeof(digest
))))
232 return trustkillconnection(sock
, "Bad MAC.");
234 sock
->state
= STATE_AUTHED
;
235 return trustdowrite(sock
, "AUTHOK");
239 static int handletrustline(trustsocket
*sock
, char *line
) {
240 char *command
, *p
, *lastpos
;
241 char *tokens
[MAXTOKENS
];
242 int tokensfound
= -1;
244 for(command
=lastpos
=p
=line
;*p
;p
++) {
247 if(tokensfound
== MAXTOKENS
)
248 return trustkillconnection(sock
, "too many tokens");
250 if(tokensfound
>= 0) {
251 tokens
[tokensfound
++] = lastpos
;
259 if(tokensfound
== MAXTOKENS
)
260 return trustkillconnection(sock
, "too many tokens");
261 tokens
[tokensfound
++] = lastpos
;
264 if(sock
->state
== STATE_UNAUTHED
&& !strcmp("AUTH", command
)) {
266 return trustkillconnection(sock
, "incorrect arg count for command.");
268 return handletrustauth(sock
, tokens
[0], tokens
[1]);
269 } else if(sock
->state
== STATE_AUTHED
&& !strcmp("CHECK", command
)) {
271 return trustkillconnection(sock
, "incorrect arg count for command.");
273 policycheck_auth(sock
, tokens
[0], tokens
[1], tokens
[2]);
276 Error("trusts_policy", ERR_WARNING
, "Bad command: %s", command
);
281 static trustsocket
*findtrustsocketbyfd(int fd
) {
282 for(trustsocket
*ts
=tslist
;ts
;ts
=ts
->next
)
289 static int handletrustclient(trustsocket
*sock
) {
290 int r
, remaining
= TRUSTBUFSIZE
- sock
->size
, i
;
294 trustkillconnection(sock
, "Buffer overflow.");
298 r
= read(sock
->fd
, sock
->buf
+ sock
->size
, remaining
);
305 for(c
=sock
->buf
,i
=0;i
<sock
->size
;i
++,c
++) {
309 if(!handletrustline(sock
, lastpos
))
312 lastpos
= c
+ 1; /* is this ok? */
314 sock
->size
-=lastpos
- sock
->buf
;
315 memmove(sock
->buf
, lastpos
, sock
->size
);
320 static void processtrustclient(int fd
, short events
) {
321 trustsocket
*sock
= findtrustsocketbyfd(fd
);
327 if(!handletrustclient(sock
))
328 trustfreeconnection(sock
);
331 static void trustdotimeout(void *arg
) {
332 time_t t
= time(NULL
);
333 trustsocket
**pnext
, *next
;
337 for(trustsocket
*sock
=tslist
;sock
;) {
340 if(sock
->state
== STATE_UNAUTHED
&& t
>= sock
->timeout
) {
341 trustkillconnection(sock
, "Auth timeout.");
342 deregisterhandler(sock
->fd
, 1);
344 nsfree(POOL_TRUSTS
, sock
);
346 pnext
= &(sock
->next
);
353 static void processtrustlistener(int fd
, short events
) {
354 if(events
& POLLIN
) {
356 char buf
[NONCELEN
* 2 + 1];
358 int newfd
= accept(fd
, NULL
, NULL
), flags
;
362 flags
= fcntl(newfd
, F_GETFL
, 0);
364 Error("trusts_policy", ERR_WARNING
, "Unable to set socket non-blocking.");
369 if(fcntl(fd
, F_SETFL
, flags
|O_NONBLOCK
) < 0) {
370 Error("trusts_policy", ERR_WARNING
, "Unable to set socket non-blocking.");
375 registerhandler(newfd
, POLLIN
|POLLERR
|POLLHUP
, processtrustclient
);
377 sock
= nsmalloc(POOL_TRUSTS
, sizeof(trustsocket
));
379 deregisterhandler(newfd
, 1);
387 if(fread((char *)sock
->nonce
, 1, NONCELEN
, urandom
) != NONCELEN
) {
388 Error("trusts_policy", ERR_WARNING
, "Error getting random bytes.");
389 deregisterhandler(newfd
, 1);
391 nsfree(POOL_TRUSTS
, sock
);
393 sock
->state
= STATE_UNAUTHED
;
395 sock
->timeout
= time(NULL
) + 30;
396 if(!trustdowrite(sock
, "AUTH %s", hmac_printhex(sock
->nonce
, buf
, NONCELEN
))) {
397 Error("trusts_policy", ERR_WARNING
, "Error writing auth to fd %d.", newfd
);
398 deregisterhandler(newfd
, 1);
400 nsfree(POOL_TRUSTS
, sock
);
407 static int createlistenersock(int port
) {
408 struct sockaddr_in s
;
412 memset(&s
, 0, sizeof(struct sockaddr_in
));
413 s
.sin_family
= AF_INET
;
414 s
.sin_addr
.s_addr
= INADDR_ANY
;
415 s
.sin_port
= htons(port
);
417 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
419 Error("trusts_policy", ERR_WARNING
, "Unable to get socket for trustfd.");
424 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &optval
, sizeof(optval
));
426 if(bind(fd
, (struct sockaddr
*)&s
, sizeof(struct sockaddr_in
)) < 0) {
427 Error("trusts_policy", ERR_WARNING
, "Unable to bind trustfd.");
432 if(listen(fd
, 5) < 0) {
433 Error("trusts_policy", ERR_WARNING
, "Unable to listen on trustfd.");
438 registerhandler(fd
, POLLIN
, processtrustlistener
);
443 static void policycheck_irc(int hooknum
, void *arg
) {
446 long moving
= (long)args
[1];
453 verdict
= checkconnectionth(np
->ident
, &np
->p_nodeaddr
, gettrusthost(np
), hooknum
, 0, message
, sizeof(message
));
459 case POLICY_FAILURE_NODECOUNT
:
460 glinebynick(np
, POLICY_GLINE_DURATION
, message
, GLINE_IGNORE_TRUST
);
462 case POLICY_FAILURE_IDENTD
:
463 glinebyip("~*", &np
->p_ipaddr
, 128, POLICY_GLINE_DURATION
, message
, GLINE_ALWAYS_USER
|GLINE_IGNORE_TRUST
);
465 case POLICY_FAILURE_IDENTCOUNT
:
466 glinebynick(np
, POLICY_GLINE_DURATION
, message
, GLINE_ALWAYS_USER
|GLINE_IGNORE_TRUST
);
471 static int trusts_cmdtrustpolicy(void *source
, int cargc
, char **cargv
) {
472 nick
*sender
= source
;
475 controlreply(sender
, "Trust policy enforcement is currently %s.", enforcepolicy
?"enabled":"disabled");
479 enforcepolicy
= atoi(cargv
[0]);
480 controlwall(NO_OPER
, NL_TRUSTS
, "%s %s trust policy enforcement.", controlid(sender
), enforcepolicy
?"enabled":"disabled");
481 controlreply(sender
, "Trust policy enforcement is now %s.", enforcepolicy
?"enabled":"disabled");
491 countext
= registertgext("count");
495 m
= getconfigitem("trusts_policy", "enforcepolicy");
497 enforcepolicy
= atoi(m
->content
);
499 m
= getconfigitem("trusts_policy", "trustport");
501 trustport
= atoi(m
->content
);
503 trustport
= DEFAULT_TRUSTPORT
;
506 listenerfd
= createlistenersock(trustport
);
508 accts
= getconfigitems("trusts_policy", "server");
510 Error("trusts_policy", ERR_INFO
, "No servers added.");
512 sstring
**servers
= (sstring
**)(accts
->content
);
514 for(i
=0;i
<accts
->cursi
;i
++) {
519 Error("trusts_policy", ERR_INFO
, "Too many servers specified.");
523 strncpy(server
, servers
[i
]->content
, sizeof(server
));
525 pos
= strchr(server
, ',');
528 Error("trusts_policy", ERR_INFO
, "Server line is missing password: %s", server
);
534 trustaccounts
[i
].used
= 1;
535 strncpy(trustaccounts
[i
].server
, server
, SERVERLEN
);
536 strncpy(trustaccounts
[i
].password
, pos
+1, TRUSTPASSLEN
);
540 registerhook(HOOK_TRUSTS_NEWNICK
, policycheck_irc
);
541 registerhook(HOOK_TRUSTS_LOSTNICK
, policycheck_irc
);
543 registercontrolhelpcmd("trustpolicy", NO_DEVELOPER
, 1, trusts_cmdtrustpolicy
, "Usage: trustpolicy ?1|0?\nEnables or disables policy enforcement. Shows current status when no parameter is specified.");
545 schedulerecurring(time(NULL
)+1, 0, 5, trustdotimeout
, NULL
);
547 urandom
= fopen("/dev/urandom", "rb");
549 Error("trusts_policy", ERR_ERROR
, "Couldn't open /dev/urandom.");
556 releasetgext(countext
);
558 deregisterhook(HOOK_TRUSTS_NEWNICK
, policycheck_irc
);
559 deregisterhook(HOOK_TRUSTS_LOSTNICK
, policycheck_irc
);
561 deregistercontrolcmd("trustpolicy", trusts_cmdtrustpolicy
);
563 deleteallschedules(trustdotimeout
);