diff --git a/doc/ircd.conf.example b/doc/ircd.conf.example index cdca5c703..94c7e3ee8 100755 --- a/doc/ircd.conf.example +++ b/doc/ircd.conf.example @@ -557,3 +557,17 @@ modules { path = "modules"; path = "modules/autoload"; }; + +/* +vhost "selfsigned.hades.arpa" { + ssl_private_key = "etc/selfssl.key"; + ssl_cert = "etc/selfssl.pem"; +}; + +vhost "oldca.hades.arpa" { + ssl_private_key = "etc/oldssl.key"; + ssl_cert = "etc/oldssl2.pem"; + ssl_dh_params = "etc/olddh.pem"; + ssl_cipher_list = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL";; +}; +*/ diff --git a/doc/reference.conf b/doc/reference.conf index 35d1096af..f2cf6628b 100755 --- a/doc/reference.conf +++ b/doc/reference.conf @@ -1360,3 +1360,17 @@ modules { /* module: the name of a module to load on startup/rehash */ #module = "some_module.so"; }; + +/* +vhost "selfsigned.hades.arpa" { + ssl_private_key = "etc/selfssl.key"; + ssl_cert = "etc/selfssl.pem"; +}; + +vhost "oldca.hades.arpa" { + ssl_private_key = "etc/oldssl.key"; + ssl_cert = "etc/oldssl2.pem"; + ssl_dh_params = "etc/olddh.pem"; + ssl_cipher_list = "kEECDH+HIGH:kEDH+HIGH:HIGH:!RC4:!aNULL"; +}; +*/ diff --git a/include/s_newconf.h b/include/s_newconf.h index dc213c5ed..04d63f058 100644 --- a/include/s_newconf.h +++ b/include/s_newconf.h @@ -53,6 +53,7 @@ extern rb_dlink_list xline_conf_list; extern rb_dlink_list resv_conf_list; extern rb_dlink_list nd_list; extern rb_dlink_list tgchange_list; +extern rb_dlink_list vhost_conf_list; extern struct _rb_patricia_tree_t *tgchange_tree; @@ -245,5 +246,16 @@ extern void add_nd_entry(const char *name); extern void free_nd_entry(struct nd_entry *); extern unsigned long get_nd_count(void); -#endif +struct vhost_conf +{ + char *hostname; + char *ssl_private_key; + char *ssl_cert; + char *ssl_dh_params; + char *ssl_cipher_list; + rb_dlink_node node; +}; +extern struct vhost_conf *make_vhost_conf(void); +extern void free_vhost_conf(struct vhost_conf *); +#endif diff --git a/include/sslproc.h b/include/sslproc.h index 981f9a4c4..ef8cb22ae 100644 --- a/include/sslproc.h +++ b/include/sslproc.h @@ -39,10 +39,10 @@ int start_ssldaemon(int count, const char *ssl_cert, const char *ssl_private_key ssl_ctl_t *start_ssld_accept(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id); ssl_ctl_t *start_ssld_connect(rb_fde_t *sslF, rb_fde_t *plainF, uint32_t id); void start_zlib_session(void *data); -void send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list, const int method); +void send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list, const int method, const char *hostname); +void send_remove_ssl_vhost(const char *hostname); void ssld_decrement_clicount(ssl_ctl_t *ctl); int get_ssld_count(void); void ssld_foreach_info(void (*func)(void *data, pid_t pid, int cli_count, enum ssld_status status), void *data); #endif - diff --git a/libratbox/include/commio-ssl.h b/libratbox/include/commio-ssl.h index 6e2bd69f0..1fc85c9c7 100644 --- a/libratbox/include/commio-ssl.h +++ b/libratbox/include/commio-ssl.h @@ -25,7 +25,7 @@ #ifndef _COMMIO_SSL_H #define _COMMIO_SSL_H -int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list); +int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list, const char *hostname); int rb_init_ssl(void); int rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept); diff --git a/libratbox/include/rb_commio.h b/libratbox/include/rb_commio.h index f0b7dbeca..da752a1e6 100644 --- a/libratbox/include/rb_commio.h +++ b/libratbox/include/rb_commio.h @@ -152,9 +152,10 @@ ssize_t rb_writev(rb_fde_t *, struct rb_iovec *vector, int count); ssize_t rb_read(rb_fde_t *, void *buf, int count); int rb_pipe(rb_fde_t **, rb_fde_t **, const char *desc); -int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list); +int rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list, const char *hostname); int rb_ssl_listen(rb_fde_t *, int backlog, int defer_accept); int rb_listen(rb_fde_t *, int backlog, int defer_accept); +int rb_remove_ssl_vserver(const char *hostname); const char *rb_inet_ntop(int af, const void *src, char *dst, unsigned int size); int rb_inet_pton(int af, const char *src, void *dst); diff --git a/libratbox/src/export-syms.txt b/libratbox/src/export-syms.txt index e828ea4a2..e34a33a7f 100644 --- a/libratbox/src/export-syms.txt +++ b/libratbox/src/export-syms.txt @@ -48,6 +48,8 @@ rb_setselect rb_settimeout rb_setup_fd rb_setup_ssl_server +rb_setup_ssl_server_hostname +rb_remove_ssl_vserver rb_socket rb_socketpair rb_ssl_listen diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index dd77e08ef..1cca2ef43 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -496,9 +496,16 @@ rb_init_ssl(void) return 1; } +int +rb_remove_ssl_vserver(const char *hostname) +{ + errno = ENOSYS; + return -1; +} + int rb_setup_ssl_server(const char *const certfile, const char *keyfile, - const char *const dhfile, const char *cipherlist) + const char *const dhfile, const char *cipherlist, const char *hostname) { if(certfile == NULL) { diff --git a/libratbox/src/mbedtls.c b/libratbox/src/mbedtls.c index 7879ad45f..14ae5c684 100644 --- a/libratbox/src/mbedtls.c +++ b/libratbox/src/mbedtls.c @@ -455,9 +455,16 @@ rb_init_ssl(void) return 1; } +int +rb_remove_ssl_vserver(const char *hostname) +{ + errno = ENOSYS; + return -1; +} + int rb_setup_ssl_server(const char *const certfile, const char *keyfile, - const char *const dhfile, const char *const cipherlist) + const char *const dhfile, const char *const cipherlist, const char *hostname) { if(certfile == NULL) { diff --git a/libratbox/src/nossl.c b/libratbox/src/nossl.c index 6164bbe75..c3fb129fa 100644 --- a/libratbox/src/nossl.c +++ b/libratbox/src/nossl.c @@ -34,7 +34,7 @@ #include int -rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list) +rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile, const char *cipher_list, const char *hostname) { errno = ENOSYS; return 0; @@ -48,6 +48,13 @@ rb_init_ssl(void) } +int +rb_remove_ssl_vserver(const char *hostname) +{ + errno = ENOSYS; + return -1; +} + int rb_ssl_listen(rb_fde_t *F, int backlog, int defer_accept) { diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index 4954e4838..f7ee58023 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -41,9 +41,31 @@ typedef enum #define SSL_P(x) ((SSL *)((x)->ssl)) - +typedef struct ssl_vhost_s +{ + char *hostname; + SSL_CTX *ctx; + rb_dlink_node node; +} ssl_vhost; static SSL_CTX *ssl_ctx = NULL; +rb_dlink_list ssl_vhosts; + +rb_dlink_node * +find_ssl_vhost(const char *hostname) +{ + ssl_vhost *vhost_p; + rb_dlink_node *ptr; + + RB_DLINK_FOREACH(ptr, ssl_vhosts.head) + { + vhost_p = ptr->data; + + if(!strcmp(hostname,vhost_p->hostname)) + return ptr; + } + return NULL; +} struct ssl_connect { @@ -337,9 +359,65 @@ rb_init_ssl(void) return 1; } +static int rb_ssl_servername_cb(SSL *s, int *ad, void *arg) +{ + ssl_vhost *vhost_p; + rb_dlink_node *ptr; + rb_dlink_node *next_ptr; + + const char * servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + + rb_lib_log("Hostname in TLS extension?"); + if (servername) + { + rb_lib_log("Hostname in TLS extension %s", servername); + + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, ssl_vhosts.head) + { + vhost_p = ptr->data; + + if (strcmp(servername, vhost_p->hostname) != 0) + continue; + + if (vhost_p->ctx) + { + rb_lib_log("Switching server context %s", servername); + SSL_set_SSL_CTX(s,vhost_p->ctx); + } + } + } + return SSL_TLSEXT_ERR_OK; +} + +void +free_ssl_vhost(ssl_vhost *vhost_p) +{ + if(vhost_p == NULL) + return; + + rb_free(vhost_p->hostname); + + SSL_CTX_free(vhost_p->ctx); + rb_free(vhost_p); +} + +int +rb_remove_ssl_vserver(const char *hostname) +{ + rb_dlink_node *ptr = find_ssl_vhost(hostname); + if(ptr != NULL && ptr) { + rb_dlinkDelete(ptr, &ssl_vhosts); + free_ssl_vhost(ptr->data); + return 1; + } + + return 0; +} + int rb_setup_ssl_server(const char *const certfile, const char *keyfile, - const char *const dhfile, const char *cipherlist) + const char *const dhfile, const char *cipherlist, + const char *hostname) { if(certfile == NULL) { @@ -419,6 +497,7 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, SSL_CTX_free(ssl_ctx_new); return 0; } + SSL_CTX_set_tlsext_servername_callback(ssl_ctx_new, rb_ssl_servername_cb); SSL_CTX_set_session_cache_mode(ssl_ctx_new, SSL_SESS_CACHE_OFF); SSL_CTX_set_verify(ssl_ctx_new, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, verify_accept_all_cb); @@ -472,14 +551,33 @@ rb_setup_ssl_server(const char *const certfile, const char *keyfile, # endif #endif + rb_lib_log("%s: TLS configuration successful", __func__); + if(hostname == NULL) { + if(ssl_ctx) + SSL_CTX_free(ssl_ctx); - if(ssl_ctx) - SSL_CTX_free(ssl_ctx); + ssl_ctx = ssl_ctx_new; + } else { + ssl_vhost *vhost_p = NULL; - ssl_ctx = ssl_ctx_new; + rb_lib_log("rb_setup_ssl_server: SETUP [%s]", hostname); + rb_dlink_node *ptr = find_ssl_vhost(hostname); + if(ptr != NULL && ptr) + vhost_p = ptr->data; + if(vhost_p == NULL) { + vhost_p = rb_malloc(sizeof(ssl_vhost)); + vhost_p->hostname = rb_strdup(hostname); + + rb_dlinkAdd(vhost_p, &vhost_p->node, &ssl_vhosts); + } + + if(vhost_p->ctx) + SSL_CTX_free(vhost_p->ctx); + + vhost_p->ctx = ssl_ctx_new; + } - rb_lib_log("%s: TLS configuration successful", __func__); return 1; } diff --git a/src/ircd.c b/src/ircd.c index cda382094..2bed571c0 100644 --- a/src/ircd.c +++ b/src/ircd.c @@ -505,7 +505,11 @@ int main(int argc, char *argv[]) { int fd; - +#ifdef HAVE_LIBCRYPTO + struct vhost_conf *vhost_p; + rb_dlink_node *ptr; + rb_dlink_node *next_ptr; +#endif /* Check to see if the user is running us as root, which is a nono */ if(geteuid() == 0) { @@ -676,13 +680,25 @@ main(int argc, char *argv[]) if(ServerInfo.ssl_cert != NULL && ServerInfo.ssl_private_key != NULL) { /* just do the rb_setup_ssl_server to validate the config */ - if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list)) + if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list, NULL)) { ilog(L_MAIN, "WARNING: Unable to setup SSL."); ircd_ssl_ok = 0; } else ircd_ssl_ok = 1; +#ifdef HAVE_LIBCRYPTO + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, vhost_conf_list.head) + { + vhost_p = ptr->data; + if(rb_setup_ssl_server(vhost_p->ssl_cert, vhost_p->ssl_private_key, + vhost_p->ssl_dh_params ? vhost_p->ssl_dh_params : ServerInfo.ssl_dh_params, + vhost_p->ssl_cipher_list ? vhost_p->ssl_cipher_list : ServerInfo.ssl_cipher_list, vhost_p->hostname)) + { + ircd_ssl_ok = 1; + } + } +#endif } if (testing_conf) diff --git a/src/newconf.c b/src/newconf.c index b5680a623..43ac9e541 100644 --- a/src/newconf.c +++ b/src/newconf.c @@ -46,6 +46,7 @@ static struct Class *yy_class = NULL; static struct remote_conf *yy_shared = NULL; static struct server_conf *yy_server = NULL; +static struct vhost_conf *yy_vhost = NULL; static rb_dlink_list yy_aconf_list; static rb_dlink_list yy_oper_list; @@ -1439,6 +1440,71 @@ conf_set_connect_class(void *data) yy_server->class_name = rb_strdup(data); } +static int +conf_begin_vhost(struct TopConf *tc) +{ + if(yy_vhost) + free_vhost_conf(yy_vhost); + + yy_vhost = make_vhost_conf(); + + if(conf_cur_block_name != NULL) { + yy_vhost->hostname = rb_strdup(conf_cur_block_name); + } + + return 0; +} + +static int +conf_end_vhost(struct TopConf *tc) +{ + if(EmptyString(yy_vhost->hostname)) + { + conf_report_error("Ignoring vhost block -- missing hostname."); + return 0; + } + + if(EmptyString(yy_vhost->ssl_cert) || EmptyString(yy_vhost->ssl_private_key)) + { + conf_report_error("Ignoring vhost block for %s -- no ssl_cert or ssl_private_key file provided.", + yy_vhost->hostname); + return 0; + } + + rb_dlinkAdd(yy_vhost, &yy_vhost->node, &vhost_conf_list); + yy_vhost = NULL; + return 0; +} + +static void +conf_set_vhost_ssl_private_key(void *data) +{ + if (yy_vhost->ssl_private_key) + rb_free(yy_vhost->ssl_private_key); + yy_vhost->ssl_private_key = rb_strdup((char *) data); +} +static void +conf_set_vhost_ssl_cert(void *data) +{ + if (yy_vhost->ssl_cert) + rb_free(yy_vhost->ssl_cert); + yy_vhost->ssl_cert = rb_strdup((char *) data); +} +static void +conf_set_vhost_ssl_dh_params(void *data) +{ + if (yy_vhost->ssl_dh_params) + rb_free(yy_vhost->ssl_dh_params); + yy_vhost->ssl_dh_params = rb_strdup((char *) data); +} +static void +conf_set_vhost_ssl_cipher_list(void *data) +{ + if (yy_vhost->ssl_cipher_list) + rb_free(yy_vhost->ssl_cipher_list); + yy_vhost->ssl_cipher_list = rb_strdup((char *) data); +} + static void conf_set_exempt_ip(void *data) { @@ -1457,6 +1523,15 @@ conf_set_exempt_ip(void *data) add_conf_by_address(yy_tmp->host, CONF_EXEMPTDLINE, NULL, NULL, yy_tmp); } +static struct ConfEntry conf_vhost_table[] = +{ + { "ssl_private_key", CF_QSTRING, conf_set_vhost_ssl_private_key, 0, NULL }, + { "ssl_cert", CF_QSTRING, conf_set_vhost_ssl_cert, 0, NULL }, + { "ssl_dh_params", CF_QSTRING, conf_set_vhost_ssl_dh_params, 0, NULL }, + { "ssl_cipher_list", CF_QSTRING, conf_set_vhost_ssl_cipher_list, 0, NULL }, + { "\0", 0, NULL, 0, NULL } +}; + static int conf_cleanup_cluster(struct TopConf *tc) { @@ -2612,6 +2687,7 @@ newconf_init() add_conf_item("shared", "flags", CF_STRING | CF_FLIST, conf_set_shared_flags); add_top_conf("connect", conf_begin_connect, conf_end_connect, conf_connect_table); + add_top_conf("vhost", conf_begin_vhost, conf_end_vhost, conf_vhost_table); add_top_conf("exempt", NULL, NULL, NULL); add_conf_item("exempt", "ip", CF_QSTRING, conf_set_exempt_ip); diff --git a/src/s_conf.c b/src/s_conf.c index ce2c9c826..2c7d3bd42 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -860,6 +860,12 @@ read_conf(void) static void validate_conf(void) { +#ifdef HAVE_LIBCRYPTO + struct vhost_conf *vhost_p; + rb_dlink_node *ptr; + rb_dlink_node *next_ptr; +#endif + if(ConfigFileEntry.default_ident_timeout < 1) ConfigFileEntry.default_ident_timeout = IDENT_TIMEOUT_DEFAULT; @@ -875,15 +881,31 @@ validate_conf(void) if(ServerInfo.ssld_count < 1) ServerInfo.ssld_count = 1; - if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list)) + if(!rb_setup_ssl_server(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list, NULL)) { ilog(L_MAIN, "WARNING: Unable to setup SSL."); ircd_ssl_ok = 0; } else { ircd_ssl_ok = 1; - send_new_ssl_certs(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list, ConfigFileEntry.certfp_method); + send_new_ssl_certs(ServerInfo.ssl_cert, ServerInfo.ssl_private_key, ServerInfo.ssl_dh_params, ServerInfo.ssl_cipher_list, ConfigFileEntry.certfp_method, NULL); } +#ifdef HAVE_LIBCRYPTO + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, vhost_conf_list.head) + { + vhost_p = ptr->data; + if(rb_setup_ssl_server(vhost_p->ssl_cert, vhost_p->ssl_private_key, + vhost_p->ssl_dh_params, + vhost_p->ssl_cipher_list, vhost_p->hostname)) + { + ircd_ssl_ok = 1; + send_new_ssl_certs(vhost_p->ssl_cert, vhost_p->ssl_private_key, + vhost_p->ssl_dh_params ? vhost_p->ssl_dh_params : ServerInfo.ssl_dh_params, + vhost_p->ssl_cipher_list ? vhost_p->ssl_cipher_list : ServerInfo.ssl_cipher_list, ConfigFileEntry.certfp_method, vhost_p->hostname); + } + } +#endif + if(ServerInfo.ssld_count > get_ssld_count()) { int start = ServerInfo.ssld_count - get_ssld_count(); @@ -1462,6 +1484,7 @@ static void clear_out_old_conf(void) { struct Class *cltmp; + struct vhost_conf *vhost_p; rb_dlink_node *ptr; rb_dlink_node *next_ptr; @@ -1547,6 +1570,14 @@ clear_out_old_conf(void) rb_dlinkDestroy(ptr, &service_list); } + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, vhost_conf_list.head) + { + vhost_p = ptr->data; + send_remove_ssl_vhost(vhost_p->hostname); + rb_dlinkDelete(ptr, &vhost_conf_list); + free_vhost_conf(ptr->data); + } + /* remove any aliases... -- nenolod */ if (alias_dict != NULL) { diff --git a/src/s_newconf.c b/src/s_newconf.c index 9a6843f1d..af175cc9d 100644 --- a/src/s_newconf.c +++ b/src/s_newconf.c @@ -56,6 +56,7 @@ rb_dlink_list xline_conf_list; rb_dlink_list resv_conf_list; /* nicks only! */ rb_dlink_list nd_list; /* nick delay */ rb_dlink_list tgchange_list; +rb_dlink_list vhost_conf_list; rb_patricia_tree_t *tgchange_tree; @@ -805,3 +806,42 @@ find_tgchange(const char *host) return NULL; } +struct vhost_conf * +find_ssl_vhost(const char *hostname) +{ + struct vhost_conf *vhost_p; + rb_dlink_node *ptr; + + RB_DLINK_FOREACH(ptr, vhost_conf_list.head) + { + vhost_p = ptr->data; + + if(!strcmp(hostname,vhost_p->hostname)) + return vhost_p; + } + return NULL; +} + +struct vhost_conf * +make_vhost_conf(void) +{ + struct vhost_conf *vhost_p = rb_malloc(sizeof(struct vhost_conf)); + return vhost_p; +} + +void +free_vhost_conf(struct vhost_conf *vhost_p) +{ + s_assert(vhost_p != NULL); + if(vhost_p == NULL) + return; + + rb_free(vhost_p->hostname); + rb_free(vhost_p->ssl_private_key); + rb_free(vhost_p->ssl_cert); + rb_free(vhost_p->ssl_dh_params); + rb_free(vhost_p->ssl_cipher_list); + + rb_free(vhost_p); +} +// TODO: Free vhost_conf_list diff --git a/src/sslproc.c b/src/sslproc.c index 944c10992..ee39058ba 100644 --- a/src/sslproc.c +++ b/src/sslproc.c @@ -25,6 +25,7 @@ #include "stdinc.h" #include "s_conf.h" +#include "s_newconf.h" #include "logger.h" #include "listener.h" #include "sslproc.h" @@ -70,7 +71,9 @@ struct _ssl_ctl static void send_new_ssl_certs_one(ssl_ctl_t * ctl, const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, - const char *ssl_cipher_list); + const char *ssl_cipher_list, const char *hostname); +static void send_remove_ssl_vhost_one(ssl_ctl_t * ctl, const char *hostname); + static void send_init_prng(ssl_ctl_t * ctl, prng_seed_t seedtype, const char *path); static void send_certfp_method(ssl_ctl_t *ctl, int method); @@ -256,6 +259,10 @@ start_ssldaemon(int count, const char *ssl_cert, const char *ssl_private_key, co char s_pid[10]; pid_t pid; int started = 0, i; + struct vhost_conf *vhost_p; + rb_dlink_node *ptr; + rb_dlink_node *next_ptr; + if(ssld_wait) return 0; @@ -341,8 +348,16 @@ start_ssldaemon(int count, const char *ssl_cert, const char *ssl_private_key, co send_init_prng(ctl, RB_PRNG_DEFAULT, NULL); send_certfp_method(ctl, ConfigFileEntry.certfp_method); - if(ssl_cert != NULL) - send_new_ssl_certs_one(ctl, ssl_cert, ssl_private_key, ssl_dh_params, ssl_cipher_list); + if(ssl_cert != NULL) { + send_new_ssl_certs_one(ctl, ssl_cert, ssl_private_key, ssl_dh_params, ssl_cipher_list, NULL); + RB_DLINK_FOREACH_SAFE(ptr, next_ptr, vhost_conf_list.head) + { + vhost_p = ptr->data; + send_new_ssl_certs_one(ctl, vhost_p->ssl_cert, vhost_p->ssl_private_key, + vhost_p->ssl_dh_params ? vhost_p->ssl_dh_params : ssl_dh_params, + vhost_p->ssl_cipher_list ? vhost_p->ssl_cipher_list : ssl_cipher_list, vhost_p->hostname); + } + } } ssl_read_ctl(ctl->F, ctl); ssl_do_pipe(P2, ctl); @@ -671,7 +686,7 @@ ssl_cmd_write_queue(ssl_ctl_t * ctl, rb_fde_t ** F, int count, const void *buf, static void send_new_ssl_certs_one(ssl_ctl_t * ctl, const char *ssl_cert, const char *ssl_private_key, - const char *ssl_dh_params, const char *ssl_cipher_list) + const char *ssl_dh_params, const char *ssl_cipher_list, const char *hostname) { size_t len; @@ -684,7 +699,10 @@ send_new_ssl_certs_one(ssl_ctl_t * ctl, const char *ssl_cert, const char *ssl_pr if (ssl_cipher_list == NULL) ssl_cipher_list = ""; - len = strlen(ssl_cert) + strlen(ssl_private_key) + strlen(ssl_dh_params) + strlen(ssl_cipher_list) + 6; + if (hostname == NULL) + hostname = ""; + + len = strlen(ssl_cert) + strlen(ssl_private_key) + strlen(ssl_dh_params) + strlen(ssl_cipher_list) + strlen(hostname) + 6; if(len > sizeof(tmpbuf)) { sendto_realops_snomask(SNO_GENERAL, L_ALL, @@ -695,8 +713,47 @@ send_new_ssl_certs_one(ssl_ctl_t * ctl, const char *ssl_cert, const char *ssl_pr len, sizeof(tmpbuf)); return; } - len = rb_snprintf(tmpbuf, sizeof(tmpbuf), "K%c%s%c%s%c%s%c%s%c", nul, ssl_cert, - nul, ssl_private_key, nul, ssl_dh_params, nul, ssl_cipher_list, nul); + len = rb_snprintf(tmpbuf, sizeof(tmpbuf), "K%c%s%c%s%c%s%c%s%c%s%c", nul, ssl_cert, + nul, ssl_private_key, nul, ssl_dh_params, nul, ssl_cipher_list, nul, hostname, nul); + ssl_cmd_write_queue(ctl, NULL, 0, tmpbuf, len); +} + +void +send_remove_ssl_vhost(const char *hostname) +{ + rb_dlink_node *ptr; + if(hostname == NULL) + { + return; + } + RB_DLINK_FOREACH(ptr, ssl_daemons.head) + { + ssl_ctl_t *ctl = ptr->data; + send_remove_ssl_vhost_one(ctl, hostname); + } +} + +static void +send_remove_ssl_vhost_one(ssl_ctl_t * ctl, const char *hostname) +{ + size_t len; + + if(hostname == NULL) + return; + + len = strlen(hostname) + 3; + if(len > sizeof(tmpbuf)) + { + sendto_realops_snomask(SNO_GENERAL, L_ALL, + "Parameters for send_init_prng too long (%zd > %zd) to pass to ssld, not sending...", + len, sizeof(tmpbuf)); + ilog(L_MAIN, + "Parameters for send_init_prng too long (%zd > %zd) to pass to ssld, not sending...", + len, sizeof(tmpbuf)); + return; + + } + len = rb_snprintf(tmpbuf, sizeof(tmpbuf), "D%c%s%c", nul, hostname, nul); ssl_cmd_write_queue(ctl, NULL, 0, tmpbuf, len); } @@ -739,7 +796,7 @@ send_certfp_method(ssl_ctl_t *ctl, int method) } void -send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list, const int method) +send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char *ssl_dh_params, const char *ssl_cipher_list, const int method, const char *hostname) { rb_dlink_node *ptr; if(ssl_cert == NULL) @@ -755,7 +812,7 @@ send_new_ssl_certs(const char *ssl_cert, const char *ssl_private_key, const char continue; send_certfp_method(ctl, method); - send_new_ssl_certs_one(ctl, ssl_cert, ssl_private_key, ssl_dh_params, ssl_cipher_list); + send_new_ssl_certs_one(ctl, ssl_cert, ssl_private_key, ssl_dh_params, ssl_cipher_list, hostname); } } diff --git a/ssld/ssld.c b/ssld/ssld.c index 8b17f2ff6..e540f406d 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -925,7 +925,7 @@ static void ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) { char *buf; - char *cert, *key, *dhparam, *cipher_list; + char *cert, *key, *dhparam, *cipher_list, *hostname; buf = (char *) &ctl_buf->buf[2]; cert = buf; @@ -935,6 +935,8 @@ ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) dhparam = buf; buf += strlen(dhparam) + 1; cipher_list = buf; + buf += strlen(cipher_list) + 1; + hostname = buf; if(strlen(key) == 0) key = cert; if(strlen(dhparam) == 0) @@ -942,7 +944,15 @@ ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) if(strlen(cipher_list) == 0) cipher_list = NULL; - if(!rb_setup_ssl_server(cert, key, dhparam, cipher_list)) + int ret; + if(strlen(hostname) == 0) { + ret = rb_setup_ssl_server(cert, key, dhparam, cipher_list, NULL); + } else { + ret = rb_setup_ssl_server(cert, key, dhparam, cipher_list, hostname); + return; + } + + if(!ret) { const char *invalid = "I"; mod_cmd_write_queue(ctl, invalid, strlen(invalid)); @@ -950,6 +960,24 @@ ssl_new_keys(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) } } +static void +ssl_remove_ssl_vhost(mod_ctl_t * ctl, mod_ctl_buf_t * ctl_buf) +{ + char *buf; + char *hostname; + + buf = (char *) &ctl_buf->buf[2]; + hostname = buf; + + if(!rb_remove_ssl_vserver(hostname)) + { + 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) { @@ -1054,6 +1082,16 @@ mod_process_cmd_recv(mod_ctl_t * ctl) ssl_new_keys(ctl, ctl_buf); break; } + case 'D': + { + if(!ssld_ssl_ok) + { + send_nossl_support(ctl, ctl_buf); + break; + } + ssl_remove_ssl_vhost(ctl, ctl_buf); + break; + } case 'I': init_prng(ctl, ctl_buf); break;