#include <netdb.h>
#include <string.h>
#include <strings.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdint.h>
#include "../lib/sstring.h"
#include "../lib/irc_string.h"
#include "../core/config.h"
#include "../core/events.h"
#include "../lib/version.h"
+#include "../core/schedule.h"
#include "nterfacer.h"
#include "logging.h"
int permit_count = 0;
int ping_handler(struct rline *ri, int argc, char **argv);
+static void nterfacer_sendcallback(struct rline *ri, int error, char *buf);
void _init(void) {
int loaded;
nrl = nterface_open_log("nterfacer", "logs/nterfacer.log", debug_mode);
loaded = load_permits();
- if(!loaded) {
- nterface_log(nrl, NL_ERROR, "No permits loaded successfully.");
+ nterface_log(nrl, NL_INFO, "Loaded %d permit%s successfully.", loaded, loaded==1?"":"s");
+
+ if(!loaded)
return;
- } else {
- nterface_log(nrl, NL_INFO, "Loaded %d permit%s successfully.", loaded, loaded==1?"":"s");
- }
nterfacer_events.on_accept = nterfacer_accept_event;
nterfacer_events.on_line = nterfacer_line_event;
}
void free_handler(struct handler *hp) {
+ struct rline *li, *pi = NULL;
+
+ for(li=rlines;li;) {
+ if(li->handler == hp) {
+ if(li->socket) {
+ esocket_write_line(li->socket, "%d,OE%d,%s", li->id, BF_UNLOADED, "Service was unloaded.");
+ } else if(li->callback) {
+ nterfacer_sendcallback(li, BF_UNLOADED, "Service was unloaded.");
+ }
+ if(pi) {
+ pi->next = li->next;
+ ntfree(li);
+ li = pi->next;
+ } else {
+ rlines = li->next;
+ ntfree(li);
+ li = rlines;
+ }
+ } else {
+ pi=li,li=li->next;
+ }
+ }
+
freesstring(hp->command);
ntfree(hp);
}
hostnamesa = getconfigitems("nterfacer", "hostname");
passwordsa = getconfigitems("nterfacer", "password");
- if(!hostnamesa || !passwordsa) {
- nterface_log(nrl, NL_ERROR, "Unable to load hostnames/passwords.");
+ if(!hostnamesa || !passwordsa)
return 0;
- }
if(hostnamesa->cursi != passwordsa->cursi) {
nterface_log(nrl, NL_ERROR, "Different number of hostnames/passwords in config file.");
return 0;
continue;
}
- item->ihost = (*(struct in_addr *)host->h_addr).s_addr;
+ item->ihost = (*(struct in_addr *)host->h_addr_list[0]).s_addr;
for(j=0;j<loaded_lines;j++) {
if(new_permits[j].ihost == item->ihost) {
nterface_log(nrl, NL_WARNING, "Host with items %d and %d is identical, dropping item %d.", j + 1, i + 1, i + 1);
if(bind(fd, (struct sockaddr *) &sin, sizeof(sin))) {
nterface_log(nrl, NL_ERROR, "Unable to bind listen socket (%d).", errno);
+ close(fd);
return -1;
}
if(ioctl(fd, FIONBIO, &opt)) {
nterface_log(nrl, NL_ERROR, "Unable to set listen socket non-blocking.");
+ close(fd);
return -1;
}
void deregister_service(struct service_node *service) {
struct service_node *sp, *lp = NULL;
- struct rline *li, *pi = NULL;
for(sp=tree;sp;lp=sp,sp=sp->next) {
if(sp == service) {
free_handlers(service);
- for(li=rlines;li;) {
- if(li->service == service) {
- if(pi) {
- pi->next = li->next;
- ntfree(li);
- li = pi->next;
- } else {
- rlines = li->next;
- ntfree(li);
- li = rlines;
- }
- } else {
- pi=li,li=li->next;
- }
- }
freesstring(service->name);
ntfree(service);
if(ioctl(newfd, FIONBIO, &opt)) {
nterface_log(nrl, NL_ERROR, "Unable to set accepted socket non-blocking.");
+ close(newfd);
return;
}
}
if(!item) {
- /* Someone needs to figure out how to print the IP :) */
- nterface_log(nrl, NL_INFO, "Unauthorised connection closed");
+ nterface_log(nrl, NL_INFO, "Unauthorised connection from %s closed", inet_ntoa(sin.sin_addr));
close(newfd);
return;
}
if(*p == ',')
break;
- if(!*p || !(p + 1))
+ if(!*p || !*(p + 1))
return RE_BAD_LINE;
*p = '\0';
*number = positive_atoi(sp + 1);
- if((*number < 1) || (*number > 0xffff))
+ if((*number < 1) || (*number > INT32_MAX))
return RE_BAD_LINE;
if (!service) {
if(argcount) {
parsebuf = (char *)ntmalloc(strlen(pp) + 1);
MemCheckR(parsebuf, RE_MEM_ERROR);
- newp = parsebuf;
for(newp=args[0]=parsebuf,pp++;*pp;pp++) {
if((*pp == '\\') && *(pp + 1)) {
prequest->id = *number;
prequest->next = rlines;
prequest->socket = socket;
+ prequest->callback = NULL;
rlines = prequest;
re = (hl->function)(prequest, argcount, args);
va_list ap;
int retval = RE_OK;
- if(li->socket) {
+ if(li->socket || li->callback) {
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
va_end(ap);
for(tp=escapedbuf,p=buf;*p||(*tp='\0');*tp++=*p++)
if((*p == ',') || (*p == '\\'))
*tp++ = '\\';
+ if(li->socket) {
+ if(esocket_write_line(li->socket, "%d,OE%d,%s", li->id, error_code, escapedbuf))
+ retval = RE_SOCKET_ERROR;
+ } else {
+ if(error_code == 0) /* :P */
+ error_code = -10000;
- if(esocket_write_line(li->socket, "%d,OE%d,%s", li->id, error_code, escapedbuf))
- retval = RE_SOCKET_ERROR;
+ nterfacer_sendcallback(li, error_code, escapedbuf);
+ }
}
for(pp=rlines;pp;lp=pp,pp=pp->next) {
struct rline *pp, *lp = NULL;
int retval = RE_OK;
- if(li->socket)
+ if(li->socket) {
if(esocket_write_line(li->socket, "%d,OO%s", li->id, li->buf))
retval = RE_SOCKET_ERROR;
+ } else if(li->callback) {
+ nterfacer_sendcallback(li, 0, li->buf);
+ }
for(pp=rlines;pp;lp=pp,pp=pp->next) {
if(pp == li) {
ri_append(ri, "OK");
return ri_final(ri);
}
+
+struct sched_rline {
+ rline rl;
+ int argc;
+ handler *hl;
+ void *schedule;
+ char argv[];
+};
+
+static const int XMAXARGS = 50;
+
+static void execrline(void *arg) {
+ struct sched_rline *sr = arg;
+ int re, i;
+ char *argv[XMAXARGS], *buf;
+
+ sr->schedule = NULL;
+
+ buf = sr->argv;
+ for(i=0;i<sr->argc;i++) {
+ argv[i] = buf;
+ buf+=strlen(buf) + 1;
+ }
+
+ re = (sr->hl->function)(&sr->rl, sr->argc, argv);
+
+ if(re)
+ Error("nterfacer", ERR_WARNING, "sendline: error occured calling %p %d: %s", sr->hl->function, re, request_error(re));
+}
+
+void *nterfacer_sendline(char *service, char *command, int argc, char **argv, rline_callback callback, void *tag) {
+ struct service_node *servicep;
+ struct rline *prequest;
+ struct sched_rline *sr;
+ struct handler *hl;
+ int totallen, i;
+ char *buf;
+
+ for(servicep=tree;servicep;servicep=servicep->next)
+ if(!strcmp(servicep->name->content, service))
+ break;
+
+ if(argc > XMAXARGS)
+ Error("nterfacer", ERR_STOP, "Over maximum arguments.");
+
+ if(!servicep) {
+ Error("nterfacer", ERR_WARNING, "sendline: service not found: %s", service);
+ return NULL;
+ }
+
+ for(hl=servicep->handlers;hl;hl=hl->next)
+ if(!strcmp(hl->command->content, command))
+ break;
+
+ if(!hl) {
+ Error("nterfacer", ERR_WARNING, "sendline: command not found: %s", command);
+ return NULL;
+ }
+
+ if(argc < hl->args) {
+ Error("nterfacer", ERR_WARNING, "sendline: wrong number of arguments: %s", command);
+ return NULL;
+ }
+
+ /* we have to create a copy of the arguments for reentrancy reasons, grr */
+ totallen = 0;
+ for(i=0;i<argc;i++)
+ totallen+=strlen(argv[i]) + 1;
+
+ /* HACKY but allows existing code to still work */
+ sr = (struct sched_rline *)ntmalloc(sizeof(struct sched_rline) + totallen);
+ if(!sr) {
+ MemError();
+ return NULL;
+ }
+ prequest = &sr->rl;
+
+ sr->argc = argc;
+ buf = sr->argv;
+ for(i=0;i<argc;i++) {
+ size_t len = strlen(argv[i]) + 1;
+ memcpy(buf, argv[i], len);
+ buf+=len;
+ }
+ sr->hl = hl;
+
+ prequest->service = servicep;
+ prequest->handler = hl;
+ prequest->buf[0] = '\0';
+ prequest->curpos = prequest->buf;
+ prequest->tag = tag;
+ prequest->id = 0;
+ prequest->socket = NULL;
+ prequest->callback = callback;
+
+ prequest->next = rlines;
+ rlines = prequest;
+
+ scheduleoneshot(time(NULL), execrline, sr);
+
+ return (void *)sr;
+}
+
+void nterfacer_freeline(void *tag) {
+ struct sched_rline *prequest = tag;
+
+ prequest->rl.callback = NULL;
+ if(prequest->schedule)
+ deleteschedule(prequest->schedule, execrline, NULL);
+}
+
+#define MAX_LINES 8192
+
+/* this bites */
+static void nterfacer_sendcallback(struct rline *ri, int error, char *buf) {
+ char *lines[MAX_LINES+1];
+ char newbuf[MAX_BUFSIZE+5];
+ char *s, *d, *laststart;
+ int linec = 0;
+
+ for(s=buf,laststart=d=newbuf;*s;s++) {
+ if((*s == '\\') && *(s + 1)) {
+ if(*(s + 1) == ',') {
+ *d++ = ',';
+ } else if(*(s + 1) == '\\') {
+ *d++ = '\\';
+ }
+ s++;
+ } else if(*s == ',') {
+ *d++ = '\0';
+ if(linec >= MAX_LINES - 5) {
+ nterfacer_sendcallback(ri, BF_OVER, "Buffer overflow.");
+ return;
+ }
+
+ lines[linec++] = laststart;
+ laststart = d;
+ } else {
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+ lines[linec++] = laststart;
+
+ ri->callback(error, linec, lines, ri->tag);
+}