3 Copyright (C) 2004-2006 Chris Porter.
8 - made sure buf[0] = '\0'
12 - added application level ping support
14 - modified for new logging system
16 - newserv seems to unload this module before the ones that depend on us,
17 so deregister_service now checks to see if it's been freed already
19 - moronic bug in linked lists fixed
28 #include <sys/types.h>
29 #include <sys/socket.h>
32 #include <sys/ioctl.h>
37 #include "../lib/sstring.h"
38 #include "../lib/irc_string.h"
39 #include "../core/config.h"
40 #include "../core/events.h"
41 #include "../lib/version.h"
43 #include "nterfacer.h"
46 MODULE_VERSION("$Id: nterfacer.c 663 2006-05-16 17:27:36Z newserv $")
48 struct service_node
*tree
= NULL
;
49 struct esocket_events nterfacer_events
;
50 struct esocket
*nterfacer_sock
;
51 struct rline
*rlines
= NULL
;
52 unsigned short nterfacer_token
= BLANK_TOKEN
;
53 struct nterface_auto_log
*nrl
;
55 struct service_node
*ping
= NULL
;
57 int ping_handler(struct rline
*ri
, int argc
, char **argv
);
61 int debug_mode
= getcopyconfigitemintpositive("nterfacer", "debug", 0);
63 nrl
= nterface_open_log("nterfacer", "logs/nterfacer.log", debug_mode
);
65 loaded
= load_permits();
67 nterface_log(nrl
, NL_ERROR
, "No permits loaded successfully.");
70 nterface_log(nrl
, NL_INFO
, "Loaded %d permit%s successfully.", loaded
, loaded
==1?"":"s");
73 nterfacer_events
.on_accept
= nterfacer_accept_event
;
74 nterfacer_events
.on_line
= nterfacer_line_event
;
75 nterfacer_events
.on_disconnect
= NULL
;
77 nterfacer_token
= esocket_token();
79 ping
= register_service("nterfacer");
83 register_handler(ping
, "ping", 0, ping_handler
);
86 accept_fd
= setup_listening_socket();
88 nterface_log(nrl
, NL_ERROR
, "Unable to setup listening socket!");
90 nterfacer_sock
= esocket_add(accept_fd
, ESOCKET_UNIX_DOMAIN
, &nterfacer_events
, nterfacer_token
);
93 /* the main unix domain socket must NOT have a disconnect event. */
94 nterfacer_events
.on_disconnect
= nterfacer_disconnect_event
;
97 void free_handler(struct handler
*hp
) {
98 freesstring(hp
->command
);
102 void free_handlers(struct service_node
*tp
) {
103 struct handler
*hp
, *lp
;
105 for(hp
=tp
->handlers
;hp
;) {
115 struct service_node
*tp
, *lp
;
119 deregister_service(ping
);
129 if((accept_fd
!= -1) && nterfacer_sock
) {
130 esocket_clean_by_token(nterfacer_token
);
131 nterfacer_sock
= NULL
;
135 if(permits
&& permit_count
) {
136 for(i
=0;i
<permit_count
;i
++) {
137 freesstring(permits
[i
].hostname
);
138 freesstring(permits
[i
].password
);
145 nrl
= nterface_close_log(nrl
);
148 int load_permits(void) {
149 int lines
, loaded_lines
= 0, i
, j
;
150 struct permitted
*new_permits
, *resized
, *item
;
151 struct hostent
*host
;
154 lines
= getcopyconfigitemintpositive("nterfacer", "permits", 0);
156 nterface_log(nrl
, NL_ERROR
, "No permits found in config file.");
159 nterface_log(nrl
, NL_INFO
, "Loading %d permit%s from config file", lines
, lines
==1?"":"s");
161 new_permits
= calloc(lines
, sizeof(struct permitted
));
164 for(i
=1;i
<=lines
;i
++) {
165 snprintf(buf
, sizeof(buf
), "hostname%d", i
);
166 item
->hostname
= getcopyconfigitem("nterfacer", buf
, "", 100);
167 if(!item
->hostname
) {
168 nterface_log(nrl
, NL_ERROR
, "No hostname found for item %d.", i
);
172 host
= gethostbyname(item
->hostname
->content
);
174 nterface_log(nrl
, NL_WARNING
, "Couldn't resolve hostname: %s (item %d).", item
->hostname
->content
, i
);
175 freesstring(item
->hostname
);
179 item
->ihost
= (*(struct in_addr
*)host
->h_addr
).s_addr
;
180 for(j
=0;j
<loaded_lines
;j
++) {
181 if(new_permits
[j
].ihost
== item
->ihost
) {
182 nterface_log(nrl
, NL_WARNING
, "Host with items %d and %d is identical, dropping item %d.", j
+ 1, i
, i
);
188 freesstring(item
->hostname
);
192 snprintf(buf
, sizeof(buf
), "password%d", i
);
193 item
->password
= getcopyconfigitem("nterfacer", buf
, "", 100);
194 if(!item
->password
) {
195 nterface_log(nrl
, NL_ERROR
, "No password found for item %d.", item
->hostname
->content
, i
);
196 freesstring(item
->hostname
);
200 nterface_log(nrl
, NL_DEBUG
, "Loaded permit, hostname: %s.", item
->hostname
->content
);
211 resized
= realloc(new_permits
, sizeof(struct permitted
) * loaded_lines
);
218 permit_count
= loaded_lines
;
223 int setup_listening_socket(void) {
224 struct sockaddr_in sin
;
226 unsigned int opt
= 1;
228 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
230 /* also shamelessly ripped from proxyscan */
232 nterface_log(nrl
, NL_ERROR
, "Unable to open listening socket (%d).", errno
);
236 if(setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (const char *) &opt
, sizeof(opt
)) != 0) {
237 nterface_log(nrl
, NL_ERROR
, "Unable to set SO_REUSEADDR on listen socket.");
241 /* Initialiase the addresses */
242 memset(&sin
, 0, sizeof(sin
));
243 sin
.sin_family
= AF_INET
;
244 sin
.sin_port
= htons(getcopyconfigitemintpositive("nterfacer", "port", NTERFACER_PORT
));
246 if(bind(fd
, (struct sockaddr
*) &sin
, sizeof(sin
))) {
247 nterface_log(nrl
, NL_ERROR
, "Unable to bind listen socket (%d).", errno
);
253 if(ioctl(fd
, FIONBIO
, &opt
)) {
254 nterface_log(nrl
, NL_ERROR
, "Unable to set listen socket non-blocking.");
261 struct service_node
*register_service(char *name
) {
262 struct service_node
*np
= malloc(sizeof(service_node
));
265 np
->name
= getsstring(name
, strlen(name
));
279 struct handler
*register_handler(struct service_node
*service
, char *command
, int args
, handler_function fp
) {
280 struct handler
*hp
= malloc(sizeof(handler
));
283 hp
->command
= getsstring(command
, strlen(command
));
293 hp
->next
= service
->handlers
;
294 hp
->service
= service
;
295 service
->handlers
= hp
;
300 void deregister_handler(struct handler
*hl
) {
301 struct service_node
*service
= (struct service_node
*)hl
->service
;
302 struct handler
*np
, *lp
= NULL
;
303 for(np
=service
->handlers
;np
;lp
=np
,np
=np
->next
) {
308 service
->handlers
= np
->next
;
316 void deregister_service(struct service_node
*service
) {
317 struct service_node
*sp
, *lp
= NULL
;
318 struct rline
*li
, *pi
= NULL
;
320 for(sp
=tree
;sp
;lp
=sp
,sp
=sp
->next
) {
331 if(!sp
) /* already freed */
334 free_handlers(service
);
337 if(li
->service
== service
) {
351 freesstring(service
->name
);
356 void nterfacer_accept_event(struct esocket
*socket
) {
357 struct sockaddr_in sin
;
358 unsigned int addrsize
= sizeof(sin
);
359 int newfd
= accept(socket
->fd
, (struct sockaddr
*)&sin
, &addrsize
), i
;
360 struct sconnect
*temp
;
361 struct permitted
*item
= NULL
;
362 struct esocket
*newsocket
;
363 unsigned int opt
= 1;
366 nterface_log(nrl
, NL_WARNING
, "Unable to accept nterfacer fd!");
370 if(ioctl(newfd
, FIONBIO
, &opt
)) {
371 nterface_log(nrl
, NL_ERROR
, "Unable to set accepted socket non-blocking.");
375 for(i
=0;i
<permit_count
;i
++) {
376 if(permits
[i
].ihost
== sin
.sin_addr
.s_addr
) {
383 nterface_log(nrl
, NL_INFO
, "Unauthorised connection from: %s", IPtostr(htonl(sin
.sin_addr
.s_addr
)));
388 temp
= (struct sconnect
*)malloc(sizeof(struct sconnect
));
395 /* do checks on hostname first */
397 newsocket
= esocket_add(newfd
, ESOCKET_UNIX_DOMAIN_CONNECTED
, &nterfacer_events
, nterfacer_token
);
403 newsocket
->tag
= temp
;
405 nterface_log(nrl
, NL_INFO
, "New connection from %s.", item
->hostname
->content
);
407 temp
->status
= SS_IDLE
;
410 esocket_write_line(newsocket
, "nterfacer " PROTOCOL_VERSION
);
413 int nterfacer_line_event(struct esocket
*sock
, char *newline
) {
414 struct sconnect
*socket
= sock
->tag
;
415 char *response
, *theirnonceh
= NULL
;
416 unsigned char theirnonce
[NONCE_LEN
];
419 switch(socket
->status
) {
421 if(strcasecmp(newline
, ANTI_FULL_VERSION
)) {
422 nterface_log(nrl
, NL_INFO
, "Protocol mismatch from %s: %s", socket
->permit
->hostname
->content
, newline
);
425 char *hex
, hexbuf
[NONCE_LEN
* 2 + 1]; /* Vekoma mAD HoUSe */
427 hex
= get_random_hex();
429 nterface_log(nrl
, NL_ERROR
, "Unable to open challenge entropy bin!");
433 memcpy(socket
->response
, challenge_response(hex
, socket
->permit
->password
->content
), sizeof(socket
->response
));
434 socket
->response
[sizeof(socket
->response
) - 1] = '\0'; /* just in case */
436 socket
->status
= SS_VERSIONED
;
437 if(!generate_nonce(socket
->ournonce
, 1)) {
438 nterface_log(nrl
, NL_ERROR
, "Unable to generate nonce!");
442 if(esocket_write_line(sock
, "%s %s", hex
, int_to_hex(socket
->ournonce
, hexbuf
, NONCE_LEN
)))
448 for(response
=newline
;*response
;response
++) {
449 if((*response
== ' ') && (*(response
+ 1))) {
451 theirnonceh
= response
+ 1;
456 if(!theirnonceh
|| (strlen(theirnonceh
) != 32) || !hex_to_int(theirnonceh
, theirnonce
, sizeof(theirnonce
))) {
457 nterface_log(nrl
, NL_INFO
, "Protocol error drop: %s", socket
->permit
->hostname
->content
);
461 if(!memcmp(socket
->ournonce
, theirnonce
, sizeof(theirnonce
))) {
462 nterface_log(nrl
, NL_INFO
, "Bad nonce drop: %s", socket
->permit
->hostname
->content
);
466 if(!strncasecmp(newline
, socket
->response
, sizeof(socket
->response
))) {
469 nterface_log(nrl
, NL_INFO
, "Authed: %s", socket
->permit
->hostname
->content
);
470 socket
->status
= SS_AUTHENTICATED
;
471 ret
= esocket_write_line(sock
, "Oauth");
473 switch_buffer_mode(sock
, socket
->permit
->password
->content
, socket
->ournonce
, theirnonce
);
478 nterface_log(nrl
, NL_INFO
, "Bad CR drop: %s", socket
->permit
->hostname
->content
);
483 case SS_AUTHENTICATED
:
484 nterface_log(nrl
, NL_INFO
|NL_LOG_ONLY
, "L(%s): %s", socket
->permit
->hostname
->content
, newline
);
485 reason
= nterfacer_new_rline(newline
, sock
, &number
);
487 if(reason
== RE_SOCKET_ERROR
)
489 if(reason
!= RE_BAD_LINE
) {
490 if(esocket_write_line(sock
, "%d,E%d,%s", number
, reason
, request_error(reason
)))
503 int nterfacer_new_rline(char *line
, struct esocket
*socket
, int *number
) {
504 char *sp
, *p
, *parsebuf
= NULL
, *pp
, commandbuf
[MAX_BUFSIZE
], *args
[MAX_ARGS
], *newp
;
506 struct service_node
*service
;
507 struct rline
*prequest
;
511 if(!line
|| !line
[0] || (line
[0] == ','))
514 for(sp
=line
;*sp
;sp
++)
518 if(!*sp
|| !*(sp
+ 1))
523 for(service
=tree
;service
;service
=service
->next
)
524 if(!strcmp(service
->name
->content
, line
))
535 *number
= positive_atoi(sp
+ 1);
537 if((*number
< 1) || (*number
> 0xffff))
541 nterface_log(nrl
, NL_DEBUG
, "Unable to find service: %s", line
);
542 return RE_SERVICER_NOT_FOUND
;
547 for(pp
=p
+1;*pp
;pp
++) {
548 if((*pp
== '\\') && *(pp
+ 1)) {
549 if(*(pp
+ 1) == ',') {
551 } else if(*(pp
+ 1) == '\\') {
555 } else if(*pp
== ',') {
562 if(*pp
== '\0') { /* if we're at the end already, we have no arguments */
565 argcount
= 1; /* we have a comma, so we have one already */
570 for(hl
=service
->handlers
;hl
;hl
=hl
->next
)
571 if(!strncmp(hl
->command
->content
, commandbuf
, sizeof(commandbuf
)))
575 return RE_COMMAND_NOT_FOUND
;
578 parsebuf
= (char *)malloc(strlen(pp
) + 1);
579 MemCheckR(parsebuf
, RE_MEM_ERROR
);
582 for(newp
=args
[0]=parsebuf
,pp
++;*pp
;pp
++) {
583 if((*pp
== '\\') && *(pp
+ 1)) {
584 if(*(pp
+ 1) == ',') {
586 } else if(*(pp
+ 1) == '\\') {
590 } else if(*pp
== ',') {
592 args
[argcount
++] = newp
;
593 if(argcount
> MAX_ARGS
) {
595 return RE_TOO_MANY_ARGS
;
603 if(argcount
< hl
->args
) {
604 if(argcount
&& parsebuf
)
606 return RE_WRONG_ARG_COUNT
;
609 prequest
= (struct rline
*)malloc(sizeof(struct rline
));
612 if(argcount
&& parsebuf
)
617 prequest
->service
= service
;
618 prequest
->handler
= hl
;
619 prequest
->buf
[0] = '\0';
620 prequest
->curpos
= prequest
->buf
;
621 prequest
->tag
= NULL
;
622 prequest
->id
= *number
;
623 prequest
->next
= rlines
;
624 prequest
->socket
= socket
;
627 re
= (hl
->function
)(prequest
, argcount
, args
);
629 if(argcount
&& parsebuf
)
635 void nterfacer_disconnect_event(struct esocket
*sock
) {
636 struct sconnect
*socket
= sock
->tag
;
640 nterface_log(nrl
, NL_INFO
, "Disconnected from %s.", socket
->permit
->hostname
->content
);
643 for(li
=rlines
;li
;li
=li
->next
)
644 if(li
->socket
->tag
== socket
)
650 int ri_append(struct rline
*li
, char *format
, ...) {
651 char buf
[MAX_BUFSIZE
], escapedbuf
[MAX_BUFSIZE
* 2 + 1], *p
, *tp
;
652 int sizeleft
= sizeof(li
->buf
) - (li
->curpos
- li
->buf
);
655 va_start(ap
, format
);
657 if(vsnprintf(buf
, sizeof(buf
), format
, ap
) >= sizeof(buf
)) {
664 for(tp
=escapedbuf
,p
=buf
;*p
||(*tp
='\0');*tp
++=*p
++)
665 if((*p
== ',') || (*p
== '\\'))
669 if(li
->curpos
== li
->buf
) {
670 li
->curpos
+=snprintf(li
->curpos
, sizeleft
, "%s", escapedbuf
);
672 li
->curpos
+=snprintf(li
->curpos
, sizeleft
, ",%s", escapedbuf
);
676 if(sizeof(li
->buf
) - (li
->curpos
- li
->buf
) > 0) {
683 int ri_error(struct rline
*li
, int error_code
, char *format
, ...) {
684 char buf
[MAX_BUFSIZE
], escapedbuf
[MAX_BUFSIZE
* 2 + 1], *p
, *tp
;
685 struct rline
*pp
, *lp
= NULL
;
690 va_start(ap
, format
);
691 vsnprintf(buf
, sizeof(buf
), format
, ap
);
694 for(tp
=escapedbuf
,p
=buf
;*p
||(*tp
='\0');*tp
++=*p
++)
695 if((*p
== ',') || (*p
== '\\'))
698 if(esocket_write_line(li
->socket
, "%d,OE%d,%s", li
->id
, error_code
, escapedbuf
))
699 retval
= RE_SOCKET_ERROR
;
702 for(pp
=rlines
;pp
;lp
=pp
,pp
=pp
->next
) {
717 int ri_final(struct rline
*li
) {
718 struct rline
*pp
, *lp
= NULL
;
722 if(esocket_write_line(li
->socket
, "%d,OO%s", li
->id
, li
->buf
))
723 retval
= RE_SOCKET_ERROR
;
725 for(pp
=rlines
;pp
;lp
=pp
,pp
=pp
->next
) {
740 int ping_handler(struct rline
*ri
, int argc
, char **argv
) {