X-Git-Url: https://jfr.im/git/irc/rqf/shadowircd.git/blobdiff_plain/03d5e1e46b565ad1094bc169ce1cff210ec8c105..6ec1ddabff92d9af0a2f671b56310db417cc71eb:/ssld/ssld.c diff --git a/ssld/ssld.c b/ssld/ssld.c index 42031a5..9870b70 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * - * $Id: ssld.c 25221 2008-04-09 22:12:16Z jilles $ + * $Id$ */ @@ -34,45 +34,43 @@ #endif static void setup_signals(void); +static pid_t ppid; -static inline rb_int32_t buf_to_int32(char *buf) +static inline int32_t +buf_to_int32(char *buf) { - rb_int32_t x; - x = *buf << 24; - x |= *(++buf) << 16; - x |= *(++buf) << 8; - x |= *(++buf); + int32_t x; + memcpy(&x, buf, sizeof(x)); return x; } -static inline void int32_to_buf(char *buf, rb_int32_t x) +static inline void +int32_to_buf(char *buf, int32_t x) { - *(buf) = x >> 24 & 0xFF; - *(++buf) = x >> 16 & 0xFF; - *(++buf) = x >> 8 & 0xFF; - *(++buf) = x & 0xFF; + memcpy(buf, &x, sizeof(x)); return; } -static inline rb_uint16_t buf_to_uint16(char *buf) +static inline uint16_t +buf_to_uint16(char *buf) { - rb_uint16_t x; - x = *(buf) << 8; - x |= *(++buf); + uint16_t x; + memcpy(&x, buf, sizeof(x)); return x; } -static inline void uint16_to_buf(char *buf, rb_uint16_t x) +static inline void +uint16_to_buf(char *buf, uint16_t x) { - *(buf) = x >> 8 & 0xFF; - *(++buf) = x & 0xFF; + memcpy(buf, &x, sizeof(x)); return; } - static char inbuf[READBUF_SIZE]; +#ifdef HAVE_LIBZ static char outbuf[READBUF_SIZE]; +#endif typedef struct _mod_ctl_buf { @@ -111,7 +109,7 @@ typedef struct _conn rawbuf_head_t *modbuf_out; rawbuf_head_t *plainbuf_out; - rb_int32_t id; + int32_t id; rb_fde_t *mod_fd; rb_fde_t *plain_fd; @@ -119,7 +117,7 @@ typedef struct _conn unsigned long long mod_in; unsigned long long plain_in; unsigned long long plain_out; - rb_uint8_t flags; + uint8_t flags; void *stream; } conn_t; @@ -127,8 +125,9 @@ typedef struct _conn #define FLAG_ZIP 0x02 #define FLAG_CORK 0x04 #define FLAG_DEAD 0x08 -#define FLAG_SSL_W_WANTS_R 0x10 /* output needs to wait until input possible */ -#define FLAG_SSL_R_WANTS_W 0x20 /* input needs to wait until output possible */ +#define FLAG_SSL_W_WANTS_R 0x10 /* output needs to wait until input possible */ +#define FLAG_SSL_R_WANTS_W 0x20 /* input needs to wait until output possible */ +#define FLAG_ZIPSSL 0x40 #define IsSSL(x) ((x)->flags & FLAG_SSL) #define IsZip(x) ((x)->flags & FLAG_ZIP) @@ -136,6 +135,7 @@ typedef struct _conn #define IsDead(x) ((x)->flags & FLAG_DEAD) #define IsSSLWWantsR(x) ((x)->flags & FLAG_SSL_W_WANTS_R) #define IsSSLRWantsW(x) ((x)->flags & FLAG_SSL_R_WANTS_W) +#define IsZipSSL(x) ((x)->flags & FLAG_ZIPSSL) #define SetSSL(x) ((x)->flags |= FLAG_SSL) #define SetZip(x) ((x)->flags |= FLAG_ZIP) @@ -143,6 +143,7 @@ typedef struct _conn #define SetDead(x) ((x)->flags |= FLAG_DEAD) #define SetSSLWWantsR(x) ((x)->flags |= FLAG_SSL_W_WANTS_R) #define SetSSLRWantsW(x) ((x)->flags |= FLAG_SSL_R_WANTS_W) +#define SetZipSSL(x) ((x)->flags |= FLAG_ZIPSSL) #define ClearSSL(x) ((x)->flags &= ~FLAG_SSL) #define ClearZip(x) ((x)->flags &= ~FLAG_ZIP) @@ -150,22 +151,28 @@ typedef struct _conn #define ClearDead(x) ((x)->flags &= ~FLAG_DEAD) #define ClearSSLWWantsR(x) ((x)->flags &= ~FLAG_SSL_W_WANTS_R) #define ClearSSLRWantsW(x) ((x)->flags &= ~FLAG_SSL_R_WANTS_W) +#define ClearZipSSL(x) ((x)->flags &= ~FLAG_ZIPSSL) #define NO_WAIT 0x0 #define WAIT_PLAIN 0x1 +#define HASH_WALK_SAFE(i, max, ptr, next, table) for(i = 0; i < max; i++) { RB_DLINK_FOREACH_SAFE(ptr, next, table[i].head) +#define HASH_WALK_END } #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_read_cb(rb_fde_t * fd, void *data); +static void conn_mod_read_cb(rb_fde_t *fd, void *data); 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 void conn_plain_read_cb(rb_fde_t *fd, void *data); +static void conn_plain_read_shutdown_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_LIBZ @@ -173,6 +180,9 @@ static int zlib_ok = 1; #else static int zlib_ok = 0; #endif + + +#ifdef HAVE_LIBZ static void * ssld_alloc(void *unused, size_t count, size_t size) { @@ -182,11 +192,12 @@ ssld_alloc(void *unused, size_t count, size_t size) static void ssld_free(void *unused, void *ptr) { - rb_free(ptr); + rb_free(ptr); } +#endif static conn_t * -conn_find_by_id(rb_int32_t id) +conn_find_by_id(int32_t id) { rb_dlink_node *ptr; conn_t *conn; @@ -201,7 +212,7 @@ conn_find_by_id(rb_int32_t id) } static void -conn_add_id_hash(conn_t * conn, rb_int32_t id) +conn_add_id_hash(conn_t * conn, int32_t id) { conn->id = id; rb_dlinkAdd(conn, &conn->node, connid_hash(id)); @@ -212,12 +223,14 @@ free_conn(conn_t * conn) { rb_free_rawbuffer(conn->modbuf_out); rb_free_rawbuffer(conn->plainbuf_out); +#ifdef HAVE_LIBZ if(IsZip(conn)) { zlib_stream_t *stream = conn->stream; inflateEnd(&stream->instream); - deflateEnd(&stream->outstream); + deflateEnd(&stream->outstream); } +#endif rb_free(conn); } @@ -239,27 +252,28 @@ 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 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(conn->id >= 0 && !IsZipSSL(conn)) + rb_dlinkDelete(&conn->node, connid_hash(conn->id)); + 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); + rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn); + rb_setselect(conn->plain_fd, RB_SELECT_WRITE, NULL, NULL); va_start(ap, fmt); rb_vsnprintf(reason, sizeof(reason), fmt, ap); va_end(ap); @@ -272,7 +286,7 @@ close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) } static conn_t * -make_conn(mod_ctl_t *ctl, rb_fde_t * mod_fd, rb_fde_t * plain_fd) +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; @@ -288,7 +302,29 @@ make_conn(mod_ctl_t *ctl, rb_fde_t * mod_fd, rb_fde_t * plain_fd) } static void -conn_mod_write_sendq(rb_fde_t * fd, void *data) +check_handshake_flood(void *unused) +{ + conn_t *conn; + rb_dlink_node *ptr, *next; + unsigned int count; + int i; + HASH_WALK_SAFE(i, CONN_HASH_SIZE, ptr, next, connid_hash_table) + { + conn = ptr->data; + if(!IsSSL(conn)) + continue; + + count = rb_ssl_handshake_count(conn->mod_fd); + /* nothing needs to do this more than twice in ten seconds i don't think */ + if(count > 2) + close_conn(conn, WAIT_PLAIN, "Handshake flooding"); + else + rb_ssl_clear_handshake_count(conn->mod_fd); + } +HASH_WALK_END} + +static void +conn_mod_write_sendq(rb_fde_t *fd, void *data) { conn_t *conn = data; const char *err; @@ -304,7 +340,7 @@ conn_mod_write_sendq(rb_fde_t * fd, void *data) return; } - while ((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0) + while((retlen = rb_rawbuf_flush(conn->modbuf_out, fd)) > 0) conn->mod_out += retlen; if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) @@ -374,7 +410,7 @@ 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; + z_stream *outstream = &((zlib_stream_t *) conn->stream)->outstream; outstream->next_in = buf; outstream->avail_in = len; outstream->next_out = (Bytef *) outbuf; @@ -395,7 +431,7 @@ common_zlib_deflate(conn_t * conn, void *buf, size_t len) } if(outstream->avail_in != 0) { - /* avail_in isn't empty...*/ + /* avail_in isn't empty... */ close_conn(conn, WAIT_PLAIN, "error compressing data, avail_in != 0"); return; } @@ -406,15 +442,15 @@ common_zlib_deflate(conn_t * conn, void *buf, size_t len) 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); + int ret, have = 0; + ((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) + while(((zlib_stream_t *) conn->stream)->instream.avail_in) { - ret = inflate(&((zlib_stream_t *)conn->stream)->instream, Z_NO_FLUSH); + ret = inflate(&((zlib_stream_t *) conn->stream)->instream, Z_NO_FLUSH); if(ret != Z_OK) { if(!strncmp("ERROR ", buf, 6)) @@ -425,14 +461,14 @@ common_zlib_inflate(conn_t * conn, void *buf, size_t len) close_conn(conn, WAIT_PLAIN, "Inflate failed: %s", zError(ret)); return; } - have = sizeof(outbuf) - ((zlib_stream_t *)conn->stream)->instream.avail_out; + have = sizeof(outbuf) - ((zlib_stream_t *) conn->stream)->instream.avail_out; - if(((zlib_stream_t *)conn->stream)->instream.avail_in) + 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); + ((zlib_stream_t *) conn->stream)->instream.next_out = (Bytef *) outbuf; + ((zlib_stream_t *) conn->stream)->instream.avail_out = sizeof(outbuf); } } if(have == 0) @@ -460,7 +496,7 @@ plain_check_cork(conn_t * conn) static void -conn_plain_read_cb(rb_fde_t * fd, void *data) +conn_plain_read_cb(rb_fde_t *fd, void *data) { conn_t *conn = data; int length = 0; @@ -473,7 +509,7 @@ conn_plain_read_cb(rb_fde_t * fd, void *data) if(plain_check_cork(conn)) return; - while (1) + while(1) { if(IsDead(conn)) return; @@ -508,10 +544,38 @@ conn_plain_read_cb(rb_fde_t * fd, void *data) } static void -conn_mod_read_cb(rb_fde_t * fd, void *data) +conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data) { conn_t *conn = data; - const char *err = remote_closed; + int length = 0; + + if(conn == NULL) + return; + + while(1) + { + length = rb_read(conn->plain_fd, inbuf, sizeof(inbuf)); + + if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) + { + rb_close(conn->plain_fd); + rb_dlinkAdd(conn, &conn->node, &dead_list); + return; + } + + if(length < 0) + { + rb_setselect(conn->plain_fd, RB_SELECT_READ, conn_plain_read_shutdown_cb, conn); + return; + } + } +} + +static void +conn_mod_read_cb(rb_fde_t *fd, void *data) +{ + conn_t *conn = data; + const char *err; int length; if(conn == NULL) return; @@ -526,7 +590,7 @@ conn_mod_read_cb(rb_fde_t * fd, void *data) return; } - while (1) + while(1) { if(IsDead(conn)) return; @@ -535,7 +599,8 @@ conn_mod_read_cb(rb_fde_t * fd, void *data) if(length == 0 || (length < 0 && !rb_ignore_errno(errno))) { - if(length == 0) { + if(length == 0) + { close_conn(conn, WAIT_PLAIN, "%s", remote_closed); return; } @@ -559,7 +624,7 @@ conn_mod_read_cb(rb_fde_t * fd, void *data) } conn_plain_write_sendq(conn->plain_fd, conn); return; - } + } conn->mod_in += length; #ifdef HAVE_LIBZ if(IsZip(conn)) @@ -571,7 +636,7 @@ conn_mod_read_cb(rb_fde_t * fd, void *data) } static void -conn_plain_write_sendq(rb_fde_t * fd, void *data) +conn_plain_write_sendq(rb_fde_t *fd, void *data) { conn_t *conn = data; int retlen; @@ -579,7 +644,7 @@ conn_plain_write_sendq(rb_fde_t * fd, void *data) if(IsDead(conn)) return; - while ((retlen = rb_rawbuf_flush(conn->plainbuf_out, fd)) > 0) + while((retlen = rb_rawbuf_flush(conn->plainbuf_out, fd)) > 0) { conn->plain_out += retlen; } @@ -588,7 +653,7 @@ conn_plain_write_sendq(rb_fde_t * fd, void *data) 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); @@ -611,39 +676,61 @@ maxconn(void) } static void -ssl_process_accept_cb(rb_fde_t * F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) +ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) { conn_t *conn = data; + char buf[5 + RB_SSL_CERTFP_LEN]; + if(status == RB_OK) { + if(rb_get_ssl_certfp(F, &buf[5])) + { + buf[0] = 'F'; + int32_to_buf(&buf[1], conn->id); + mod_cmd_write_queue(conn->ctl, buf, sizeof buf); + } conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); return; } + /* ircd doesn't care about the reason for this */ close_conn(conn, NO_WAIT, 0); return; } static void -ssl_process_connect_cb(rb_fde_t * F, int status, void *data) +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; + else if(status == RB_ERR_TIMEOUT) + close_conn(conn, WAIT_PLAIN, "SSL handshake timed out"); + else if(status == RB_ERROR_SSL) + close_conn(conn, WAIT_PLAIN, "%s", rb_get_ssl_strerror(conn->mod_fd)); + else + close_conn(conn, WAIT_PLAIN, "SSL handshake failed"); } +static void +cleanup_bad_message(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + int i; + + /* XXX should log this somehow */ + for (i = 0; i < ctlb->nfds; i++) + rb_close(ctlb->F[i]); +} + static void ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { conn_t *conn; - rb_int32_t id; + int32_t id; conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); @@ -655,7 +742,7 @@ ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) 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) @@ -668,7 +755,7 @@ static void ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { conn_t *conn; - rb_int32_t id; + int32_t id; conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); id = buf_to_int32(&ctlb->buf[1]); @@ -693,13 +780,13 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) char outstat[512]; conn_t *conn; const char *odata; - rb_int32_t id; + int32_t id; id = buf_to_int32(&ctlb->buf[1]); if(id < 0) return; - + odata = &ctlb->buf[5]; conn = conn_find_by_id(id); @@ -715,27 +802,29 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) mod_cmd_write_queue(ctl, outstat, strlen(outstat) + 1); /* +1 is so we send the \0 as well */ } -#ifdef HAVE_LIBZ static void -zlib_send_zip_ready(mod_ctl_t *ctl, conn_t *conn) +change_connid(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) { - char buf[5]; - - buf[0] = 'R'; - int32_to_buf(&buf[1], conn->id); - mod_cmd_write_queue(conn->ctl, buf, sizeof(buf)); + int32_t id = buf_to_int32(&ctlb->buf[1]); + int32_t newid = buf_to_int32(&ctlb->buf[5]); + conn_t *conn = conn_find_by_id(id); + if(conn->id >= 0) + rb_dlinkDelete(&conn->node, connid_hash(conn->id)); + SetZipSSL(conn); + conn->id = newid; } +#ifdef HAVE_LIBZ static void zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { - rb_uint8_t level; + uint8_t level; size_t recvqlen; - size_t hdr = (sizeof(rb_uint8_t) * 2) + sizeof(rb_int32_t); + size_t hdr = (sizeof(uint8_t) * 2) + sizeof(int32_t); void *recvq_start; z_stream *instream, *outstream; conn_t *conn; - rb_int32_t id; + int32_t id; conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) @@ -747,22 +836,22 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) id = buf_to_int32(&ctlb->buf[1]); conn_add_id_hash(conn, id); - level = (rb_uint8_t) ctlb->buf[5]; + level = (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 = &((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); + inflateInit(&((zlib_stream_t *) conn->stream)->instream); outstream->total_in = 0; outstream->total_out = 0; @@ -773,10 +862,10 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) if(level > 9) level = Z_DEFAULT_COMPRESSION; - deflateInit(&((zlib_stream_t *)conn->stream)->outstream, level); + 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; @@ -789,8 +878,8 @@ 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]; + + seed_type = (prng_seed_t) ctl_buf->buf[1]; path = &ctl_buf->buf[2]; rb_init_prng(path, seed_type); } @@ -816,41 +905,41 @@ ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) 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) +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; + 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)); + } + mod_cmd_write_queue(ctl, nossl_cmd, strlen(nossl_cmd)); } static void -send_i_am_useless(mod_ctl_t *ctl) +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) +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; + int32_t id; if(ctlb != NULL) { conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); @@ -859,7 +948,7 @@ send_nozlib_support(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) 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)); } @@ -877,6 +966,12 @@ mod_process_cmd_recv(mod_ctl_t * ctl) { case 'A': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + if(!ssl_ok) { send_nossl_support(ctl, ctl_buf); @@ -887,6 +982,12 @@ mod_process_cmd_recv(mod_ctl_t * ctl) } case 'C': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + if(!ssl_ok) { send_nossl_support(ctl, ctl_buf); @@ -907,26 +1008,38 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } case 'I': - init_prng(ctl, ctl_buf); - break; + init_prng(ctl, ctl_buf); + break; case 'S': { process_stats(ctl, ctl_buf); break; } + case 'Y': + { + change_connid(ctl, ctl_buf); + break; + } + #ifdef HAVE_LIBZ case 'Z': { + if (ctl_buf->nfds != 2 || ctl_buf->buflen < 6) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + /* just zlib only */ zlib_process(ctl, ctl_buf); break; } #else - case 'Y': + case 'Z': send_nozlib_support(ctl, ctl_buf); break; - + #endif default: break; @@ -942,11 +1055,12 @@ mod_process_cmd_recv(mod_ctl_t * ctl) static void -mod_read_ctl(rb_fde_t * F, void *data) +mod_read_ctl(rb_fde_t *F, void *data) { mod_ctl_buf_t *ctl_buf; mod_ctl_t *ctl = data; int retlen; + int i; do { @@ -964,9 +1078,12 @@ mod_read_ctl(rb_fde_t * F, void *data) { ctl_buf->buflen = retlen; rb_dlinkAddTail(ctl_buf, &ctl_buf->node, &ctl->readq); + for (i = 0; i < MAXPASSFD && ctl_buf->F[i] != NULL; i++) + ; + ctl_buf->nfds = i; } } - while (retlen > 0); + while(retlen > 0); if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno))) exit(0); @@ -976,7 +1093,7 @@ mod_read_ctl(rb_fde_t * F, void *data) } static void -mod_write_ctl(rb_fde_t * F, void *data) +mod_write_ctl(rb_fde_t *F, void *data) { mod_ctl_t *ctl = data; mod_ctl_buf_t *ctl_buf; @@ -987,29 +1104,30 @@ mod_write_ctl(rb_fde_t * F, void *data) { ctl_buf = ptr->data; retlen = rb_send_fd_buf(ctl->F, ctl_buf->F, ctl_buf->nfds, ctl_buf->buf, - ctl_buf->buflen); + ctl_buf->buflen, ppid); if(retlen > 0) { rb_dlinkDelete(ptr, &ctl->writeq); - for (x = 0; x < ctl_buf->nfds; x++) + 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); + exit(0); + } + if(rb_dlink_list_length(&ctl->writeq) > 0) + rb_setselect(ctl->F, RB_SELECT_WRITE, mod_write_ctl, ctl); } static void -read_pipe_ctl(rb_fde_t * F, void *data) +read_pipe_ctl(rb_fde_t *F, void *data) { int retlen; - while ((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0) + 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.. */ } @@ -1022,31 +1140,36 @@ read_pipe_ctl(rb_fde_t * F, void *data) int main(int argc, char **argv) { - const char *s_ctlfd, *s_pipe; + const char *s_ctlfd, *s_pipe, *s_pid; int ctlfd, pipefd, x, maxfd; maxfd = maxconn(); + s_ctlfd = getenv("CTL_FD"); s_pipe = getenv("CTL_PIPE"); + s_pid = getenv("CTL_PPID"); - if(s_ctlfd == NULL || s_pipe == NULL) + if(s_ctlfd == NULL || s_pipe == NULL || s_pid == 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 25221 2008-04-09 22:12:16Z jilles $\n"); + 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$\n"); fprintf(stderr, "Have a nice life\n"); exit(1); } ctlfd = atoi(s_ctlfd); pipefd = atoi(s_pipe); - - for (x = 0; x < maxfd; x++) + ppid = atoi(s_pid); + x = 0; +#ifndef _WIN32 + 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) @@ -1062,14 +1185,14 @@ main(int argc, char **argv) setup_signals(); rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096); rb_init_rawbuffers(1024); - ssl_ok = rb_supports_ssl(); - + 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); + rb_event_add("check_handshake_flood", check_handshake_flood, NULL, 10); read_pipe_ctl(mod_ctl->F_pipe, NULL); mod_read_ctl(mod_ctl->F, mod_ctl); if(!zlib_ok && !ssl_ok) @@ -1077,7 +1200,7 @@ main(int argc, char **argv) /* this is really useless... */ send_i_am_useless(mod_ctl); /* sleep until the ircd kills us */ - rb_sleep(2<<30, 0); + rb_sleep(2 << 30, 0); exit(1); } @@ -1090,16 +1213,18 @@ main(int argc, char **argv) } - +#ifndef _WIN32 static void dummy_handler(int sig) { return; } +#endif static void setup_signals() { +#ifndef _WIN32 struct sigaction act; act.sa_flags = 0; @@ -1122,5 +1247,5 @@ setup_signals() act.sa_handler = dummy_handler; sigaction(SIGALRM, &act, 0); +#endif } -