bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Siraineno_stream_ssl_close(struct iostream_private *stream, bool close_parent)
52d19b57c2411bb1c60f8248ea5c8c1a1cfc1b4fTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen o_stream_close(sstream->ssl_io->plain_output);
52d19b57c2411bb1c60f8248ea5c8c1a1cfc1b4fTimo Sirainenstatic void o_stream_ssl_destroy(struct iostream_private *stream)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Siraineno_stream_ssl_buffer(struct ssl_ostream *sstream, const struct const_iovec *iov,
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen unsigned int i;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen sstream->buffer = buffer_create_dynamic(default_pool, 4096);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen for (i = 0; i < iov_count; i++) {
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi /* we're requested to use whatever space is available in
1c3e5f6b1afaf119335e3892b0a5ca76a37acebdTimo Sirainen the buffer */
8b48c53a81bdc67f267ffbcc45ba9860cb49e977Timo Sirainen avail = buffer_get_writable_size(sstream->buffer) - sstream->buffer->used;
1c3e5f6b1afaf119335e3892b0a5ca76a37acebdTimo Sirainen avail = sstream->ostream.max_buffer_size > sstream->buffer->used ?
1c3e5f6b1afaf119335e3892b0a5ca76a37acebdTimo Sirainen sstream->ostream.max_buffer_size - sstream->buffer->used : 0;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen size = I_MIN(iov[i].iov_len - skip_left, avail);
ed41ec8aa0efaa50954fd16cb44c86c8350dadccTimo Sirainen o_stream_set_flush_pending(sstream->ssl_io->plain_output, TRUE);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen for (; i < iov_count; i++) {
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen buffer_append(sstream->buffer, iov[i].iov_base, size);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen sstream->ostream.ostream.offset += bytes_sent;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int o_stream_ssl_flush_buffer(struct ssl_ostream *sstream)
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* we're writing plaintext data to OpenSSL, which it encrypts
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen and writes to bio_int's buffer. ssl_iostream_bio_sync()
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen reads it from there and adds to plain_output stream. */
8bcf6fd065a71ae0ca6dc76989250e819d08d7f6Aki Tuomi ret = openssl_iostream_handle_error(sstream->ssl_io,
8bcf6fd065a71ae0ca6dc76989250e819d08d7f6Aki Tuomi ret, OPENSSL_IOSTREAM_SYNC_TYPE_WRITE, "SSL_write");
1c6f6f5bef70f16546b3bc8f4cd5f93f373e82a2Timo Sirainen io_stream_set_error(&sstream->ostream.iostream,
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen sstream->ostream.ostream.stream_errno = errno;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int o_stream_ssl_flush(struct ostream_private *stream)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
16d3a9396730dae3d869dc8159f9c1287fc9f28eStephan Bosch struct ostream *plain_output = sstream->ssl_io->plain_output;
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* handshake failed */
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen } else if (ret > 0 && sstream->buffer != NULL &&
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* we can try to send some of our buffered data */
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* we need to read more data until we can continue. */
16d3a9396730dae3d869dc8159f9c1287fc9f28eStephan Bosch o_stream_set_flush_pending(plain_output, FALSE);
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen sstream->ssl_io->ostream_flush_waiting_input = TRUE;
092762029d2fd162283c1df6a40ddc1019605798Stephan Bosch /* return 1 only when the output buffer is empty, which is what the
092762029d2fd162283c1df6a40ddc1019605798Stephan Bosch caller expects. */
092762029d2fd162283c1df6a40ddc1019605798Stephan Bosch return o_stream_get_buffer_used_size(plain_output) == 0 ? 1 : 0;
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Siraineno_stream_ssl_sendv(struct ostream_private *stream,
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen const struct const_iovec *iov, unsigned int iov_count)
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen bytes_sent = o_stream_ssl_buffer(sstream, iov, iov_count, bytes_sent);
b1faf5924b03c6863d37f828b6dfb67f91dafec8Timo Sirainen /* buffer was empty before calling this. try to write it
b1faf5924b03c6863d37f828b6dfb67f91dafec8Timo Sirainen immediately. */
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Boschstatic void o_stream_ssl_switch_ioloop_to(struct ostream_private *stream,
71da447014454c84828d9dface77219875554d7dTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch o_stream_switch_ioloop_to(sstream->ssl_io->plain_output, ioloop);
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainenstatic int plain_flush_callback(struct ssl_ostream *sstream)
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen struct ostream *ostream = &sstream->ostream.ostream;
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* try to actually flush the pending data */
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen if ((ret = o_stream_flush(sstream->ssl_io->plain_output)) < 0)
21fed972adb354b92771eefad27f8ac8cbd5dd45Timo Sirainen /* we may be able to copy more data, try it */
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen ret2 = sstream->ostream.callback(sstream->ostream.context);
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen ret2 = o_stream_flush(&sstream->ostream.ostream);
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen o_stream_set_flush_pending(sstream->ssl_io->plain_output, TRUE);
31df48d66a9a2327f6de41796e6819543c4494e1Timo Sirainenstatic size_t o_stream_ssl_get_used_size(const struct ostream_private *stream)
31df48d66a9a2327f6de41796e6819543c4494e1Timo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)stream;
31df48d66a9a2327f6de41796e6819543c4494e1Timo Sirainen return o_stream_get_buffer_used_size(sstream->ssl_io->plain_output);
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Siraineno_stream_ssl_flush_pending(struct ostream_private *_stream, bool set)
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)_stream;
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen o_stream_set_flush_pending(sstream->ssl_io->plain_output, set);
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainenstatic void o_stream_ssl_set_max_buffer_size(struct iostream_private *_stream,
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen struct ssl_ostream *sstream = (struct ssl_ostream *)_stream;
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen o_stream_set_max_buffer_size(sstream->ssl_io->plain_output, max_size);
3faa1040e5a3f9f35ffad29110216094ab2f5880Timo Sirainenstruct ostream *openssl_o_stream_create_ssl(struct ssl_iostream *ssl_io)
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen ssl_io->plain_output->real_stream->max_buffer_size;
52d19b57c2411bb1c60f8248ea5c8c1a1cfc1b4fTimo Sirainen sstream->ostream.iostream.close = o_stream_ssl_close;
52d19b57c2411bb1c60f8248ea5c8c1a1cfc1b4fTimo Sirainen sstream->ostream.iostream.destroy = o_stream_ssl_destroy;
8aa8399893c66b40e2790a4568256807a6ec6742Stephan Bosch sstream->ostream.switch_ioloop_to = o_stream_ssl_switch_ioloop_to;
31df48d66a9a2327f6de41796e6819543c4494e1Timo Sirainen sstream->ostream.get_used_size = o_stream_ssl_get_used_size;
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen sstream->ostream.flush_pending = o_stream_ssl_flush_pending;
c239a1de4ad80639335c3ea4564537ca441eb76aTimo Sirainen sstream->ostream.iostream.set_max_buffer_size =
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen sstream->ostream.callback = ssl_io->plain_output->real_stream->callback;
ce8cd19ccf52b19f14d4ea9c8b29bd94c0e48e4dTimo Sirainen sstream->ostream.context = ssl_io->plain_output->real_stream->context;
e98de01b5644c88b6053e2921eb5e9a506fe263fTimo Sirainen o_stream_set_flush_callback(ssl_io->plain_output,