diff options
-rw-r--r-- | server/reds.c | 85 | ||||
-rw-r--r-- | server/reds_stream.c | 50 | ||||
-rw-r--r-- | server/reds_stream.h | 2 |
3 files changed, 82 insertions, 55 deletions
diff --git a/server/reds.c b/server/reds.c index 3f625fa7..2e56758a 100644 --- a/server/reds.c +++ b/server/reds.c @@ -37,12 +37,8 @@ #include <ctype.h> #include <stdbool.h> -#include <openssl/bio.h> -#include <openssl/pem.h> -#include <openssl/bn.h> -#include <openssl/rsa.h> -#include <openssl/ssl.h> #include <openssl/err.h> + #if HAVE_SASL #include <sasl/sasl.h> #endif @@ -2677,24 +2673,22 @@ static void reds_handle_new_link(RedLinkInfo *link) static void reds_handle_ssl_accept(int fd, int event, void *data) { RedLinkInfo *link = (RedLinkInfo *)data; - int return_code; + int return_code = reds_stream_ssl_accept(link->stream); - if ((return_code = SSL_accept(link->stream->ssl)) != 1) { - int ssl_error = SSL_get_error(link->stream->ssl, return_code); - if (ssl_error != SSL_ERROR_WANT_READ && ssl_error != SSL_ERROR_WANT_WRITE) { - spice_warning("SSL_accept failed, error=%d", ssl_error); + switch (return_code) { + case REDS_STREAM_SSL_STATUS_ERROR: reds_link_free(link); - } else { - if (ssl_error == SSL_ERROR_WANT_READ) { - core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_READ); - } else { - core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_WRITE); - } - } - return; + return; + case REDS_STREAM_SSL_STATUS_WAIT_FOR_READ: + core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_READ); + return; + case REDS_STREAM_SSL_STATUS_WAIT_FOR_WRITE: + core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_WRITE); + return; + case REDS_STREAM_SSL_STATUS_OK: + reds_stream_remove_watch(link->stream); + reds_handle_new_link(link); } - reds_stream_remove_watch(link->stream); - reds_handle_new_link(link); } static RedLinkInfo *reds_init_client_connection(int socket) @@ -2756,52 +2750,33 @@ error: static RedLinkInfo *reds_init_client_ssl_connection(int socket) { RedLinkInfo *link; - int return_code; - int ssl_error; - BIO *sbio; + int ssl_status; link = reds_init_client_connection(socket); if (link == NULL) goto error; - // Handle SSL handshaking - if (!(sbio = BIO_new_socket(link->stream->socket, BIO_NOCLOSE))) { - spice_warning("could not allocate ssl bio socket"); - goto error; - } - - link->stream->ssl = SSL_new(reds->ctx); - if (!link->stream->ssl) { - spice_warning("could not allocate ssl context"); - BIO_free(sbio); - goto error; - } - - SSL_set_bio(link->stream->ssl, sbio, sbio); - link->stream->write = stream_ssl_write_cb; link->stream->read = stream_ssl_read_cb; link->stream->writev = NULL; - return_code = SSL_accept(link->stream->ssl); - if (return_code == 1) { - reds_handle_new_link(link); - return link; - } - - ssl_error = SSL_get_error(link->stream->ssl, return_code); - if (return_code == -1 && (ssl_error == SSL_ERROR_WANT_READ || - ssl_error == SSL_ERROR_WANT_WRITE)) { - int eventmask = ssl_error == SSL_ERROR_WANT_READ ? - SPICE_WATCH_EVENT_READ : SPICE_WATCH_EVENT_WRITE; - link->stream->watch = core->watch_add(link->stream->socket, eventmask, + ssl_status = reds_stream_enable_ssl(link->stream, reds->ctx); + switch (ssl_status) { + case REDS_STREAM_SSL_STATUS_OK: + reds_handle_new_link(link); + return link; + case REDS_STREAM_SSL_STATUS_ERROR: + goto error; + case REDS_STREAM_SSL_STATUS_WAIT_FOR_READ: + link->stream->watch = core->watch_add(link->stream->socket, SPICE_WATCH_EVENT_READ, reds_handle_ssl_accept, link); - return link; + break; + case REDS_STREAM_SSL_STATUS_WAIT_FOR_WRITE: + link->stream->watch = core->watch_add(link->stream->socket, SPICE_WATCH_EVENT_WRITE, + reds_handle_ssl_accept, link); + break; } - - ERR_print_errors_fp(stderr); - spice_warning("SSL_accept failed, error=%d", ssl_error); - SSL_free(link->stream->ssl); + return link; error: free(link->stream); diff --git a/server/reds_stream.c b/server/reds_stream.c index 093621fb..5ec0efa8 100644 --- a/server/reds_stream.c +++ b/server/reds_stream.c @@ -149,6 +149,56 @@ void reds_stream_push_channel_event(RedsStream *s, int event) main_dispatcher_channel_event(event, s->info); } +RedsStreamSslStatus reds_stream_ssl_accept(RedsStream *stream) +{ + int ssl_error; + int return_code; + + return_code = SSL_accept(stream->ssl); + if (return_code == 1) { + return REDS_STREAM_SSL_STATUS_OK; + } + + ssl_error = SSL_get_error(stream->ssl, return_code); + if (return_code == -1 && (ssl_error == SSL_ERROR_WANT_READ || + ssl_error == SSL_ERROR_WANT_WRITE)) { + if (ssl_error == SSL_ERROR_WANT_READ) { + return REDS_STREAM_SSL_STATUS_WAIT_FOR_READ; + } else { + return REDS_STREAM_SSL_STATUS_WAIT_FOR_WRITE; + } + } + + ERR_print_errors_fp(stderr); + spice_warning("SSL_accept failed, error=%d", ssl_error); + SSL_free(stream->ssl); + stream->ssl = NULL; + + return REDS_STREAM_SSL_STATUS_ERROR; +} + +int reds_stream_enable_ssl(RedsStream *stream, SSL_CTX *ctx) +{ + BIO *sbio; + + // Handle SSL handshaking + if (!(sbio = BIO_new_socket(stream->socket, BIO_NOCLOSE))) { + spice_warning("could not allocate ssl bio socket"); + return REDS_STREAM_SSL_STATUS_ERROR; + } + + stream->ssl = SSL_new(ctx); + if (!stream->ssl) { + spice_warning("could not allocate ssl context"); + BIO_free(sbio); + return REDS_STREAM_SSL_STATUS_ERROR; + } + + SSL_set_bio(stream->ssl, sbio, sbio); + + return reds_stream_ssl_accept(stream); +} + #if HAVE_SASL bool reds_stream_write_u8(RedsStream *s, uint8_t n) { diff --git a/server/reds_stream.h b/server/reds_stream.h index c7254142..a0a3651f 100644 --- a/server/reds_stream.h +++ b/server/reds_stream.h @@ -101,5 +101,7 @@ void reds_stream_free(RedsStream *s); void reds_stream_push_channel_event(RedsStream *s, int event); void reds_stream_remove_watch(RedsStream* s); +RedsStreamSslStatus reds_stream_ssl_accept(RedsStream *stream); +int reds_stream_enable_ssl(RedsStream *stream, SSL_CTX *ctx); #endif |