From: Stephan Bosch Date: Mon, 26 Oct 2020 09:19:46 +0000 (+0100) Subject: lib-ssl-iosteam: ostream-openssl - Make sure error on plaintext streams is propagated. X-Git-Tag: 2.3.13~51 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=75ab810591e60e7519e8782f424bf5517fff370e;p=thirdparty%2Fdovecot%2Fcore.git lib-ssl-iosteam: ostream-openssl - Make sure error on plaintext streams is propagated. --- diff --git a/src/lib-ssl-iostream/iostream-openssl.c b/src/lib-ssl-iostream/iostream-openssl.c index 96fcba848a..5d11526f11 100644 --- a/src/lib-ssl-iostream/iostream-openssl.c +++ b/src/lib-ssl-iostream/iostream-openssl.c @@ -386,12 +386,12 @@ static void openssl_iostream_destroy(struct ssl_iostream *ssl_io) ssl_iostream_unref(&ssl_io); } -static bool openssl_iostream_bio_output(struct ssl_iostream *ssl_io) +static int openssl_iostream_bio_output(struct ssl_iostream *ssl_io) { size_t bytes, max_bytes; ssize_t sent; unsigned char buffer[IO_BLOCK_SIZE]; - bool bytes_sent = FALSE; + int result = 0; int ret; o_stream_cork(ssl_io->plain_output); @@ -428,13 +428,14 @@ static bool openssl_iostream_bio_output(struct ssl_iostream *ssl_io) ssl_io->plain_stream_errno = ssl_io->plain_output->stream_errno; ssl_io->closed = TRUE; + result = -1; break; } i_assert(sent == (ssize_t)bytes); - bytes_sent = TRUE; + result = 1; } o_stream_uncork(ssl_io->plain_output); - return bytes_sent; + return result; } static ssize_t @@ -458,8 +459,9 @@ openssl_iostream_read_more(struct ssl_iostream *ssl_io, return 0; } -static bool openssl_iostream_bio_input(struct ssl_iostream *ssl_io, - enum openssl_iostream_sync_type type) +static int +openssl_iostream_bio_input(struct ssl_iostream *ssl_io, + enum openssl_iostream_sync_type type) { const unsigned char *data; size_t bytes, size; @@ -480,7 +482,7 @@ static bool openssl_iostream_bio_input(struct ssl_iostream *ssl_io, ssl_io->plain_input->stream_errno; } ssl_io->closed = TRUE; - return FALSE; + return -1; } if (size == 0) { /* wait for more input */ @@ -503,7 +505,7 @@ static bool openssl_iostream_bio_input(struct ssl_iostream *ssl_io, i_strdup("SSL BIO buffer size too small"); ssl_io->plain_stream_errno = EINVAL; ssl_io->closed = TRUE; - return FALSE; + return -1; } if (i_stream_get_data_size(ssl_io->plain_input) > 0) { i_error("SSL: Too much data in buffered plain input buffer"); @@ -512,7 +514,7 @@ static bool openssl_iostream_bio_input(struct ssl_iostream *ssl_io, i_strdup("SSL: Too much data in buffered plain input buffer"); ssl_io->plain_stream_errno = EINVAL; ssl_io->closed = TRUE; - return FALSE; + return -1; } if (bytes_read) { if (ssl_io->ostream_flush_waiting_input) { @@ -524,17 +526,17 @@ static bool openssl_iostream_bio_input(struct ssl_iostream *ssl_io, i_stream_set_input_pending(ssl_io->ssl_input, TRUE); ssl_io->want_read = FALSE; } - return bytes_read; + return (bytes_read ? 1 : 0); } -bool openssl_iostream_bio_sync(struct ssl_iostream *ssl_io, - enum openssl_iostream_sync_type type) +int openssl_iostream_bio_sync(struct ssl_iostream *ssl_io, + enum openssl_iostream_sync_type type) { - bool ret; + int ret; ret = openssl_iostream_bio_output(ssl_io); - if (openssl_iostream_bio_input(ssl_io, type)) - ret = TRUE; + if (ret >= 0 && openssl_iostream_bio_input(ssl_io, type) > 0) + ret = 1; return ret; } @@ -547,7 +549,8 @@ int openssl_iostream_more(struct ssl_iostream *ssl_io, if ((ret = ssl_iostream_handshake(ssl_io)) <= 0) return ret; } - (void)openssl_iostream_bio_sync(ssl_io, type); + if (openssl_iostream_bio_sync(ssl_io, type) < 0) + return -1; return 1; } @@ -573,7 +576,7 @@ int openssl_iostream_handle_error(struct ssl_iostream *ssl_io, int ret, err = SSL_get_error(ssl_io->ssl, ret); switch (err) { case SSL_ERROR_WANT_WRITE: - if (!openssl_iostream_bio_sync(ssl_io, type)) { + if (openssl_iostream_bio_sync(ssl_io, type) == 0) { if (type != OPENSSL_IOSTREAM_SYNC_TYPE_WRITE) i_panic("SSL ostream buffer size not unlimited"); return 0; diff --git a/src/lib-ssl-iostream/iostream-openssl.h b/src/lib-ssl-iostream/iostream-openssl.h index 11ed286453..e5f5faac35 100644 --- a/src/lib-ssl-iostream/iostream-openssl.h +++ b/src/lib-ssl-iostream/iostream-openssl.h @@ -99,10 +99,11 @@ bool openssl_cert_match_name(SSL *ssl, const char *verify_name, int openssl_min_protocol_to_options(const char *min_protocol, long *opt_r, int *version_r) ATTR_NULL(2,3); -/* Sync plain_input/plain_output streams with BIOs. Returns TRUE if at least - one byte was read/written. */ -bool openssl_iostream_bio_sync(struct ssl_iostream *ssl_io, - enum openssl_iostream_sync_type type); +/* Sync plain_input/plain_output streams with BIOs. Returns 1 if at least + one byte was read/written, 0 if nothing was written, and -1 if an error + occurred. */ +int openssl_iostream_bio_sync(struct ssl_iostream *ssl_io, + enum openssl_iostream_sync_type type); /* Call when there's more data available in plain_input/plain_output. Returns 1 if it's ok to continue with SSL_read/SSL_write, 0 if not (still handshaking), -1 if error occurred. */ diff --git a/src/lib-ssl-iostream/ostream-openssl.c b/src/lib-ssl-iostream/ostream-openssl.c index c763493322..a696056581 100644 --- a/src/lib-ssl-iostream/ostream-openssl.c +++ b/src/lib-ssl-iostream/ostream-openssl.c @@ -123,8 +123,18 @@ static int o_stream_ssl_flush_buffer(struct ssl_ostream *sstream) break; } else { pos += ret; - (void)openssl_iostream_bio_sync( + ret = openssl_iostream_bio_sync( ssl_io, OPENSSL_IOSTREAM_SYNC_TYPE_WRITE); + if (ret < 0) { + i_assert(ssl_io->plain_stream_errstr != NULL && + ssl_io->plain_stream_errno != 0); + io_stream_set_error( + &sstream->ostream.iostream, + "%s", ssl_io->plain_stream_errstr); + sstream->ostream.ostream.stream_errno = + ssl_io->plain_stream_errno; + break; + } } } buffer_delete(sstream->buffer, 0, pos);