X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/a7675ed2554a35dd8632fffa5578972ed2eb71d4..b068a4b51855e82f547fd7d52386e3617e016827:/ssld/ssld.c diff --git a/ssld/ssld.c b/ssld/ssld.c index def8ce57..db33486b 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -17,8 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA - * - * $Id$ */ @@ -36,46 +34,25 @@ static void setup_signals(void); static pid_t ppid; -static inline int32_t -buf_to_int32(char *buf) +static inline uint32_t +buf_to_uint32(uint8_t *buf) { - int32_t x; + uint32_t x; memcpy(&x, buf, sizeof(x)); return x; } static inline void -int32_to_buf(char *buf, int32_t x) +uint32_to_buf(uint8_t *buf, uint32_t x) { memcpy(buf, &x, sizeof(x)); return; } -static inline uint16_t -buf_to_uint16(char *buf) -{ - uint16_t x; - memcpy(&x, buf, sizeof(x)); - return x; -} - -static inline void -uint16_to_buf(char *buf, uint16_t x) -{ - 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 { rb_dlink_node node; - char *buf; + uint8_t *buf; size_t buflen; rb_fde_t *F[MAXPASSFD]; int nfds; @@ -109,14 +86,14 @@ typedef struct _conn rawbuf_head_t *modbuf_out; rawbuf_head_t *plainbuf_out; - int32_t id; + uint32_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; + uint64_t mod_out; + uint64_t mod_in; + uint64_t plain_in; + uint64_t plain_out; uint8_t flags; void *stream; } conn_t; @@ -143,15 +120,10 @@ 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) #define ClearCork(x) ((x)->flags &= ~FLAG_CORK) -#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 @@ -174,11 +146,12 @@ 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; +static bool ssld_ssl_ok; +static int certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1; #ifdef HAVE_LIBZ -static int zlib_ok = 1; +static bool zlib_ok = true; #else -static int zlib_ok = 0; +static bool zlib_ok = false; #endif @@ -197,7 +170,7 @@ ssld_free(void *unused, void *ptr) #endif static conn_t * -conn_find_by_id(int32_t id) +conn_find_by_id(uint32_t id) { rb_dlink_node *ptr; conn_t *conn; @@ -212,7 +185,7 @@ conn_find_by_id(int32_t id) } static void -conn_add_id_hash(conn_t * conn, int32_t id) +conn_add_id_hash(conn_t * conn, uint32_t id) { conn->id = id; rb_dlinkAdd(conn, &conn->node, connid_hash(id)); @@ -229,6 +202,7 @@ free_conn(conn_t * conn) zlib_stream_t *stream = conn->stream; inflateEnd(&stream->instream); deflateEnd(&stream->outstream); + rb_free(stream); } #endif rb_free(conn); @@ -253,7 +227,7 @@ 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]; + uint8_t buf[256]; int len; if(IsDead(conn)) return; @@ -263,7 +237,7 @@ close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) rb_close(conn->mod_fd); SetDead(conn); - if(conn->id >= 0 && !IsZipSSL(conn)) + if(!IsZipSSL(conn)) rb_dlinkDelete(&conn->node, connid_hash(conn->id)); if(!wait_plain || fmt == NULL) @@ -275,12 +249,12 @@ close_conn(conn_t * conn, int wait_plain, const char *fmt, ...) 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); + vsnprintf(reason, sizeof(reason), fmt, ap); va_end(ap); buf[0] = 'D'; - int32_to_buf(&buf[1], conn->id); - strcpy(&buf[5], reason); + uint32_to_buf(&buf[1], conn->id); + rb_strlcpy((char *) &buf[5], reason, sizeof(buf) - 5); len = (strlen(reason) + 1) + 5; mod_cmd_write_queue(conn->ctl, buf, len); } @@ -409,6 +383,7 @@ mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len) static void common_zlib_deflate(conn_t * conn, void *buf, size_t len) { + char outbuf[READBUF_SIZE]; int ret, have; z_stream *outstream = &((zlib_stream_t *) conn->stream)->outstream; outstream->next_in = buf; @@ -442,6 +417,7 @@ common_zlib_deflate(conn_t * conn, void *buf, size_t len) static void common_zlib_inflate(conn_t * conn, void *buf, size_t len) { + char outbuf[READBUF_SIZE]; int ret, have = 0; ((zlib_stream_t *) conn->stream)->instream.next_in = buf; ((zlib_stream_t *) conn->stream)->instream.avail_in = len; @@ -478,26 +454,27 @@ common_zlib_inflate(conn_t * conn, void *buf, size_t len) } #endif -static int +static bool 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 + /* 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 true; } - return 0; + return false; } static void conn_plain_read_cb(rb_fde_t *fd, void *data) { + char inbuf[READBUF_SIZE]; conn_t *conn = data; int length = 0; if(conn == NULL) @@ -546,6 +523,7 @@ conn_plain_read_cb(rb_fde_t *fd, void *data) static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data) { + char inbuf[READBUF_SIZE]; conn_t *conn = data; int length = 0; @@ -574,8 +552,8 @@ conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data) static void conn_mod_read_cb(rb_fde_t *fd, void *data) { + char inbuf[READBUF_SIZE]; conn_t *conn = data; - const char *err = remote_closed; int length; if(conn == NULL) return; @@ -605,6 +583,7 @@ conn_mod_read_cb(rb_fde_t *fd, void *data) return; } + const char *err; if(IsSSL(conn) && length == RB_RW_SSL_ERROR) err = rb_get_ssl_strerror(conn->mod_fd); else @@ -675,20 +654,67 @@ maxconn(void) return MAXCONNECTIONS; } +static void +ssl_send_cipher(conn_t *conn) +{ + size_t len; + uint8_t buf[512]; + char cstring[256]; + const char *p; + if(!IsSSL(conn)) + return; + + p = rb_ssl_get_cipher(conn->mod_fd); + + if(p == NULL) + return; + + rb_strlcpy(cstring, p, sizeof(cstring)); + + buf[0] = 'C'; + uint32_to_buf(&buf[1], conn->id); + strcpy((char *) &buf[5], cstring); + len = (strlen(cstring) + 1) + 5; + mod_cmd_write_queue(conn->ctl, buf, len); +} + +static void +ssl_send_certfp(conn_t *conn) +{ + uint8_t buf[13 + RB_SSL_CERTFP_LEN]; + + int len = rb_get_ssl_certfp(conn->mod_fd, &buf[13], certfp_method); + if (!len) + return; + + lrb_assert(len <= RB_SSL_CERTFP_LEN); + buf[0] = 'F'; + uint32_to_buf(&buf[1], conn->id); + uint32_to_buf(&buf[5], certfp_method); + uint32_to_buf(&buf[9], len); + mod_cmd_write_queue(conn->ctl, buf, 13 + len); +} + +static void +ssl_send_open(conn_t *conn) +{ + uint8_t buf[5]; + + buf[0] = 'O'; + uint32_to_buf(&buf[1], conn->id); + mod_cmd_write_queue(conn->ctl, buf, 5); +} + 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; - 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); - } + ssl_send_cipher(conn); + ssl_send_certfp(conn); + ssl_send_open(conn); conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); return; @@ -702,16 +728,12 @@ static void ssl_process_connect_cb(rb_fde_t *F, int status, 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); - } + ssl_send_cipher(conn); + ssl_send_certfp(conn); + ssl_send_open(conn); conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); } @@ -738,44 +760,44 @@ static void ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { conn_t *conn; - int32_t id; + uint32_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); + id = buf_to_uint32(&ctlb->buf[1]); + 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) + + if(rb_get_type(conn->plain_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_change_certfp_method(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + certfp_method = buf_to_uint32(&ctlb->buf[1]); +} + static void ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { conn_t *conn; - int32_t id; + uint32_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); + id = buf_to_uint32(&ctlb->buf[1]); + 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) + if(rb_get_type(conn->plain_fd) == RB_FD_UNKNOWN) rb_set_type(conn->plain_fd, RB_FD_SOCKET); @@ -787,13 +809,10 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { char outstat[512]; conn_t *conn; - const char *odata; - int32_t id; - - id = buf_to_int32(&ctlb->buf[1]); + uint8_t *odata; + uint32_t id; - if(id < 0) - return; + id = buf_to_uint32(&ctlb->buf[1]); odata = &ctlb->buf[5]; conn = conn_find_by_id(id); @@ -801,8 +820,11 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) 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); + snprintf(outstat, sizeof(outstat), "S %s %llu %llu %llu %llu", odata, + (unsigned long long)conn->plain_out, + (unsigned long long)conn->mod_in, + (unsigned long long)conn->plain_in, + (unsigned long long)conn->mod_out); conn->plain_out = 0; conn->plain_in = 0; conn->mod_in = 0; @@ -810,29 +832,17 @@ 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 */ } -static void -change_connid(mod_ctl_t *ctl, mod_ctl_buf_t *ctlb) -{ - 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) { uint8_t level; size_t recvqlen; - size_t hdr = (sizeof(uint8_t) * 2) + sizeof(int32_t); + size_t hdr = (sizeof(uint8_t) * 2) + sizeof(uint32_t); void *recvq_start; z_stream *instream, *outstream; conn_t *conn; - int32_t id; + uint32_t id; conn = make_conn(ctl, ctlb->F[0], ctlb->F[1]); if(rb_get_type(conn->mod_fd) == RB_FD_UNKNOWN) @@ -841,7 +851,7 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) 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]); + id = buf_to_uint32(&ctlb->buf[1]); conn_add_id_hash(conn, id); level = (uint8_t)ctlb->buf[5]; @@ -868,7 +878,7 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) outstream->data_type = Z_ASCII; if(level > 9) - level = Z_DEFAULT_COMPRESSION; + level = (uint8_t) Z_DEFAULT_COMPRESSION; deflateInit(&((zlib_stream_t *) conn->stream)->outstream, level); if(recvqlen > 0) @@ -881,34 +891,28 @@ zlib_process(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) } #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; + char *cert, *key, *dhparam, *cipher_list; - buf = &ctl_buf->buf[2]; + buf = (char *) &ctl_buf->buf[2]; cert = buf; buf += strlen(cert) + 1; key = buf; buf += strlen(key) + 1; dhparam = buf; + buf += strlen(dhparam) + 1; + cipher_list = buf; + if(strlen(key) == 0) + key = cert; if(strlen(dhparam) == 0) dhparam = NULL; + if(strlen(cipher_list) == 0) + cipher_list = NULL; - if(!rb_setup_ssl_server(cert, key, dhparam)) + if(!rb_setup_ssl_server(cert, key, dhparam, cipher_list)) { const char *invalid = "I"; mod_cmd_write_queue(ctl, invalid, strlen(invalid)); @@ -921,15 +925,13 @@ send_nossl_support(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { static const char *nossl_cmd = "N"; conn_t *conn; - int32_t id; + uint32_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); + id = buf_to_uint32(&ctlb->buf[1]); + 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)); @@ -942,19 +944,25 @@ send_i_am_useless(mod_ctl_t * ctl) mod_cmd_write_queue(ctl, useless, strlen(useless)); } +static void +send_version(mod_ctl_t * ctl) +{ + char version[256] = { 'V', 0 }; + strncpy(&version[1], rb_lib_version(), sizeof(version) - 2); + mod_cmd_write_queue(ctl, version, strlen(version)); +} + static void send_nozlib_support(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { static const char *nozlib_cmd = "z"; conn_t *conn; - int32_t id; + uint32_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); + id = buf_to_uint32(&ctlb->buf[1]); + 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)); @@ -980,7 +988,7 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } - if(!ssl_ok) + if(!ssld_ssl_ok) { send_nossl_support(ctl, ctl_buf); break; @@ -990,13 +998,13 @@ mod_process_cmd_recv(mod_ctl_t * ctl) } case 'C': { - if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + if (ctl_buf->buflen != 5) { cleanup_bad_message(ctl, ctl_buf); break; } - if(!ssl_ok) + if(!ssld_ssl_ok) { send_nossl_support(ctl, ctl_buf); break; @@ -1004,10 +1012,19 @@ mod_process_cmd_recv(mod_ctl_t * ctl) ssl_process_connect(ctl, ctl_buf); break; } - + case 'F': + { + if (ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + ssl_change_certfp_method(ctl, ctl_buf); + break; + } case 'K': { - if(!ssl_ok) + if(!ssld_ssl_ok) { send_nossl_support(ctl, ctl_buf); break; @@ -1015,19 +1032,11 @@ mod_process_cmd_recv(mod_ctl_t * ctl) ssl_new_keys(ctl, ctl_buf); break; } - case 'I': - 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': @@ -1043,7 +1052,7 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } #else - + case 'Z': send_nozlib_support(ctl, ctl_buf); break; @@ -1134,6 +1143,7 @@ mod_write_ctl(rb_fde_t *F, void *data) static void read_pipe_ctl(rb_fde_t *F, void *data) { + char inbuf[READBUF_SIZE]; int retlen; while((retlen = rb_read(F, inbuf, sizeof(inbuf))) > 0) { @@ -1149,7 +1159,7 @@ int main(int argc, char **argv) { const char *s_ctlfd, *s_pipe, *s_pid; - int ctlfd, pipefd, x, maxfd; + int ctlfd, pipefd, maxfd; maxfd = maxconn(); s_ctlfd = getenv("CTL_FD"); @@ -1159,23 +1169,25 @@ main(int argc, char **argv) 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"); + "This is the charybdis ssld for internal ircd use.\n"); fprintf(stderr, - "You get an Id tag for this: $Id$\n"); - fprintf(stderr, "Have a nice life\n"); + "You aren't supposed to run me directly. Exiting.\n"); exit(1); } ctlfd = atoi(s_ctlfd); pipefd = atoi(s_pipe); ppid = atoi(s_pid); - x = 0; + #ifndef _WIN32 - for(x = 0; x < maxfd; x++) + int x; + + for(x = 3; x < maxfd; x++) { - if(x != ctlfd && x != pipefd && x > 2) + if(x != ctlfd && x != pipefd) close(x); } + x = open("/dev/null", O_RDWR); if(x >= 0) @@ -1190,10 +1202,12 @@ main(int argc, char **argv) close(x); } #endif + setup_signals(); rb_lib_init(NULL, NULL, NULL, 0, maxfd, 1024, 4096); rb_init_rawbuffers(1024); - ssl_ok = rb_supports_ssl(); + rb_init_prng(NULL, RB_PRNG_DEFAULT); + ssld_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"); @@ -1203,18 +1217,19 @@ main(int argc, char **argv) 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) + send_version(mod_ctl); + if(!zlib_ok && !ssld_ssl_ok) { /* this is really useless... */ send_i_am_useless(mod_ctl); /* sleep until the ircd kills us */ - rb_sleep(2 << 30, 0); + rb_sleep(1 << 30, 0); exit(1); } if(!zlib_ok) send_nozlib_support(mod_ctl, NULL); - if(!ssl_ok) + if(!ssld_ssl_ok) send_nossl_support(mod_ctl, NULL); rb_lib_loop(0); return 0;