X-Git-Url: https://jfr.im/git/solanum.git/blobdiff_plain/6657de63ac4384ffb03bbe4a98f79e24817673b3..272af6a505831a25601a07b93b0cec98846e2749:/ssld/ssld.c?ds=sidebyside diff --git a/ssld/ssld.c b/ssld/ssld.c index b28520da..226ee8fa 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) -{ - int32_t x; - memcpy(&x, buf, sizeof(x)); - return x; -} - -static inline void -int32_to_buf(char *buf, int32_t x) -{ - memcpy(buf, &x, sizeof(x)); - return; -} - -static inline uint16_t -buf_to_uint16(char *buf) +static inline uint32_t +buf_to_uint32(uint8_t *buf) { - uint16_t x; + uint32_t x; memcpy(&x, buf, sizeof(x)); return x; } static inline void -uint16_to_buf(char *buf, uint16_t x) +uint32_to_buf(uint8_t *buf, uint32_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; @@ -174,11 +151,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_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 +175,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 +190,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 +207,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 +232,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 +242,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 +254,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 +388,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 +422,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 +459,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 +528,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,6 +557,7 @@ 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; @@ -675,14 +659,57 @@ 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[9 + RB_SSL_CERTFP_LEN]; + + int len = rb_get_ssl_certfp(conn->mod_fd, &buf[9], 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], len); + mod_cmd_write_queue(conn->ctl, buf, 9 + len); +} + 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); + ssl_send_cipher(conn); + ssl_send_certfp(conn); return; } /* ircd doesn't care about the reason for this */ @@ -694,10 +721,13 @@ 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); + ssl_send_cipher(conn); + ssl_send_certfp(conn); } else if(status == RB_ERR_TIMEOUT) close_conn(conn, WAIT_PLAIN, "SSL handshake timed out"); @@ -722,44 +752,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); @@ -771,13 +801,10 @@ process_stats(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { char outstat[512]; conn_t *conn; - const char *odata; - int32_t id; + uint8_t *odata; + uint32_t id; - id = buf_to_int32(&ctlb->buf[1]); - - if(id < 0) - return; + id = buf_to_uint32(&ctlb->buf[1]); odata = &ctlb->buf[5]; conn = conn_find_by_id(id); @@ -785,8 +812,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; @@ -794,29 +824,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) @@ -825,7 +843,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]; @@ -852,7 +870,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) @@ -872,7 +890,7 @@ init_prng(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) prng_seed_t seed_type; seed_type = (prng_seed_t) ctl_buf->buf[1]; - path = &ctl_buf->buf[2]; + path = (char *) &ctl_buf->buf[2]; rb_init_prng(path, seed_type); } @@ -881,9 +899,9 @@ 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; @@ -891,8 +909,12 @@ ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) dhparam = buf; if(strlen(dhparam) == 0) dhparam = NULL; + buf += strlen(dhparam) + 1; + cipher_list = buf; + 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)); @@ -905,15 +927,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)); @@ -926,19 +946,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)); @@ -964,7 +990,7 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } - if(!ssl_ok) + if(!ssld_ssl_ok) { send_nossl_support(ctl, ctl_buf); break; @@ -980,7 +1006,7 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } - if(!ssl_ok) + if(!ssld_ssl_ok) { send_nossl_support(ctl, ctl_buf); break; @@ -988,10 +1014,19 @@ mod_process_cmd_recv(mod_ctl_t * ctl) ssl_process_connect(ctl, ctl_buf); break; } - + case 'F': + { + if (ctl_buf->nfds != 2 || 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; @@ -1007,11 +1042,6 @@ mod_process_cmd_recv(mod_ctl_t * ctl) process_stats(ctl, ctl_buf); break; } - case 'Y': - { - change_connid(ctl, ctl_buf); - break; - } #ifdef HAVE_LIBZ case 'Z': @@ -1027,7 +1057,7 @@ mod_process_cmd_recv(mod_ctl_t * ctl) break; } #else - + case 'Z': send_nozlib_support(ctl, ctl_buf); break; @@ -1118,6 +1148,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) { @@ -1143,10 +1174,9 @@ 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); } @@ -1177,7 +1207,7 @@ 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(); + 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"); @@ -1187,7 +1217,8 @@ 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); @@ -1198,7 +1229,7 @@ main(int argc, char **argv) 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;