diff --git a/Makefile.in b/Makefile.in index 7714844d..f86c522c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ CFLAGS = @CFLAGS@ # the system one. #CFLAGS= -DNDEBUG -g -O2 -D"FD_SETSIZE=1024" SHELL=/bin/sh -SUBDIRS=libratbox modules extensions src tools servlink doc help +SUBDIRS=libratbox modules extensions src tools ssld doc help CLEANDIRS = ${SUBDIRS} RSA_FILES=rsa_respond/README rsa_respond/respond.c rsa_respond/Makefile diff --git a/include/s_conf.h b/include/s_conf.h index 3fa389dc..5b917481 100644 --- a/include/s_conf.h +++ b/include/s_conf.h @@ -54,22 +54,26 @@ struct ip_value extern FILE *conf_fbfile_in; extern char conf_line_in[256]; -struct ConfItem -{ - struct ConfItem *next; /* list node pointer */ - unsigned int status; /* If CONF_ILLEGAL, delete when no clients */ - unsigned int flags; - int clients; /* Number of *LOCAL* clients using this */ - char *name; /* IRC name, nick, server name, or original u@h */ - char *host; /* host part of user@host */ - char *passwd; /* doubles as kline reason *ugh* */ - char *spasswd; /* Password to send. */ - char *user; /* user part of user@host */ - int port; - time_t hold; /* Hold action until this time (calendar time) */ - char *className; /* Name of class */ - struct Class *c_class; /* Class of connection */ - rb_patricia_node_t *pnode; /* Our patricia node */ +struct ConfItem +{ + unsigned int status; /* If CONF_ILLEGAL, delete when no clients */ + unsigned int flags; + int clients; /* Number of *LOCAL* clients using this */ + + union + { + char *name; /* IRC name, nick, server name, or original u@h */ + const char *oper; + } info; + + char *host; /* host part of user@host */ + char *passwd; /* doubles as kline reason *ugh* */ + char *spasswd; /* Password to send. */ + char *user; /* user part of user@host */ + int port; + time_t hold; /* Hold action until this time (calendar time) */ + struct Class *c_class; /* Class of connection */ + rb_patricia_node_t *pnode; }; #define CONF_ILLEGAL 0x80000000 diff --git a/servlink/.cvsignore b/servlink/.cvsignore deleted file mode 100644 index 224f7c65..00000000 --- a/servlink/.cvsignore +++ /dev/null @@ -1,3 +0,0 @@ -Makefile -setup.h -servlink diff --git a/servlink/.indent.pro b/servlink/.indent.pro deleted file mode 100644 index a4981660..00000000 --- a/servlink/.indent.pro +++ /dev/null @@ -1 +0,0 @@ --i8 -bli0 -ut -nsai -l100 -npcs \ No newline at end of file diff --git a/servlink/Makefile.in b/servlink/Makefile.in deleted file mode 100644 index a0470123..00000000 --- a/servlink/Makefile.in +++ /dev/null @@ -1,82 +0,0 @@ -# -# Makefile.in for servlink/src -# -# $Id: Makefile.in 1285 2006-05-05 15:03:53Z nenolod $ -# - -CC = @CC@ -INSTALL = @INSTALL@ -INSTALL_BIN = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_SUID = @INSTALL_PROGRAM@ -o root -m 4755 -RM = @RM@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -CFLAGS = @IRC_CFLAGS@ -DIRCD_PREFIX=\"@prefix@\" -LDFLAGS = @LDFLAGS@ -MKDEP = @MKDEP@ -DIRCD_PREFIX=\"@prefix@\" -MV = @MV@ -RM = @RM@ -prefix = @prefix@ -exec_prefix = @exec_prefix@ -bindir = @bindir@ -libexecdir = @libexecdir@ -confdir = @confdir@ -localstatedir = @localstatedir@ - -ZIP_LIB = @ZLIB_LD@ - -IRCDLIBS = @LIBS@ $(ZIP_LIB) - -INCLUDES = -I. -I../include $(SSL_INCLUDES) -CPPFLAGS = ${INCLUDES} @CPPFLAGS@ - -PROGS = servlink - -SOURCES = \ - servlink.c \ - io.c \ - control.c - - -OBJECTS = ${SOURCES:.c=.o} - -all: servlink - -build: all - -servlink: ${OBJECTS} - ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJECTS} ${IRCDLIBS} - -install: build - @echo "ircd: installing servlink ($(PROGS))" - @for i in $(PROGS); do \ - if test -f $(DESTDIR)$(bindir)/$$i; then \ - $(MV) $(DESTDIR)$(bindir)/$$i $(DESTDIR)$(bindir)/$$i.old; \ - fi; \ - $(INSTALL_BIN) $$i $(DESTDIR)$(bindir); \ - done - -.c.o: - ${CC} ${CPPFLAGS} ${CFLAGS} -c $< - -.PHONY: depend clean distclean -depend: - @${MKDEP} ${CPPFLAGS} ${SOURCES} > .depend.tmp - @sed -e '/^# DO NOT DELETE THIS LINE/,$$d' Makefile.depend - @echo '# DO NOT DELETE THIS LINE!!!' >>Makefile.depend - @echo '# make depend needs it.' >>Makefile.depend - @cat .depend.tmp >>Makefile.depend - @mv Makefile.depend Makefile - @rm -f .depend.tmp - -clean: - ${RM} -f *.o *~ *.core core servlink - -lint: - lint -aacgprxhH $(CPPFLAGS) -DIRCD_PREFIX=\"@prefix@\" $(SOURCES) >>../lint.out - -distclean: clean - ${RM} -f Makefile - -# End of Makefile diff --git a/servlink/README b/servlink/README deleted file mode 100644 index 2ccfcd67..00000000 --- a/servlink/README +++ /dev/null @@ -1,71 +0,0 @@ -Servlink protocol documentation. -$Id: README 1285 2006-05-05 15:03:53Z nenolod $ --------------- - -After negotiating an incoming/outgoing server connection, the ircd will -fork, then execve servlink, with fd 0 as one end of a control pipe and -fd 1 as one end of a data pipe. fd 2 will be the socket connected to -the remote server. - -The data pipe is used by the ircd to send/receive normal, decrypted, -uncompressed IRC commands to/from the remote server. The socket is used to -send the (processed) data to the remote server, and receive the data from -the remote server. - -The control pipe is used to activate encryption/compression and to set the -encryption key/algorithm to be used. - -Format of control messages: - - - -data format: - - -Commands: - -001 - SET_ZIP_OUT_LEVEL - data: yes - description: - set compression level (0 [use default, 6], or 1-9) - -002 - START_ZIP_OUT - data: no - description: - all data written to the data pipe will be compressed - prior to being sent to the remote server. - -003 - START_ZIP_IN - data: no - description: - all data not yet read from the slink program will be - decompressed before reading - -004 - INJECT_RECVQ - data: recvq - - Used before INIT to inject any data read from the server fd which - should be pre-processed by servlink before being sent back - to the LOCAL_FD through the data fd. - -005 - INJECT_SENDQ - data: sendq - - As above, but sent to remote server without processing. - -006 - INIT - -007 - ZIPSTATS - request to send ziplinks statistics reply. - -replies - -001 - ERROR - data: u32 len/char error[len] - - fatal error message. - -002 - ZIPSTATS - data: u32 in/u32 in_wire/u32 out/u32 out_wire - - ziplinks commpression statistics diff --git a/servlink/TODO b/servlink/TODO deleted file mode 100644 index 6fcefa16..00000000 --- a/servlink/TODO +++ /dev/null @@ -1,7 +0,0 @@ -Servlink todo list -$Id: TODO 6 2005-09-10 01:02:21Z nenolod $ ------------------- - -Fix any bugs that come up - -Think of improvements :) diff --git a/servlink/control.c b/servlink/control.c deleted file mode 100644 index 1f341a78..00000000 --- a/servlink/control.c +++ /dev/null @@ -1,129 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/servlink.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: control.c 1285 2006-05-05 15:03:53Z nenolod $ - */ - -#include "setup.h" - -#include - -#include -#include -#include -#include -#ifdef HAVE_LIBZ -#include -#endif - -#include "servlink.h" -#include "io.h" -#include "control.h" - -static cmd_handler cmd_set_zip_out_level; -static cmd_handler cmd_start_zip_out; -static cmd_handler cmd_start_zip_in; -static cmd_handler cmd_init; - -struct command_def command_table[] = { - {CMD_SET_ZIP_OUT_LEVEL, cmd_set_zip_out_level, COMMAND_FLAG_DATA}, - {CMD_START_ZIP_OUT, cmd_start_zip_out, 0}, - {CMD_START_ZIP_IN, cmd_start_zip_in, 0}, - {CMD_INJECT_RECVQ, process_recvq, COMMAND_FLAG_DATA}, - {CMD_INJECT_SENDQ, process_sendq, COMMAND_FLAG_DATA}, - {CMD_INIT, cmd_init, 0}, - {CMD_ZIPSTATS, send_zipstats, 0}, - {0, 0, 0} -}; - -void -cmd_set_zip_out_level(struct ctrl_command *cmd) -{ -#ifdef HAVE_LIBZ - out_state.zip_state.level = *cmd->data; - if((out_state.zip_state.level < -1) || (out_state.zip_state.level > 9)) - send_error("invalid compression level %d", out_state.zip_state.level); -#else - send_error("can't set compression level - no libz support!"); -#endif -} - -void -cmd_start_zip_out(struct ctrl_command *cmd) -{ -#ifdef HAVE_LIBZ - int ret; - - if(out_state.zip) - send_error("can't start compression - already started!"); - - out_state.zip_state.z_stream.total_in = 0; - out_state.zip_state.z_stream.total_out = 0; - out_state.zip_state.z_stream.zalloc = (alloc_func) 0; - out_state.zip_state.z_stream.zfree = (free_func) 0; - out_state.zip_state.z_stream.data_type = Z_ASCII; - - if(out_state.zip_state.level <= 0) - out_state.zip_state.level = Z_DEFAULT_COMPRESSION; - - if((ret = deflateInit(&out_state.zip_state.z_stream, out_state.zip_state.level)) != Z_OK) - send_error("deflateInit failed: %s", zError(ret)); - - out_state.zip = 1; -#else - send_error("can't start compression - no libz support!"); -#endif -} - -void -cmd_start_zip_in(struct ctrl_command *cmd) -{ -#ifdef HAVE_LIBZ - int ret; - - if(in_state.zip) - send_error("can't start decompression - already started!"); - - in_state.zip_state.z_stream.total_in = 0; - in_state.zip_state.z_stream.total_out = 0; - in_state.zip_state.z_stream.zalloc = (alloc_func) 0; - in_state.zip_state.z_stream.zfree = (free_func) 0; - in_state.zip_state.z_stream.data_type = Z_ASCII; - if((ret = inflateInit(&in_state.zip_state.z_stream)) != Z_OK) - send_error("inflateInit failed: %s", zError(ret)); - in_state.zip = 1; -#else - send_error("can't start decompression - no libz support!"); -#endif -} - - -void -cmd_init(struct ctrl_command *cmd) -{ - if(in_state.active || out_state.active) - send_error("CMD_INIT sent twice!"); - - in_state.active = 1; - out_state.active = 1; - CONTROL.read_cb = read_ctrl; - CONTROL.write_cb = NULL; - LOCAL.read_cb = read_data; - LOCAL.write_cb = NULL; - REMOTE.read_cb = read_net; - REMOTE.write_cb = NULL; -} diff --git a/servlink/control.h b/servlink/control.h deleted file mode 100644 index 294eeb93..00000000 --- a/servlink/control.h +++ /dev/null @@ -1,57 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/control.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: control.h 1285 2006-05-05 15:03:53Z nenolod $ - */ - -#ifndef INCLUDED_servlink_control_h -#define INCLUDED_servlink_control_h - -#define CMD_SET_ZIP_OUT_LEVEL 1 /* data */ -#define CMD_START_ZIP_OUT 2 -#define CMD_START_ZIP_IN 3 -#define CMD_INJECT_RECVQ 4 /* data */ -#define CMD_INJECT_SENDQ 5 /* data */ -#define CMD_INIT 6 -#define CMD_ZIPSTATS 7 - -#define RPL_ERROR 1 /* data */ -#define RPL_ZIPSTATS 2 /* data */ - -/* flags */ -#define COMMAND_FLAG_DATA 0x0001 /* command has data - following */ -struct ctrl_command -{ - int command; - int datalen; - int gotdatalen; - int readdata; - unsigned char *data; -}; - -typedef void cmd_handler(struct ctrl_command *); - -struct command_def -{ - unsigned int commandid; - cmd_handler *handler; - unsigned int flags; -}; - -extern struct command_def command_table[]; -#endif /* INCLUDED_servlink_control_h */ diff --git a/servlink/io.c b/servlink/io.c deleted file mode 100644 index f4f91f2e..00000000 --- a/servlink/io.c +++ /dev/null @@ -1,657 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/io.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: io.c 3319 2007-03-29 20:03:06Z jilles $ - */ - -#include "setup.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBZ -#include -#endif - -#include "servlink.h" -#include "io.h" -#include "control.h" - -static int check_error(int, int, int); - -static const char * -fd_name(int fd) -{ - if(fd == CONTROL.fd) - return "control"; - if(fd == LOCAL.fd) - return "data"; - if(fd == REMOTE.fd) - return "network"; - - /* uh oh... */ - return "unknown"; -} - -#if defined( HAVE_LIBZ ) -static unsigned char tmp_buf[BUFLEN]; -static unsigned char tmp2_buf[BUFLEN]; -#endif - -static unsigned char ctrl_buf[256] = ""; -static unsigned int ctrl_len = 0; -static unsigned int ctrl_ofs = 0; - -void -io_loop(int nfds) -{ - fd_set rfds; - fd_set wfds; - int i, ret; - - /* loop forever */ - for (;;) - { - FD_ZERO(&rfds); - FD_ZERO(&wfds); - - for (i = 0; i < 3; i++) - { - if(fds[i].read_cb) - FD_SET(fds[i].fd, &rfds); - if(fds[i].write_cb) - FD_SET(fds[i].fd, &wfds); - } - - /* we have <3 fds ever, so I don't think select is too painful */ - ret = select(nfds, &rfds, &wfds, NULL, NULL); - - if(ret < 0) - { - check_error(ret, IO_SELECT, -1); /* exit on fatal errors */ - } - else if(ret > 0) - { - /* call any callbacks */ - for (i = 2; i >= 0; i--) - { - if(FD_ISSET(fds[i].fd, &rfds) && fds[i].read_cb) - (*fds[i].read_cb) (); - if(FD_ISSET(fds[i].fd, &wfds) && fds[i].write_cb) - (*fds[i].write_cb) (); - } - } - } -} - -void -send_data_blocking(int fd, unsigned char *data, int datalen) -{ - int ret; - fd_set wfds; - - while (1) - { - ret = write(fd, data, datalen); - - if(ret == datalen) - return; - else if(ret > 0) - { - data += ret; - datalen -= ret; - } - - ret = check_error(ret, IO_WRITE, fd); - - FD_ZERO(&wfds); - FD_SET(fd, &wfds); - - /* sleep until we can write to the fd */ - while (1) - { - ret = select(fd + 1, NULL, &wfds, NULL, NULL); - - if(ret > 0) /* break out so we can write */ - break; - - if(ret < 0) /* error ? */ - check_error(ret, IO_SELECT, fd); /* exit on fatal errors */ - - /* loop on non-fatal errors */ - } - } -} - -/* - * process_sendq: - * - * used before CMD_INIT to pass contents of SendQ from ircd - * to servlink. This data must _not_ be encrypted/compressed. - */ -void -process_sendq(struct ctrl_command *cmd) -{ - send_data_blocking(REMOTE.fd, cmd->data, cmd->datalen); -} - -/* - * process_recvq: - * - * used before CMD_INIT to pass contents of RecvQ from ircd - * to servlink. This data must be decrypted/decopmressed before - * sending back to the ircd. - */ -void -process_recvq(struct ctrl_command *cmd) -{ - int ret; - unsigned char *buf; - int blen; - unsigned char *data = cmd->data; - unsigned int datalen = cmd->datalen; - - buf = data; - blen = datalen; - ret = -1; - if(datalen > READLEN) - send_error("Error processing INJECT_RECVQ - buffer too long (%d > %d)", - datalen, READLEN); - -#ifdef HAVE_LIBZ - if(in_state.zip) - { - /* decompress data */ - in_state.zip_state.z_stream.next_in = buf; - in_state.zip_state.z_stream.avail_in = blen; - in_state.zip_state.z_stream.next_out = tmp2_buf; - in_state.zip_state.z_stream.avail_out = BUFLEN; - - buf = tmp2_buf; - while (in_state.zip_state.z_stream.avail_in) - { - if((ret = inflate(&in_state.zip_state.z_stream, Z_NO_FLUSH)) != Z_OK) - { - if(!strncmp("ERROR ", (char *)in_state.zip_state.z_stream.next_in, 6)) - send_error("Received uncompressed ERROR"); - else - send_error("Inflate failed: %s", zError(ret)); - } - blen = BUFLEN - in_state.zip_state.z_stream.avail_out; - - if(in_state.zip_state.z_stream.avail_in) - { - send_data_blocking(LOCAL.fd, buf, blen); - blen = 0; - in_state.zip_state.z_stream.next_out = buf; - in_state.zip_state.z_stream.avail_out = BUFLEN; - } - } - - if(!blen) - return; - } -#endif - - send_data_blocking(LOCAL.fd, buf, blen); -} - -void -send_zipstats(struct ctrl_command *unused) -{ -#ifdef HAVE_LIBZ - int i = 0; - int ret; - u_int32_t len; - if(!in_state.active || !out_state.active) - send_error("Error processing CMD_ZIPSTATS - link is not active!"); - if(!in_state.zip || !out_state.zip) - send_error("Error processing CMD_ZIPSTATS - link is not compressed!"); - - ctrl_buf[i++] = RPL_ZIPSTATS; - ctrl_buf[i++] = 0; - ctrl_buf[i++] = 16; - - len = (u_int32_t) in_state.zip_state.z_stream.total_out; - ctrl_buf[i++] = ((len >> 24) & 0xFF); - ctrl_buf[i++] = ((len >> 16) & 0xFF); - ctrl_buf[i++] = ((len >> 8) & 0xFF); - ctrl_buf[i++] = ((len) & 0xFF); - - len = (u_int32_t) in_state.zip_state.z_stream.total_in; - ctrl_buf[i++] = ((len >> 24) & 0xFF); - ctrl_buf[i++] = ((len >> 16) & 0xFF); - ctrl_buf[i++] = ((len >> 8) & 0xFF); - ctrl_buf[i++] = ((len) & 0xFF); - - len = (u_int32_t) out_state.zip_state.z_stream.total_in; - ctrl_buf[i++] = ((len >> 24) & 0xFF); - ctrl_buf[i++] = ((len >> 16) & 0xFF); - ctrl_buf[i++] = ((len >> 8) & 0xFF); - ctrl_buf[i++] = ((len) & 0xFF); - - len = (u_int32_t) out_state.zip_state.z_stream.total_out; - ctrl_buf[i++] = ((len >> 24) & 0xFF); - ctrl_buf[i++] = ((len >> 16) & 0xFF); - ctrl_buf[i++] = ((len >> 8) & 0xFF); - ctrl_buf[i++] = ((len) & 0xFF); - - in_state.zip_state.z_stream.total_in = 0; - in_state.zip_state.z_stream.total_out = 0; - out_state.zip_state.z_stream.total_in = 0; - out_state.zip_state.z_stream.total_out = 0; - - ret = check_error(write(CONTROL.fd, ctrl_buf, i), IO_WRITE, CONTROL.fd); - if(ret < i) - { - /* write incomplete, register write cb */ - CONTROL.write_cb = write_ctrl; - /* deregister read_cb */ - CONTROL.read_cb = NULL; - ctrl_ofs = ret; - ctrl_len = i - ret; - return; - } -#else - send_error("can't send_zipstats -- no zlib support!"); -#endif -} - -/* send_error - * - we ran into some problem, make a last ditch effort to - * flush the control fd sendq, then (blocking) send an - * error message over the control fd. - */ -void -send_error(const char *message, ...) -{ - va_list args; - static int sending_error = 0; - struct linger linger_opt = { 1, 30 }; /* wait 30 seconds */ - int len; - - if(sending_error) - exit(1); /* we did _try_ */ - - sending_error = 1; - - if(ctrl_len) /* attempt to flush any data we have... */ - { - send_data_blocking(CONTROL.fd, (ctrl_buf + ctrl_ofs), ctrl_len); - } - - /* prepare the message, in in_buf, since we won't be using it again.. */ - in_state.buf[0] = RPL_ERROR; - in_state.buf[1] = 0; - in_state.buf[2] = 0; - - va_start(args, message); - len = vsprintf((char *) in_state.buf + 3, message, args); - va_end(args); - - in_state.buf[3 + len++] = '\0'; - in_state.buf[1] = len >> 8; - in_state.buf[2] = len & 0xFF; - len += 3; - - send_data_blocking(CONTROL.fd, in_state.buf, len); - - /* XXX - is this portable? - * this obviously will fail on a non socket.. */ - setsockopt(CONTROL.fd, SOL_SOCKET, SO_LINGER, &linger_opt, sizeof(struct linger)); - - /* well, we've tried... */ - exit(1); /* now abort */ -} - -/* read_ctrl - * called when a command is waiting on the control pipe - */ -void -read_ctrl(void) -{ - int ret; - unsigned char tmp[2]; - unsigned char *len; - struct command_def *cdef; - static struct ctrl_command cmd = { 0, 0, 0, 0, NULL }; - - if(cmd.command == 0) /* we don't have a command yet */ - { - cmd.gotdatalen = 0; - cmd.datalen = 0; - cmd.readdata = 0; - cmd.data = NULL; - - /* read the command */ - if(!(ret = check_error(read(CONTROL.fd, tmp, 1), IO_READ, CONTROL.fd))) - return; - - cmd.command = tmp[0]; - } - - for (cdef = command_table; cdef->commandid; cdef++) - { - if((int)cdef->commandid == cmd.command) - break; - } - - if(!cdef->commandid) - { - send_error("Unsupported command (servlink/ircd out of sync?): %d", cmd.command); - /* NOTREACHED */ - } - - /* read datalen for commands including data */ - if(cdef->flags & COMMAND_FLAG_DATA) - { - if(cmd.gotdatalen < 2) - { - len = tmp; - if(!(ret = check_error(read(CONTROL.fd, len, - (2 - cmd.gotdatalen)), IO_READ, CONTROL.fd))) - return; - - if(cmd.gotdatalen == 0) - { - cmd.datalen = len[0] << 8; - cmd.gotdatalen++; - ret--; - len++; - } - if(ret && (cmd.gotdatalen == 1)) - { - cmd.datalen |= len[0]; - cmd.gotdatalen++; - if(cmd.datalen > 0) - cmd.data = calloc(cmd.datalen, 1); - } - } - } - - if(cmd.readdata < cmd.datalen) /* try to get any remaining data */ - { - if(!(ret = check_error(read(CONTROL.fd, - (cmd.data + cmd.readdata), - cmd.datalen - cmd.readdata), IO_READ, CONTROL.fd))) - return; - - cmd.readdata += ret; - if(cmd.readdata < cmd.datalen) - return; - } - - /* we now have the command and any data */ - (*cdef->handler) (&cmd); - - if(cmd.datalen > 0) - free(cmd.data); - cmd.command = 0; -} - -void -write_ctrl(void) -{ - int ret; - - assert(ctrl_len); - - if(!(ret = check_error(write(CONTROL.fd, (ctrl_buf + ctrl_ofs), - ctrl_len), IO_WRITE, CONTROL.fd))) - return; /* no data waiting */ - - ctrl_len -= ret; - - if(!ctrl_len) - { - /* write completed, de-register write cb */ - CONTROL.write_cb = NULL; - /* reregister read_cb */ - CONTROL.read_cb = read_ctrl; - ctrl_ofs = 0; - } - else - ctrl_ofs += ret; -} - -void -read_data(void) -{ - int ret, ret2; - unsigned char *buf = out_state.buf; - int blen; - ret2 = -1; - assert(!out_state.len); - -#if defined(HAVE_LIBZ) - if(out_state.zip || out_state.crypt) - buf = tmp_buf; -#endif - - while ((ret = check_error(read(LOCAL.fd, buf, READLEN), IO_READ, LOCAL.fd))) - { - blen = ret; -#ifdef HAVE_LIBZ - if(out_state.zip) - { - out_state.zip_state.z_stream.next_in = buf; - out_state.zip_state.z_stream.avail_in = ret; - - buf = out_state.buf; - out_state.zip_state.z_stream.next_out = buf; - out_state.zip_state.z_stream.avail_out = BUFLEN; - if(!(ret2 = deflate(&out_state.zip_state.z_stream, - Z_PARTIAL_FLUSH)) == Z_OK) - send_error("error compressing outgoing data - deflate returned: %s", - zError(ret2)); - - if(!out_state.zip_state.z_stream.avail_out) - send_error("error compressing outgoing data - avail_out == 0"); - if(out_state.zip_state.z_stream.avail_in) - send_error("error compressing outgoing data - avail_in != 0"); - - blen = BUFLEN - out_state.zip_state.z_stream.avail_out; - } -#endif - - - ret = check_error(write(REMOTE.fd, out_state.buf, blen), IO_WRITE, REMOTE.fd); - if(ret < blen) - { - /* write incomplete, register write cb */ - REMOTE.write_cb = write_net; - /* deregister read_cb */ - LOCAL.read_cb = NULL; - out_state.ofs = ret; - out_state.len = blen - ret; - return; - } -#if defined(HAVE_LIBZ) - if(out_state.zip) - buf = tmp_buf; -#endif - } - -} - -void -write_net(void) -{ - int ret; - - assert(out_state.len); - - if(!(ret = check_error(write(REMOTE.fd, - (out_state.buf + out_state.ofs), - out_state.len), IO_WRITE, REMOTE.fd))) - return; /* no data waiting */ - - out_state.len -= ret; - - if(!out_state.len) - { - /* write completed, de-register write cb */ - REMOTE.write_cb = NULL; - /* reregister read_cb */ - LOCAL.read_cb = read_data; - out_state.ofs = 0; - } - else - out_state.ofs += ret; -} - -void -read_net(void) -{ - int ret; - int ret2; - unsigned char *buf = in_state.buf; - int blen; - ret2 = -1; - assert(!in_state.len); - -#if defined(HAVE_LIBZ) - if(in_state.zip) - buf = tmp_buf; -#endif - - while ((ret = check_error(read(REMOTE.fd, buf, READLEN), IO_READ, REMOTE.fd))) - { - blen = ret; -#ifdef HAVE_LIBZ - if(in_state.zip) - { - /* decompress data */ - in_state.zip_state.z_stream.next_in = buf; - in_state.zip_state.z_stream.avail_in = ret; - in_state.zip_state.z_stream.next_out = in_state.buf; - in_state.zip_state.z_stream.avail_out = BUFLEN; - - while (in_state.zip_state.z_stream.avail_in) - { - if((ret2 = inflate(&in_state.zip_state.z_stream, - Z_NO_FLUSH)) != Z_OK) - { - if(!strncmp("ERROR ", (char *)buf, 6)) - send_error("Received uncompressed ERROR"); - send_error("Inflate failed: %s", zError(ret2)); - } - blen = BUFLEN - in_state.zip_state.z_stream.avail_out; - - if(in_state.zip_state.z_stream.avail_in) - { - if(blen) - { - send_data_blocking(LOCAL.fd, in_state.buf, blen); - blen = 0; - } - - in_state.zip_state.z_stream.next_out = in_state.buf; - in_state.zip_state.z_stream.avail_out = BUFLEN; - } - } - - if(!blen) - return; /* that didn't generate any decompressed input.. */ - } -#endif - - ret = check_error(write(LOCAL.fd, in_state.buf, blen), IO_WRITE, LOCAL.fd); - - if(ret < blen) - { - in_state.ofs = ret; - in_state.len = blen - ret; - /* write incomplete, register write cb */ - LOCAL.write_cb = write_data; - /* deregister read_cb */ - REMOTE.read_cb = NULL; - return; - } -#if defined(HAVE_LIBZ) - if(in_state.zip) - buf = tmp_buf; -#endif - } -} - -void -write_data(void) -{ - int ret; - - assert(in_state.len); - - if(!(ret = check_error(write(LOCAL.fd, - (in_state.buf + in_state.ofs), - in_state.len), IO_WRITE, LOCAL.fd))) - return; - - in_state.len -= ret; - - if(!in_state.len) - { - /* write completed, de-register write cb */ - LOCAL.write_cb = NULL; - /* reregister read_cb */ - REMOTE.read_cb = read_net; - in_state.ofs = 0; - } - else - in_state.ofs += ret; -} - -int -check_error(int ret, int io, int fd) -{ - if(ret > 0) /* no error */ - return ret; - if(ret == 0) /* EOF */ - { - send_error("%s failed on %s: EOF", IO_TYPE(io), FD_NAME(fd)); - exit(1); /* NOTREACHED */ - } - - /* ret == -1.. */ - switch (errno) - { - case EINPROGRESS: - case EWOULDBLOCK: -#if EAGAIN != EWOULDBLOCK - case EAGAIN: -#endif - case EALREADY: - case EINTR: -#ifdef ERESTART - case ERESTART: -#endif - /* non-fatal error, 0 bytes read */ - return 0; - } - - /* fatal error */ - send_error("%s failed on %s: %s", IO_TYPE(io), FD_NAME(fd), strerror(errno)); - exit(1); /* NOTREACHED */ -} diff --git a/servlink/io.h b/servlink/io.h deleted file mode 100644 index da2126a3..00000000 --- a/servlink/io.h +++ /dev/null @@ -1,48 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/io.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: io.h 6 2005-09-10 01:02:21Z nenolod $ - */ - -#ifndef INCLUDED_servlink_io_h -#define INCLUDED_servlink_io_h - -#include "control.h" - -#define IO_READ 0 -#define IO_WRITE 1 -#define IO_SELECT 2 - -#define IO_TYPE(io) ((io==IO_SELECT)?"select": \ - ((io==IO_WRITE)?"write":"read")) - -#define FD_NAME(fd) (fd_name(fd)) - -extern void io_loop(int nfds); -extern void write_data(void); -extern void read_data(void); -extern void write_ctrl(void); -extern void read_ctrl(void); -extern void write_net(void); -extern void read_net(void); -extern void send_error(const char *, ...); -extern void send_data_blocking(int fd, unsigned char *data, int datalen); -extern cmd_handler process_recvq; -extern cmd_handler process_sendq; -extern cmd_handler send_zipstats; - -#endif /* INCLUDED_servlink_io_h */ diff --git a/servlink/servlink.c b/servlink/servlink.c deleted file mode 100644 index 1276200c..00000000 --- a/servlink/servlink.c +++ /dev/null @@ -1,121 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/servlink.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: servlink.c 6 2005-09-10 01:02:21Z nenolod $ - */ - -#include "setup.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBZ -#include -#endif - -#include "servlink.h" -#include "io.h" -#include "control.h" - -static void usage(void); - -struct slink_state in_state; -struct slink_state out_state; - -struct fd_table fds[3] = { - {0, read_ctrl, NULL}, /* ctrl */ - {0, NULL, NULL}, /* data */ - {0, NULL, NULL}, /* net */ -}; - -/* usage(); - * - * Display usage message - */ -static void -usage(void) -{ - fprintf(stderr, "ircd-ratbox server link v1.2\n"); - fprintf(stderr, "2004-03-02\n"); - fprintf(stderr, "\n"); - fprintf(stderr, "This program is called by the ircd-ratbox ircd.\n"); - fprintf(stderr, "It cannot be used on its own.\n"); - exit(1); -} - -int -main(int argc, char *argv[]) -{ - int max_fd = 0; - int i, x; -#ifdef SERVLINK_DEBUG - int GDBAttached = 0; - - while (!GDBAttached) - sleep(1); -#endif - - /* Make sure we are running under ircd.. */ - - if(argc != 4 || strcmp(argv[0], "-slink")) - usage(); /* exits */ - - - for (i = 0; i < 3; i++) - { - fds[i].fd = atoi(argv[i + 1]); - if(fds[i].fd < 0) - exit(1); - } - - for (i = 0; i < 3; i++) - { - /* XXX: Hack alert...we need to do dup2() here for some dumb - * platforms (Solaris) that don't like select using fds > 255 - */ - - if(fds[i].fd >= 255) - { - for(x = 0; x < 255; x++) - { - if(x != fds[0].fd && x != fds[1].fd && x != fds[2].fd) - { - if(dup2(fds[i].fd, x) < 0) - exit(1); - close(fds[i].fd); - fds[i].fd = x; - break; - } - } - } - fcntl(fds[i].fd, F_SETFL, O_NONBLOCK); - if(fds[i].fd > max_fd) - max_fd = fds[i].fd; - } - - /* enter io loop */ - io_loop(max_fd + 1); - - /* NOTREACHED */ - return (0); -} /* main() */ diff --git a/servlink/servlink.h b/servlink/servlink.h deleted file mode 100644 index a0f37dea..00000000 --- a/servlink/servlink.h +++ /dev/null @@ -1,83 +0,0 @@ -/************************************************************************ - * IRC - Internet Relay Chat, servlink/servlink.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 1, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: servlink.h 1285 2006-05-05 15:03:53Z nenolod $ - */ - -#ifndef INCLUDED_servlink_servlink_h -#define INCLUDED_servlink_servlink_h - -#include "setup.h" - -#ifdef HAVE_LIBZ -#include -#endif - -/* do not use stdin/out/err, as it seems to break on solaris */ -#define CONTROL fds[0] -#define LOCAL fds[1] -#define REMOTE fds[2] - -#undef SERVLINK_DEBUG - -#define READLEN 16384 - -#ifdef HAVE_LIBZ -#define BUFLEN READLEN * 6 /* allow for decompression */ -#else -#define BUFLEN READLEN -#endif - - -#ifdef HAVE_LIBZ -struct zip_state -{ - z_stream z_stream; - int level; /* compression level */ -}; -#endif - -struct slink_state -{ - unsigned int crypt:1; - unsigned int zip:1; - unsigned int active:1; - - unsigned char buf[BUFLEN * 2]; - unsigned int ofs; - unsigned int len; - -#ifdef HAVE_LIBZ - struct zip_state zip_state; -#endif -}; - - -typedef void (io_callback) (void); - -struct fd_table -{ - int fd; - io_callback *read_cb; - io_callback *write_cb; -}; - -extern struct slink_state in_state; -extern struct slink_state out_state; -extern struct fd_table fds[3]; - -#endif /* INCLUDED_servlink_servlink_h */ diff --git a/ssld/Makefile.am b/ssld/Makefile.am new file mode 100644 index 00000000..f6aeb4c7 --- /dev/null +++ b/ssld/Makefile.am @@ -0,0 +1,14 @@ +# +# $Id: Makefile.am 24818 2008-01-02 18:38:26Z androsyn $ +# +bin_PROGRAMS = ssld +AM_CFLAGS=$(WARNFLAGS) + +INCLUDES = -I../include -I../libratbox/include + + +ssld_SOURCES = ssld.c + +ssld_LDADD = ../libratbox/src/libratbox.la @ZLIB_LD@ + + diff --git a/ssld/Makefile.in b/ssld/Makefile.in new file mode 100644 index 00000000..7504608c --- /dev/null +++ b/ssld/Makefile.in @@ -0,0 +1,499 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = ssld$(EXEEXT) +subdir = ssld +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/setup.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_ssld_OBJECTS = ssld.$(OBJEXT) +ssld_OBJECTS = $(am_ssld_OBJECTS) +ssld_DEPENDENCIES = ../libratbox/src/libratbox.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(ssld_SOURCES) +DIST_SOURCES = $(ssld_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETC_DIR = @ETC_DIR@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +GREP = @GREP@ +HELP_DIR = @HELP_DIR@ +INCLTDL = @INCLTDL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +IRCD_PREFIX = @IRCD_PREFIX@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBLTDL = @LIBLTDL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN = @LN@ +LN_S = @LN_S@ +LOG_DIR = @LOG_DIR@ +LTLIBOBJS = @LTLIBOBJS@ +LT_OBJDIR = @LT_OBJDIR@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MODULE_DIR = @MODULE_DIR@ +MV = @MV@ +NMEDIT = @NMEDIT@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PICFLAGS = @PICFLAGS@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SEDOBJ = @SEDOBJ@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SHLIBEXT = @SHLIBEXT@ +SQLITE_INCLUDES = @SQLITE_INCLUDES@ +SQLITE_LD = @SQLITE_LD@ +SQLITE_SUBDIR = @SQLITE_SUBDIR@ +SSL_INCLUDES = @SSL_INCLUDES@ +SSL_LIBS = @SSL_LIBS@ +SSL_SRCS_ENABLE = @SSL_SRCS_ENABLE@ +STRIP = @STRIP@ +TOUCH = @TOUCH@ +VERSION = @VERSION@ +WARNFLAGS = @WARNFLAGS@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +ZLIB_LD = @ZLIB_LD@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +confdir = @confdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +helpdir = @helpdir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +logdir = @logdir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +subdirs = @subdirs@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CFLAGS = $(WARNFLAGS) +INCLUDES = -I../include -I../libratbox/include +ssld_SOURCES = ssld.c +ssld_LDADD = ../libratbox/src/libratbox.la @ZLIB_LD@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ssld/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu ssld/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f $$p $$f"; \ + rm -f $$p $$f ; \ + done +ssld$(EXEEXT): $(ssld_OBJECTS) $(ssld_DEPENDENCIES) + @rm -f ssld$(EXEEXT) + $(LINK) $(ssld_OBJECTS) $(ssld_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssld.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ssld/ssld.c b/ssld/ssld.c new file mode 100644 index 00000000..238201cb --- /dev/null +++ b/ssld/ssld.c @@ -0,0 +1,1096 @@ +/* + * ssld.c: The ircd-ratbox ssl/zlib helper daemon thingy + * Copyright (C) 2007 Aaron Sethman + * Copyright (C) 2007 ircd-ratbox development team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + * + * $Id: ssld.c 25179 2008-03-30 16:34:57Z androsyn $ + */ + + +#include "stdinc.h" + +#ifdef HAVE_ZLIB +#include +#endif + +#define MAXPASSFD 4 +#ifndef READBUF_SIZE +#define READBUF_SIZE 16384 +#endif + +static void setup_signals(void); + +static inline rb_int32_t buf_to_int32(char *buf) +{ + rb_int32_t x; + x = *buf << 24; + x |= *(++buf) << 16; + x |= *(++buf) << 8; + x |= *(++buf); + return x; +} + +static inline void int32_to_buf(char *buf, rb_int32_t x) +{ + *(buf) = x >> 24 & 0xFF; + *(++buf) = x >> 16 & 0xFF; + *(++buf) = x >> 8 & 0xFF; + *(++buf) = x & 0xFF; + return; +} + +static inline rb_uint16_t buf_to_uint16(char *buf) +{ + rb_uint16_t x; + x = *(buf) << 8; + x |= *(++buf); + return x; +} + +static inline void uint16_to_buf(char *buf, rb_uint16_t x) +{ + *(buf) = x >> 8 & 0xFF; + *(++buf) = x & 0xFF; + return; +} + + + +static char inbuf[READBUF_SIZE]; +static char outbuf[READBUF_SIZE]; + +typedef struct _mod_ctl_buf +{ + rb_dlink_node node; + char *buf; + size_t buflen; + rb_fde_t *F[MAXPASSFD]; + int nfds; +} mod_ctl_buf_t; + +typedef struct _mod_ctl +{ + rb_dlink_node node; + int cli_count; + rb_fde_t *F; + rb_fde_t *F_pipe; + rb_dlink_list readq; + rb_dlink_list writeq; +} mod_ctl_t; + +static mod_ctl_t *mod_ctl; + + +#ifdef HAVE_ZLIB +typedef struct _zlib_stream +{ + z_stream instream; + z_stream outstream; +} zlib_stream_t; +#endif + +typedef struct _conn +{ + rb_dlink_node node; + mod_ctl_t *ctl; + rawbuf_head_t *modbuf_out; + rawbuf_head_t *plainbuf_out; + + rb_int32_t id; + + rb_fde_t *mod_fd; + rb_fde_t *plain_fd; + unsigned long long mod_out; + unsigned long long mod_in; + unsigned long long plain_in; + unsigned long long plain_out; + rb_uint8_t flags; + void *stream; +} conn_t; + +#define FLAG_SSL 0x01 +#define FLAG_ZIP 0x02 +#define FLAG_CORK 0x04 +#define FLAG_DEAD 0x08 + + +#define IsSSL(x) ((x)->flags & FLAG_SSL) +#define IsZip(x) ((x)->flags & FLAG_ZIP) +#define IsCork(x) ((x)->flags & FLAG_CORK) +#define IsDead(x) ((x)->flags & FLAG_DEAD) + +#define SetSSL(x) ((x)->flags |= FLAG_SSL) +#define SetZip(x) ((x)->flags |= FLAG_ZIP) +#define SetCork(x) ((x)->flags |= FLAG_CORK) +#define SetDead(x) ((x)->flags |= FLAG_DEAD) + +#define ClearSSL(x) ((x)->flags &= ~FLAG_SSL) +#define ClearZip(x) ((x)->flags &= ~FLAG_ZIP) +#define ClearCork(x) ((x)->flags &= ~FLAG_CORK) +#define ClearDead(x) ((x)->flags &= ~FLAG_DEAD) + +#define NO_WAIT 0x0 +#define WAIT_PLAIN 0x1 + +#define CONN_HASH_SIZE 2000 +#define connid_hash(x) (&connid_hash_table[(x % CONN_HASH_SIZE)]) + +static rb_dlink_list connid_hash_table[CONN_HASH_SIZE]; +static rb_dlink_list dead_list; + +static void conn_mod_write_sendq(rb_fde_t *, void *data); +static void conn_plain_write_sendq(rb_fde_t *, void *data); +static void mod_write_ctl(rb_fde_t *, void *data); +static void conn_plain_read_cb(rb_fde_t * fd, void *data); +static void mod_cmd_write_queue(mod_ctl_t *ctl, const void *data, size_t len); +static const char *remote_closed = "Remote host closed the connection"; +static int ssl_ok; +#ifdef HAVE_ZLIB +static int zlib_ok = 1; +#else +static int zlib_ok = 0; +#endif +static void * +ssld_alloc(void *unused, size_t count, size_t size) +{ + return rb_malloc(count * size); +} + +static void +ssld_free(void *unused, void *ptr) +{ + rb_free(ptr); +} + +static conn_t * +conn_find_by_id(rb_int32_t id) +{ + rb_dlink_node *ptr; + conn_t *conn; + + RB_DLINK_FOREACH(ptr, (connid_hash(id))->head) + { + conn = ptr->data; + if(conn->id == id && !IsDead(conn)) + return conn; + } + return NULL; +} + +static void +conn_add_id_hash(conn_t * conn, rb_int32_t id) +{ + conn->id = id; + rb_dlinkAdd(conn, &conn->node, connid_hash(id)); +} + +static void +free_conn(conn_t * conn) +{ + rb_free_rawbuffer(conn->modbuf_out); + rb_free_rawbuffer(conn->plainbuf_out); + if(IsZip(conn)) + { + zlib_stream_t *stream = conn->stream; + inflateEnd(&stream->instream); + deflateEnd(&stream->outstream); + } + rb_free(conn); +} + +static void +clean_dead_conns(void *unused) +{ + conn_t *conn; + rb_dlink_node *ptr, *next; + RB_DLINK_FOREACH_SAFE(ptr, next, dead_list.head) + { + conn = ptr->data; + free_conn(conn); + } + dead_list.tail = dead_list.head = NULL; +} + + +static void +close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) +{ + va_list ap; + char reason[128]; /* must always be under 250 bytes */ + char buf[256]; + int len; + if(IsDead(conn)) + return; + + rb_rawbuf_flush(conn->modbuf_out, conn->mod_fd); + rb_rawbuf_flush(conn->plainbuf_out, conn->plain_fd); + rb_close(conn->mod_fd); + SetDead(conn); + + if(!wait_plain || fmt == NULL) + { + rb_close(conn->plain_fd); + + if(conn->id >= 0) + rb_dlinkDelete(&conn->node, connid_hash(conn->id)); + rb_dlinkAdd(conn, &conn->node, &dead_list); + return; + } + rb_setselect(conn->plain_fd, RB_SELECT_WRITE|RB_SELECT_READ, NULL, NULL); + va_start(ap, fmt); + rb_vsnprintf(reason, sizeof(reason), fmt, ap); + va_end(ap); + + buf[0] = 'D'; + int32_to_buf(&buf[1], conn->id); + strcpy(&buf[5], reason); + len = (strlen(reason) + 1) + 5; + mod_cmd_write_queue(conn->ctl, buf, len); +} + +static conn_t * +make_conn(mod_ctl_t *ctl, rb_fde_t * mod_fd, rb_fde_t * plain_fd) +{ + conn_t *conn = rb_malloc(sizeof(conn_t)); + conn->ctl = ctl; + conn->modbuf_out = rb_new_rawbuffer(); + conn->plainbuf_out = rb_new_rawbuffer(); + conn->mod_fd = mod_fd; + conn->plain_fd = plain_fd; + conn->id = -1; + conn->stream = NULL; + rb_set_nb(mod_fd); + rb_set_nb(plain_fd); + return conn; +} + +static void +conn_mod_write_sendq(rb_fde_t * fd, void *data) +{ + conn_t *conn = data; + const char *err; + int retlen; + if(IsDead(conn)) + return; + + while ((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0) + conn->mod_out += retlen; + + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + { + if(retlen == 0) + close_conn(conn, WAIT_PLAIN, "%s", remote_closed); + if(IsSSL(conn) && retlen == RB_RW_SSL_ERROR) + err = rb_get_ssl_strerror(conn->mod_fd); + else + err = strerror(errno); + close_conn(conn, WAIT_PLAIN, "Write error: %s", err); + return; + } + if(rb_rawbuf_length(conn->modbuf_out) > 0) + { + int flags = RB_SELECT_WRITE; + if(retlen == RB_RW_SSL_NEED_READ) + flags |= RB_SELECT_READ; + + rb_setselect(conn->mod_fd, flags, conn_mod_write_sendq, conn); + } + else + rb_setselect(conn->mod_fd, RB_SELECT_WRITE, NULL, NULL); + + if(IsCork(conn) && rb_rawbuf_length(conn->modbuf_out) == 0) + { + ClearCork(conn); + conn_plain_read_cb(conn->plain_fd, conn); + } + +} + +static void +conn_mod_write(conn_t * conn, void *data, size_t len) +{ + if(IsDead(conn)) /* no point in queueing to a dead man */ + return; + rb_rawbuf_append(conn->modbuf_out, data, len); +} + +static void +conn_plain_write(conn_t * conn, void *data, size_t len) +{ + if(IsDead(conn)) /* again no point in queueing to dead men */ + return; + rb_rawbuf_append(conn->plainbuf_out, data, len); +} + +static void +mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len) +{ + mod_ctl_buf_t *ctl_buf; + ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t)); + ctl_buf->buf = rb_malloc(len); + ctl_buf->buflen = len; + memcpy(ctl_buf->buf, data, len); + ctl_buf->nfds = 0; + rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->writeq); + mod_write_ctl(ctl->F, ctl); +} + +#ifdef HAVE_ZLIB +static void +common_zlib_deflate(conn_t * conn, void *buf, size_t len) +{ + int ret, have; + z_stream *outstream = &((zlib_stream_t *)conn->stream)->outstream; + outstream->next_in = buf; + outstream->avail_in = len; + outstream->next_out = (Bytef *) outbuf; + outstream->avail_out = sizeof(outbuf); + + ret = deflate(outstream, Z_SYNC_FLUSH); + if(ret != Z_OK) + { + /* deflate error */ + close_conn(conn, WAIT_PLAIN, "Deflate failed: %s", zError(ret)); + return; + } + if(outstream->avail_out == 0) + { + /* avail_out empty */ + close_conn(conn, WAIT_PLAIN, "error compressing data, avail_out == 0"); + return; + } + if(outstream->avail_in != 0) + { + /* avail_in isn't empty...*/ + close_conn(conn, WAIT_PLAIN, "error compressing data, avail_in != 0"); + return; + } + have = sizeof(outbuf) - outstream->avail_out; + conn_mod_write(conn, outbuf, have); +} + +static void +common_zlib_inflate(conn_t * conn, void *buf, size_t len) +{ + int ret, have; + ((zlib_stream_t *)conn->stream)->instream.next_in = buf; + ((zlib_stream_t *)conn->stream)->instream.avail_in = len; + ((zlib_stream_t *)conn->stream)->instream.next_out = (Bytef *) outbuf; + ((zlib_stream_t *)conn->stream)->instream.avail_out = sizeof(outbuf); + + while (((zlib_stream_t *)conn->stream)->instream.avail_in) + { + ret = inflate(&((zlib_stream_t *)conn->stream)->instream, Z_NO_FLUSH); + if(ret != Z_OK) + { + if(!strncmp("ERROR ", buf, 6)) + { + close_conn(conn, WAIT_PLAIN, "Received uncompressed ERROR"); + return; + } + close_conn(conn, WAIT_PLAIN, "Inflate failed: %s", zError(ret)); + return; + } + have = sizeof(outbuf) - ((zlib_stream_t *)conn->stream)->instream.avail_out; + + if(((zlib_stream_t *)conn->stream)->instream.avail_in) + { + conn_plain_write(conn, outbuf, have); + have = 0; + ((zlib_stream_t *)conn->stream)->instream.next_out = (Bytef *) outbuf; + ((zlib_stream_t *)conn->stream)->instream.avail_out = sizeof(outbuf); + } + } + if(have == 0) + return; + + conn_plain_write(conn, outbuf, have); +} +#endif + +static int +plain_check_cork(conn_t * conn) +{ + if(rb_rawbuf_length(conn->modbuf_out) >= 4096) + { + /* if we have over 4k pending outbound, don't read until + * we've cleared the queue */ + SetCork(conn); + rb_setselect(conn->plain_fd, RB_SELECT_READ, NULL, NULL); + /* try to write */ + conn_mod_write_sendq(conn->mod_fd, conn); + return 1; + } + return 0; +} + + +static void +conn_plain_read_cb(rb_fde_t * fd, void *data) +{ + conn_t *conn = data; + int length = 0; + if(conn == NULL) + return; + + if(IsDead(conn)) + return; + + if(plain_check_cork(conn)) + return; + + while (1) + { + if(IsDead(conn)) + return; + + length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf)); + + if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) + { + close_conn(conn, NO_WAIT, NULL); + return; + } + + if(length < 0) + { + rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_cb, conn); + conn_mod_write_sendq(conn->mod_fd, conn); + return; + } + conn->plain_in += length; + +#ifdef HAVE_ZLIB + if(IsZip(conn)) + common_zlib_deflate(conn, inbuf, length); + else +#endif + conn_mod_write(conn, inbuf, length); + if(IsDead(conn)) + return; + if(plain_check_cork(conn)) + return; + } +} + +static void +conn_mod_read_cb(rb_fde_t * fd, void *data) +{ + conn_t *conn = data; + const char *err = remote_closed; + int length; + if(conn == NULL) + return; + if(IsDead(conn)) + return; + + while (1) + { + if(IsDead(conn)) + return; + + length = rb_read(conn->mod_fd, inbuf, sizeof(inbuf)); + + if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) + { + if(length == 0) { + close_conn(conn, WAIT_PLAIN, "%s", remote_closed); + return; + } + + if(IsSSL(conn) && length == RB_RW_SSL_ERROR) + err = rb_get_ssl_strerror(conn->mod_fd); + else + err = strerror(errno); + close_conn(conn, WAIT_PLAIN, "Read error: %s", err); + return; + } + if(length < 0) + { + int flags = RB_SELECT_READ; + if(length == RB_RW_SSL_NEED_WRITE) + flags |= RB_SELECT_WRITE; + + rb_setselect(conn->mod_fd, flags, conn_mod_read_cb, conn); + conn_plain_write_sendq(conn->plain_fd, conn); + return; + } + conn->mod_in += length; +#ifdef HAVE_ZLIB + if(IsZip(conn)) + common_zlib_inflate(conn, inbuf, length); + else +#endif + conn_plain_write(conn, inbuf, length); + } +} + +static void +conn_plain_write_sendq(rb_fde_t * fd, void *data) +{ + conn_t *conn = data; + int retlen; + + if(IsDead(conn)) + return; + + while ((retlen = rb_rawbuf_flush(conn->plainbuf_out, fd)) > 0) + { + conn->plain_out += retlen; + } + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + { + close_conn(data, NO_WAIT, NULL); + return; + } + + + if(rb_rawbuf_length(conn->plainbuf_out) > 0) + rb_setselect(conn->plain_fd, RB_SELECT_WRITE, conn_plain_write_sendq, conn); + else + rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL); +} + +static int +maxconn(void) +{ +#if defined(RLIMIT_NOFILE) && defined(HAVE_SYS_RESOURCE_H) + struct rlimit limit; + + if(!getrlimit(RLIMIT_NOFILE, &limit)) + { + return limit.rlim_cur; + } +#endif /* RLIMIT_FD_MAX */ + return MAXCONNECTIONS; +} + +static void +ssl_process_accept_cb(rb_fde_t * F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) +{ + conn_t *conn = data; + if(status == RB_OK) + { + conn_mod_read_cb(conn->mod_fd, conn); + conn_plain_read_cb(conn->plain_fd, conn); + return; + } + close_conn(conn, NO_WAIT, 0); + return; +} + +static void +ssl_process_connect_cb(rb_fde_t * F, int status, void *data) +{ + conn_t *conn = data; + if(status == RB_OK) + { + conn_mod_read_cb(conn->mod_fd, conn); + conn_plain_read_cb(conn->plain_fd, conn); + return; + } + close_conn(conn, NO_WAIT, 0); + return; +} + + +static void +ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + conn_t *conn; + rb_int32_t id; + + conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); + + id = buf_to_int32(&ctlb->buf[1]); + + if(id >= 0) + conn_add_id_hash(conn, id); + SetSSL(conn); + + if(rb_get_type(conn->mod_fd) & RB_FD_UNKNOWN) + { + + rb_set_type(conn->mod_fd, RB_FD_SOCKET); + } + if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) + rb_set_type(conn->plain_fd, RB_FD_SOCKET); + + rb_ssl_start_accepted(ctlb->F[0], ssl_process_accept_cb, conn, 10); +} + +static void +ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + conn_t *conn; + rb_int32_t id; + conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); + + id = buf_to_int32(&ctlb->buf[1]); + + if(id >= 0) + conn_add_id_hash(conn, id); + SetSSL(conn); + + if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) + rb_set_type(conn->mod_fd, RB_FD_SOCKET); + + if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) + rb_set_type(conn->plain_fd, RB_FD_SOCKET); + + + rb_ssl_start_connected(ctlb->F[0], ssl_process_connect_cb, conn, 10); +} + +static void +process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + char outstat[512]; + conn_t *conn; + const char *odata; + rb_int32_t id; + + id = buf_to_int32(&ctlb->buf[1]); + + if(id < 0) + return; + + odata = &ctlb->buf[5]; + conn = conn_find_by_id(id); + + if(conn == NULL) + return; + + rb_snprintf(outstat, sizeof(outstat), "S %s %llu %llu %llu %llu", odata, + conn->plain_out, conn->mod_in, conn->plain_in, conn->mod_out); + conn->plain_out = 0; + conn->plain_in = 0; + conn->mod_in = 0; + conn->mod_out = 0; + mod_cmd_write_queue(ctl, outstat, strlen(outstat) + 1); /* +1 is so we send the \0 as well */ +} + +#ifdef HAVE_ZLIB +static void +zlib_send_zip_ready(mod_ctl_t *ctl, conn_t *conn) +{ + char buf[5]; + + buf[0] = 'R'; + int32_to_buf(&buf[1], conn->id); + mod_cmd_write_queue(conn->ctl, buf, sizeof(buf)); +} + +static void +zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + rb_uint8_t level; + size_t recvqlen; + size_t hdr = (sizeof(rb_uint8_t) * 2) + sizeof(rb_int32_t); + void *recvq_start; + z_stream *instream, *outstream; + conn_t *conn; + rb_int32_t id; + + conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); + if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) + rb_set_type(conn->mod_fd, RB_FD_SOCKET); + + if(rb_get_type(conn->plain_fd) == RB_FD_UNKNOWN) + rb_set_type(conn->plain_fd, RB_FD_SOCKET); + + id = buf_to_int32(&ctlb->buf[1]); + conn_add_id_hash(conn, id); + + level = (rb_uint8_t) ctlb->buf[5]; + + recvqlen = ctlb->buflen - hdr; + recvq_start = &ctlb->buf[6]; + + SetZip(conn); + conn->stream = rb_malloc(sizeof(zlib_stream_t)); + instream = &((zlib_stream_t *)conn->stream)->instream; + outstream = &((zlib_stream_t *)conn->stream)->outstream; + + instream->total_in = 0; + instream->total_out = 0; + instream->zalloc = (alloc_func) ssld_alloc; + instream->zfree = (free_func) ssld_free; + instream->data_type = Z_ASCII; + inflateInit(&((zlib_stream_t *)conn->stream)->instream); + + outstream->total_in = 0; + outstream->total_out = 0; + outstream->zalloc = (alloc_func) ssld_alloc; + outstream->zfree = (free_func) ssld_free; + outstream->data_type = Z_ASCII; + + if(level > 9) + level = Z_DEFAULT_COMPRESSION; + + deflateInit(&((zlib_stream_t *)conn->stream)->outstream, level); + if(recvqlen > 0) + common_zlib_inflate(conn, recvq_start, recvqlen); + zlib_send_zip_ready(ctl, conn); + conn_mod_read_cb(conn->mod_fd, conn); + conn_plain_read_cb(conn->plain_fd, conn); + return; + +} +#endif + +static void +init_prng(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) +{ + char *path; + prng_seed_t seed_type; + + seed_type = (prng_seed_t)ctl_buf->buf[1]; + path = &ctl_buf->buf[2]; + rb_init_prng(path, seed_type); +} + + +static void +ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) +{ + char *buf; + char *cert, *key, *dhparam; + + buf = &ctl_buf->buf[2]; + cert = buf; + buf += strlen(cert) + 1; + key = buf; + buf += strlen(key) + 1; + dhparam = buf; + if(strlen(dhparam) == 0) + dhparam = NULL; + + if(!rb_setup_ssl_server(cert, key, dhparam)) + { + const char *invalid = "I"; + mod_cmd_write_queue(ctl, invalid, strlen(invalid)); + return; + } +} + +static void +send_nossl_support(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) +{ + static const char *nossl_cmd = "N"; + conn_t *conn; + rb_int32_t id; + + if(ctlb != NULL) + { + conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); + id = buf_to_int32(&ctlb->buf[1]); + + if(id >= 0) + conn_add_id_hash(conn, id); + close_conn(conn, WAIT_PLAIN, "libratbox reports no SSL/TLS support"); + } + mod_cmd_write_queue(ctl, nossl_cmd, strlen(nossl_cmd)); +} + +static void +send_i_am_useless(mod_ctl_t *ctl) +{ + static const char *useless = "U"; + mod_cmd_write_queue(ctl, useless, strlen(useless)); +} + +static void +send_nozlib_support(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) +{ + static const char *nozlib_cmd = "z"; + conn_t *conn; + rb_int32_t id; + if(ctlb != NULL) + { + conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); + id = buf_to_int32(&ctlb->buf[1]); + + if(id >= 0) + conn_add_id_hash(conn, id); + close_conn(conn, WAIT_PLAIN, "libratbox reports no zlib support"); + } + mod_cmd_write_queue(ctl, nozlib_cmd, strlen(nozlib_cmd)); +} + +static void +mod_process_cmd_recv(mod_ctl_t * ctl) +{ + rb_dlink_node *ptr, *next; + mod_ctl_buf_t *ctl_buf; + + RB_DLINK_FOREACH_SAFE(ptr, next, ctl->readq.head) + { + ctl_buf = ptr->data; + + switch (*ctl_buf->buf) + { + case 'A': + { + if(!ssl_ok) + { + send_nossl_support(ctl, ctl_buf); + break; + } + ssl_process_accept(ctl, ctl_buf); + break; + } + case 'C': + { + if(!ssl_ok) + { + send_nossl_support(ctl, ctl_buf); + break; + } + ssl_process_connect(ctl, ctl_buf); + break; + } + + case 'K': + { + if(!ssl_ok) + { + send_nossl_support(ctl, ctl_buf); + break; + } + ssl_new_keys(ctl, ctl_buf); + break; + } + case 'I': + init_prng(ctl, ctl_buf); + break; + case 'S': + { + process_stats(ctl, ctl_buf); + break; + } +#ifdef HAVE_ZLIB + case 'Z': + { + /* just zlib only */ + zlib_process(ctl, ctl_buf); + break; + } +#else + case 'Y': + case 'Z': + send_nozlib_support(ctl); + break; + +#endif + default: + break; + /* Log unknown commands */ + } + rb_dlinkDelete(ptr, &ctl->readq); + rb_free(ctl_buf->buf); + rb_free(ctl_buf); + } + +} + + + +static void +mod_read_ctl(rb_fde_t * F, void *data) +{ + mod_ctl_buf_t *ctl_buf; + mod_ctl_t *ctl = data; + int retlen; + + do + { + ctl_buf = rb_malloc(sizeof(mod_ctl_buf_t)); + ctl_buf->buf = rb_malloc(READBUF_SIZE); + ctl_buf->buflen = READBUF_SIZE; + retlen = rb_recv_fd_buf(ctl->F, ctl_buf->buf, ctl_buf->buflen, ctl_buf->F, + MAXPASSFD); + if(retlen <= 0) + { + rb_free(ctl_buf->buf); + rb_free(ctl_buf); + } + else + { + ctl_buf->buflen = retlen; + rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq); + } + } + while (retlen > 0); + + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + exit(0); + + mod_process_cmd_recv(ctl); + rb_setselect(ctl->F, RB_SELECT_READ, mod_read_ctl, ctl); +} + +static void +mod_write_ctl(rb_fde_t * F, void *data) +{ + mod_ctl_t *ctl = data; + mod_ctl_buf_t *ctl_buf; + rb_dlink_node *ptr, *next; + int retlen, x; + + RB_DLINK_FOREACH_SAFE(ptr, next, ctl->writeq.head) + { + ctl_buf = ptr->data; + retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf, + ctl_buf->buflen); + if(retlen > 0) + { + rb_dlinkDelete(ptr, &ctl->writeq); + for (x = 0; x < ctl_buf->nfds; x++) + rb_close(ctl_buf->F[x]); + rb_free(ctl_buf->buf); + rb_free(ctl_buf); + + } + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + exit(0); + + rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl); + } +} + + +static void +read_pipe_ctl(rb_fde_t * F, void *data) +{ + int retlen; + while ((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0) + { + ;; /* we don't do anything with the pipe really, just care if the other process dies.. */ + } + if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) + exit(0); + rb_setselect(F, RB_SELECT_READ, read_pipe_ctl, NULL); + +} + +int +main(int argc, char **argv) +{ + const char *s_ctlfd, *s_pipe; + int ctlfd, pipefd, x, maxfd; + maxfd = maxconn(); + s_ctlfd = getenv("CTL_FD"); + s_pipe = getenv("CTL_PIPE"); + + if(s_ctlfd == NULL || s_pipe == NULL) + { + fprintf(stderr, "This is ircd-ratbox ssld. You know you aren't supposed to run me directly?\n"); + fprintf(stderr, "You get an Id tag for this: $Id: ssld.c 25179 2008-03-30 16:34:57Z androsyn $\n"); + fprintf(stderr, "Have a nice life\n"); + exit(1); + } + + ctlfd = atoi(s_ctlfd); + pipefd = atoi(s_pipe); + + for (x = 0; x < maxfd; x++) + { + if(x != ctlfd && x != pipefd && x > 2) + close(x); + } + +#if 0 + x = open("/dev/null", O_RDWR); + if(x >= 0) + { + if(ctlfd != 0 && pipefd != 0) + dup2(x, 0); + if(ctlfd != 1 && pipefd != 1) + dup2(x, 1); + if(ctlfd != 2 && pipefd != 2) + dup2(x, 2); + if(x > 2) + close(x); + } +#endif + setup_signals(); + rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096); + rb_init_rawbuffers(1024); + ssl_ok = rb_supports_ssl(); + + mod_ctl = rb_malloc(sizeof(mod_ctl_t)); + mod_ctl->F = rb_open(ctlfd, RB_FD_SOCKET, "ircd control socket"); + mod_ctl->F_pipe = rb_open(pipefd, RB_FD_PIPE, "ircd pipe"); + rb_set_nb(mod_ctl->F); + rb_set_nb(mod_ctl->F_pipe); + rb_event_addish("clean_dead_conns", clean_dead_conns, NULL, 10); + read_pipe_ctl(mod_ctl->F_pipe, NULL); + mod_read_ctl(mod_ctl->F, mod_ctl); + if(!zlib_ok && !ssl_ok) + { + /* this is really useless... */ + send_i_am_useless(mod_ctl); + /* sleep until the ircd kills us */ + rb_sleep(2<<30, 0); + exit(1); + } + + if(!zlib_ok) + send_nozlib_support(mod_ctl, NULL); + if(!ssl_ok) + send_nossl_support(mod_ctl, NULL); + rb_lib_loop(0); + return 0; +} + + + +static void +dummy_handler(int sig) +{ + return; +} + +static void +setup_signals() +{ + struct sigaction act; + + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGPIPE); + sigaddset(&act.sa_mask, SIGALRM); +#ifdef SIGTRAP + sigaddset(&act.sa_mask, SIGTRAP); +#endif + +#ifdef SIGWINCH + sigaddset(&act.sa_mask, SIGWINCH); + sigaction(SIGWINCH, &act, 0); +#endif + sigaction(SIGPIPE, &act, 0); +#ifdef SIGTRAP + sigaction(SIGTRAP, &act, 0); +#endif + + act.sa_handler = dummy_handler; + sigaction(SIGALRM, &act, 0); +} +