summaryrefslogtreecommitdiff
path: root/modules/ssl/ssl_engine_io.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ssl/ssl_engine_io.c')
-rw-r--r--modules/ssl/ssl_engine_io.c994
1 files changed, 0 insertions, 994 deletions
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
deleted file mode 100644
index a2a338dc46..0000000000
--- a/modules/ssl/ssl_engine_io.c
+++ /dev/null
@@ -1,994 +0,0 @@
-/* _ _
-** _ __ ___ ___ __| | ___ ___| | mod_ssl
-** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
-** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
-** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
-** |_____|
-** ssl_engine_io.c
-** I/O Functions
-*/
-
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- */
- /* ``MY HACK: This universe.
- Just one little problem:
- core keeps dumping.''
- -- Unknown */
-#include "mod_ssl.h"
-
-/* _________________________________________________________________
-**
-** I/O Hooks
-** _________________________________________________________________
-*/
-
-/* XXX THIS STUFF NEEDS A MAJOR CLEANUP -RSE XXX */
-
-/* this custom BIO allows us to hook SSL_write directly into
- * an apr_bucket_brigade and use transient buckets with the SSL
- * malloc-ed buffer, rather than copying into a mem BIO.
- * also allows us to pass the brigade as data is being written
- * rather than buffering up the entire response in the mem BIO.
- *
- * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush()
- * which will trigger a call to bio_bucket_ctrl() -> BIO_bucket_flush().
- * so we only need to flush the output ourselves if we receive an
- * EOS or FLUSH bucket. this was not possible with the mem BIO where we
- * had to flush all over the place not really knowing when it was required
- * to do so.
- */
-
-typedef struct {
- SSLFilterRec *frec;
- conn_rec *c;
- apr_bucket_brigade *bb;
- apr_size_t length;
- char buffer[AP_IOBUFSIZE];
- apr_size_t blen;
-} BIO_bucket_t;
-
-static BIO_bucket_t *BIO_bucket_new(SSLFilterRec *frec, conn_rec *c)
-{
- BIO_bucket_t *b = apr_palloc(c->pool, sizeof(*b));
-
- b->frec = frec;
- b->c = c;
- b->bb = apr_brigade_create(c->pool);
- b->blen = 0;
- b->length = 0;
-
- return b;
-}
-
-#define BIO_bucket_ptr(bio) (BIO_bucket_t *)bio->ptr
-
-static int BIO_bucket_flush(BIO *bio)
-{
- BIO_bucket_t *b = BIO_bucket_ptr(bio);
-
- if (!(b->blen || b->length)) {
- return APR_SUCCESS;
- }
-
- if (b->blen) {
- apr_bucket *bucket =
- apr_bucket_transient_create(b->buffer,
- b->blen);
- /* we filled this buffer first so add it to the
- * head of the brigade
- */
- APR_BRIGADE_INSERT_HEAD(b->bb, bucket);
- b->blen = 0;
- }
-
- b->length = 0;
- APR_BRIGADE_INSERT_TAIL(b->bb, apr_bucket_flush_create());
-
- return ap_pass_brigade(b->frec->pOutputFilter->next, b->bb);
-}
-
-static int bio_bucket_new(BIO *bio)
-{
- bio->shutdown = 1;
- bio->init = 1;
- bio->num = -1;
- bio->ptr = NULL;
-
- return 1;
-}
-
-static int bio_bucket_free(BIO *bio)
-{
- if (bio == NULL) {
- return 0;
- }
-
- /* nothing to free here.
- * apache will destroy the bucket brigade for us
- */
- return 1;
-}
-
-static int bio_bucket_read(BIO *bio, char *out, int outl)
-{
- /* this is never called */
- return -1;
-}
-
-static int bio_bucket_write(BIO *bio, const char *in, int inl)
-{
- BIO_bucket_t *b = BIO_bucket_ptr(bio);
-
- /* when handshaking we'll have a small number of bytes.
- * max size SSL will pass us here is about 16k.
- * (16413 bytes to be exact)
- */
- BIO_clear_retry_flags(bio);
-
- if (!b->length && (inl + b->blen < sizeof(b->buffer))) {
- /* the first two SSL_writes (of 1024 and 261 bytes)
- * need to be in the same packet (vec[0].iov_base)
- */
- /* XXX: could use apr_brigade_write() to make code look cleaner
- * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE)
- * and free() of it later
- */
- memcpy(&b->buffer[b->blen], in, inl);
- b->blen += inl;
- }
- else {
- /* pass along the encrypted data
- * need to flush since we're using SSL's malloc-ed buffer
- * which will be overwritten once we leave here
- */
- apr_bucket *bucket = apr_bucket_transient_create(in, inl);
-
- b->length += inl;
- APR_BRIGADE_INSERT_TAIL(b->bb, bucket);
-
- BIO_bucket_flush(bio);
- }
-
- return inl;
-}
-
-static long bio_bucket_ctrl(BIO *bio, int cmd, long num, void *ptr)
-{
- long ret = 1;
- char **pptr;
-
- BIO_bucket_t *b = BIO_bucket_ptr(bio);
-
- switch (cmd) {
- case BIO_CTRL_RESET:
- b->blen = b->length = 0;
- break;
- case BIO_CTRL_EOF:
- ret = (long)((b->blen + b->length) == 0);
- break;
- case BIO_C_SET_BUF_MEM_EOF_RETURN:
- b->blen = b->length = (apr_size_t)num;
- break;
- case BIO_CTRL_INFO:
- ret = (long)(b->blen + b->length);
- if (ptr) {
- pptr = (char **)ptr;
- *pptr = (char *)&(b->buffer[0]);
- }
- break;
- case BIO_CTRL_GET_CLOSE:
- ret = (long)bio->shutdown;
- break;
- case BIO_CTRL_SET_CLOSE:
- bio->shutdown = (int)num;
- break;
- case BIO_CTRL_WPENDING:
- ret = 0L;
- break;
- case BIO_CTRL_PENDING:
- ret = (long)(b->blen + b->length);
- break;
- case BIO_CTRL_FLUSH:
- ret = (BIO_bucket_flush(bio) == APR_SUCCESS);
- break;
- case BIO_CTRL_DUP:
- ret = 1;
- break;
- /* N/A */
- case BIO_C_SET_BUF_MEM:
- case BIO_C_GET_BUF_MEM_PTR:
- /* we don't care */
- case BIO_CTRL_PUSH:
- case BIO_CTRL_POP:
- default:
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static int bio_bucket_gets(BIO *bio, char *buf, int size)
-{
- /* this is never called */
- return -1;
-}
-
-static int bio_bucket_puts(BIO *bio, const char *str)
-{
- /* this is never called */
- return -1;
-}
-
-static BIO_METHOD bio_bucket_method = {
- BIO_TYPE_MEM,
- "APR bucket brigade",
- bio_bucket_write,
- bio_bucket_read,
- bio_bucket_puts,
- bio_bucket_gets,
- bio_bucket_ctrl,
- bio_bucket_new,
- bio_bucket_free,
-#ifdef OPENSSL_VERSION_NUMBER
- NULL /* sslc does not have the callback_ctrl field */
-#endif
-};
-
-static BIO_METHOD *BIO_s_bucket(void)
-{
- return &bio_bucket_method;
-}
-
-typedef struct {
- int length;
- char *value;
-} char_buffer_t;
-
-typedef struct {
- SSL *ssl;
- BIO *wbio;
- ap_filter_t *f;
- apr_status_t rc;
- ap_input_mode_t mode;
- apr_read_type_e block;
- apr_bucket_brigade *bb;
- apr_bucket *bucket;
- char_buffer_t cbuf;
-} BIO_bucket_in_t;
-
-typedef struct {
- BIO_bucket_in_t inbio;
- char_buffer_t cbuf;
- apr_pool_t *pool;
- char buffer[AP_IOBUFSIZE];
- SSLFilterRec *frec;
-} ssl_io_input_ctx_t;
-
-/*
- * this char_buffer api might seem silly, but we don't need to copy
- * any of this data and we need to remember the length.
- */
-static int char_buffer_read(char_buffer_t *buffer, char *in, int inl)
-{
- if (!buffer->length) {
- return 0;
- }
-
- if (buffer->length > inl) {
- /* we have have enough to fill the caller's buffer */
- memcpy(in, buffer->value, inl);
- buffer->value += inl;
- buffer->length -= inl;
- }
- else {
- /* swallow remainder of the buffer */
- memcpy(in, buffer->value, buffer->length);
- inl = buffer->length;
- buffer->value = NULL;
- buffer->length = 0;
- }
-
- return inl;
-}
-
-static int char_buffer_write(char_buffer_t *buffer, char *in, int inl)
-{
- buffer->value = in;
- buffer->length = inl;
- return inl;
-}
-
-/*
- * this is the function called by SSL_read()
- */
-#define BIO_bucket_in_ptr(bio) (BIO_bucket_in_t *)bio->ptr
-
-static int bio_bucket_in_read(BIO *bio, char *in, int inl)
-{
- BIO_bucket_in_t *inbio = BIO_bucket_in_ptr(bio);
- int len = 0;
-
- /* XXX: flush here only required for SSLv2;
- * OpenSSL calls BIO_flush() at the appropriate times for
- * the other protocols.
- */
- if (SSL_version(inbio->ssl) == SSL2_VERSION) {
- BIO_bucket_flush(inbio->wbio);
- }
-
- inbio->rc = APR_SUCCESS;
-
- /* first use data already read from socket if any */
- if ((len = char_buffer_read(&inbio->cbuf, in, inl))) {
- if ((len <= inl) || inbio->mode == AP_MODE_GETLINE) {
- return len;
- }
- inl -= len;
- }
-
- while (1) {
- const char *buf;
- apr_size_t buf_len = 0;
-
- if (inbio->bucket) {
- /* all of the data in this bucket has been read,
- * so we can delete it now.
- */
- apr_bucket_delete(inbio->bucket);
- inbio->bucket = NULL;
- }
-
- if (APR_BRIGADE_EMPTY(inbio->bb)) {
- /* We will always call with READBYTES even if the user wants
- * GETLINE.
- */
- inbio->rc = ap_get_brigade(inbio->f->next, inbio->bb,
- AP_MODE_READBYTES, inbio->block,
- inl);
-
- if ((inbio->rc != APR_SUCCESS) || APR_BRIGADE_EMPTY(inbio->bb))
- {
- break;
- }
- }
-
- inbio->bucket = APR_BRIGADE_FIRST(inbio->bb);
-
- inbio->rc = apr_bucket_read(inbio->bucket,
- &buf, &buf_len, inbio->block);
-
- if (inbio->rc != APR_SUCCESS) {
- apr_bucket_delete(inbio->bucket);
- inbio->bucket = NULL;
- return len;
- }
-
- if (buf_len) {
- /* Protected against len > MAX_INT
- */
- if ((len + (int)buf_len) >= inl || (int)buf_len < 0) {
- /* we have enough to fill the buffer.
- * append if we have already written to the buffer.
- */
- int nibble = inl - len;
- char *value = (char *)buf+nibble;
-
- int length = buf_len - nibble;
- memcpy(in + len, buf, nibble);
-
- char_buffer_write(&inbio->cbuf, value, length);
- len += nibble;
-
- break;
- }
- else {
- /* not enough data,
- * save what we have and try to read more.
- */
- memcpy(in + len, buf, buf_len);
- len += buf_len;
- }
- }
-
- if (inbio->mode == AP_MODE_GETLINE) {
- /* only read from the socket once in getline mode.
- * since callers buffer size is likely much larger than
- * the request headers. caller can always come back for more
- * if first read didn't get all the headers.
- */
- break;
- }
- }
-
- return len;
-}
-
-static BIO_METHOD bio_bucket_in_method = {
- BIO_TYPE_MEM,
- "APR input bucket brigade",
- NULL, /* write is never called */
- bio_bucket_in_read,
- NULL, /* puts is never called */
- NULL, /* gets is never called */
- NULL, /* ctrl is never called */
- bio_bucket_new,
- bio_bucket_free,
-#ifdef OPENSSL_VERSION_NUMBER
- NULL /* sslc does not have the callback_ctrl field */
-#endif
-};
-
-static BIO_METHOD *BIO_s_in_bucket(void)
-{
- return &bio_bucket_in_method;
-}
-
-static const char ssl_io_filter[] = "SSL/TLS Filter";
-
-static int ssl_io_hook_read(SSL *ssl, char *buf, int len)
-{
- int rc;
-
- if (ssl == NULL) {
- return -1;
- }
-
- rc = SSL_read(ssl, buf, len);
-
- if (rc < 0) {
- int ssl_err = SSL_get_error(ssl, rc);
-
- if (ssl_err == SSL_ERROR_WANT_READ) {
- /*
- * Simulate an EINTR in case OpenSSL wants to read more.
- * (This is usually the case when the client forces an SSL
- * renegotation which is handled implicitly by OpenSSL.)
- */
- errno = EINTR;
- }
- else if (ssl_err == SSL_ERROR_SSL) {
- /*
- * Log SSL errors
- */
- conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
- "SSL error on reading data");
- }
- /*
- * XXX - Just trying to reflect the behaviour in
- * openssl_state_machine.c [mod_tls]. TBD
- */
- rc = -1;
- }
- return rc;
-}
-
-static int ssl_io_hook_write(SSL *ssl, unsigned char *buf, int len)
-{
- int rc;
-
- if (ssl == NULL) {
- return -1;
- }
-
- rc = SSL_write(ssl, buf, len);
-
- if (rc < 0) {
- int ssl_err = SSL_get_error(ssl, rc);
-
- if (ssl_err == SSL_ERROR_WANT_WRITE) {
- /*
- * Simulate an EINTR in case OpenSSL wants to write more.
- */
- errno = EINTR;
- }
- else if (ssl_err == SSL_ERROR_SSL) {
- /*
- * Log SSL errors
- */
- conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- ssl_log(c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
- "SSL error on writing data");
- }
- /*
- * XXX - Just trying to reflect the behaviour in
- * openssl_state_machine.c [mod_tls]. TBD
- */
- rc = 0;
- }
- return rc;
-}
-
-static apr_status_t ssl_filter_write(ap_filter_t *f,
- const char *data,
- apr_size_t len)
-{
- SSLFilterRec *ctx = f->ctx;
- apr_size_t n;
-
- /* write SSL */
- n = ssl_io_hook_write(ctx->pssl, (unsigned char *)data, len);
-
- if (n != len) {
- conn_rec *c = f->c;
- char *reason = "reason unknown";
-
- /* XXX: probably a better way to determine this */
- if (SSL_total_renegotiations(ctx->pssl)) {
- reason = "likely due to failed renegotiation";
- }
-
- ssl_log(c->base_server, SSL_LOG_ERROR,
- "failed to write %d of %d bytes (%s)",
- n > 0 ? len - n : len, len, reason);
-
- return APR_EINVAL;
- }
-
- return APR_SUCCESS;
-}
-
-static apr_status_t ssl_io_filter_Output(ap_filter_t *f,
- apr_bucket_brigade *bb)
-{
- apr_status_t status = APR_SUCCESS;
-
- while (!APR_BRIGADE_EMPTY(bb)) {
- apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
-
- /* If it is a flush or EOS, we need to pass this down.
- * These types do not require translation by OpenSSL.
- */
- if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
- SSLFilterRec *ctx = f->ctx;
-
- if ((status = BIO_bucket_flush(ctx->pbioWrite)) != APR_SUCCESS) {
- return status;
- }
-
- if (APR_BUCKET_IS_EOS(bucket)) {
- /* By definition, nothing can come after EOS.
- * which also means we can pass the rest of this brigade
- * without creating a new one since it only contains the
- * EOS bucket.
- */
-
- if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
- return status;
- }
- break;
- }
- else {
- /* BIO_bucket_flush() already passed down a flush bucket
- * if there was any data to be flushed.
- */
- apr_bucket_delete(bucket);
- }
- }
- else {
- /* read filter */
- const char *data;
- apr_size_t len;
-
- apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
- status = ssl_filter_write(f, data, len);
- apr_bucket_delete(bucket);
-
- if (status != APR_SUCCESS) {
- break;
- }
- }
- }
-
- return status;
-}
-
-/*
- * ctx->cbuf is leftover plaintext from ssl_io_input_getline,
- * use what we have there first if any,
- * then go for more by calling ssl_io_hook_read.
- */
-static apr_status_t ssl_io_input_read(ssl_io_input_ctx_t *ctx,
- char *buf,
- apr_size_t *len)
-{
- apr_size_t wanted = *len;
- apr_size_t bytes = 0;
- int rc;
-
- *len = 0;
-
- if ((bytes = char_buffer_read(&ctx->cbuf, buf, wanted))) {
- *len = bytes;
- if (ctx->inbio.mode == AP_MODE_SPECULATIVE) {
- /* We want to rollback this read. */
- ctx->cbuf.value -= bytes;
- ctx->cbuf.length += bytes;
- return APR_SUCCESS;
- }
- if ((*len >= wanted) || ctx->inbio.mode == AP_MODE_GETLINE) {
- return APR_SUCCESS;
- }
- }
-
- rc = ssl_io_hook_read(ctx->frec->pssl, buf + bytes, wanted - bytes);
-
- if (rc > 0) {
- *len += rc;
- if (ctx->inbio.mode == AP_MODE_SPECULATIVE) {
- char_buffer_write(&ctx->cbuf, buf, rc);
- }
- }
-
- return ctx->inbio.rc;
-}
-
-static apr_status_t ssl_io_input_getline(ssl_io_input_ctx_t *ctx,
- char *buf,
- apr_size_t *len)
-{
- const char *pos = NULL;
- apr_status_t status;
- apr_size_t tmplen = *len, buflen = *len, offset = 0;
-
- *len = 0;
-
- /*
- * in most cases we get all the headers on the first SSL_read.
- * however, in certain cases SSL_read will only get a partial
- * chunk of the headers, so we try to read until LF is seen.
- */
-
- while (tmplen > 0) {
- status = ssl_io_input_read(ctx, buf + offset, &tmplen);
-
- if (status != APR_SUCCESS) {
- return status;
- }
-
- *len += tmplen;
-
- if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
- break;
- }
-
- offset += tmplen;
- tmplen = buflen - offset;
- }
-
- if (pos) {
- char *value;
- int length;
- apr_size_t bytes = pos - buf;
-
- bytes += 1;
- value = buf + bytes;
- length = *len - bytes;
-
- char_buffer_write(&ctx->cbuf, value, length);
-
- *len = bytes;
- }
-
- return APR_SUCCESS;
-}
-
-#define HTTP_ON_HTTPS_PORT \
- "GET /mod_ssl:error:HTTP-request HTTP/1.0\r\n\r\n"
-
-#define HTTP_ON_HTTPS_PORT_BUCKET() \
- apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \
- sizeof(HTTP_ON_HTTPS_PORT) - 1)
-
-static apr_status_t ssl_io_filter_error(ap_filter_t *f,
- apr_bucket_brigade *bb,
- apr_status_t status)
-{
- apr_bucket *bucket;
-
- switch (status) {
- case HTTP_BAD_REQUEST:
- /* log the situation */
- ssl_log(f->c->base_server, SSL_LOG_ERROR|SSL_ADD_SSLERR,
- "SSL handshake failed: HTTP spoken on HTTPS port; "
- "trying to send HTML error page");
-
- /* fake the request line */
- bucket = HTTP_ON_HTTPS_PORT_BUCKET();
- break;
-
- default:
- return status;
- }
-
- APR_BRIGADE_INSERT_TAIL(bb, bucket);
-
- return APR_SUCCESS;
-}
-
-static apr_status_t ssl_io_filter_Input(ap_filter_t *f,
- apr_bucket_brigade *bb,
- ap_input_mode_t mode,
- apr_read_type_e block,
- apr_off_t readbytes)
-{
- apr_status_t status;
- ssl_io_input_ctx_t *ctx = f->ctx;
-
- apr_size_t len = sizeof(ctx->buffer);
- int is_init = (mode == AP_MODE_INIT);
-
- /* XXX: we don't currently support anything other than these modes. */
- if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
- mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
- return APR_ENOTIMPL;
- }
-
- ctx->inbio.mode = mode;
- ctx->inbio.block = block;
-
- /* XXX: we could actually move ssl_hook_process_connection to an
- * ap_hook_process_connection but would still need to call it for
- * AP_MODE_INIT for protocols that may upgrade the connection
- * rather than have SSLEngine On configured.
- */
- status = ssl_hook_process_connection(ctx->frec);
-
- if (status != APR_SUCCESS) {
- return ssl_io_filter_error(f, bb, status);
- }
-
- if (is_init) {
- /* protocol module needs to handshake before sending
- * data to client (e.g. NNTP or FTP)
- */
- return APR_SUCCESS;
- }
-
- if (ctx->inbio.mode == AP_MODE_READBYTES ||
- ctx->inbio.mode == AP_MODE_SPECULATIVE) {
- /* Protected from truncation, readbytes < MAX_SIZE_T
- * FIXME: No, it's *not* protected. -- jre */
- if (readbytes < len) {
- len = (apr_size_t)readbytes;
- }
- status = ssl_io_input_read(ctx, ctx->buffer, &len);
- }
- else if (ctx->inbio.mode == AP_MODE_GETLINE) {
- status = ssl_io_input_getline(ctx, ctx->buffer, &len);
- }
- else {
- /* We have no idea what you are talking about, so return an error. */
- return APR_ENOTIMPL;
- }
-
- if (status != APR_SUCCESS) {
- return ssl_io_filter_error(f, bb, status);
- }
-
- if (len > 0) {
- apr_bucket *bucket =
- apr_bucket_transient_create(ctx->buffer, len);
- APR_BRIGADE_INSERT_TAIL(bb, bucket);
- }
-
- return APR_SUCCESS;
-}
-
-static void ssl_io_input_add_filter(SSLFilterRec *frec, conn_rec *c,
- SSL *ssl)
-{
- ssl_io_input_ctx_t *ctx;
-
- ctx = apr_palloc(c->pool, sizeof(*ctx));
-
- frec->pInputFilter = ap_add_input_filter(ssl_io_filter, ctx, NULL, c);
-
- frec->pbioRead = BIO_new(BIO_s_in_bucket());
- frec->pbioRead->ptr = &ctx->inbio;
-
- ctx->frec = frec;
- ctx->inbio.ssl = ssl;
- ctx->inbio.wbio = frec->pbioWrite;
- ctx->inbio.f = frec->pInputFilter;
- ctx->inbio.bb = apr_brigade_create(c->pool);
- ctx->inbio.bucket = NULL;
- ctx->inbio.cbuf.length = 0;
-
- ctx->cbuf.length = 0;
-
- ctx->pool = c->pool;
-}
-
-static apr_status_t ssl_io_filter_cleanup (void *data)
-{
- apr_status_t ret;
- SSLFilterRec *pRec = (SSLFilterRec *)data;
-
- if (!pRec->pssl) {
- /* already been shutdown */
- return APR_SUCCESS;
- }
-
- if ((ret = ssl_hook_CloseConnection(pRec)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_ERR, ret, NULL,
- "Error in ssl_hook_CloseConnection");
- }
-
- return ret;
-}
-
-void ssl_io_filter_init(conn_rec *c, SSL *ssl)
-{
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
- SSLFilterRec *filter;
-
- filter = apr_palloc(c->pool, sizeof(SSLFilterRec));
-
- filter->pOutputFilter = ap_add_output_filter(ssl_io_filter,
- filter, NULL, c);
-
- filter->pbioWrite = BIO_new(BIO_s_bucket());
- filter->pbioWrite->ptr = BIO_bucket_new(filter, c);
-
- ssl_io_input_add_filter(filter, c, ssl);
-
- SSL_set_bio(ssl, filter->pbioRead, filter->pbioWrite);
- filter->pssl = ssl;
-
- apr_pool_cleanup_register(c->pool, (void*)filter,
- ssl_io_filter_cleanup, apr_pool_cleanup_null);
-
- if (sc->nLogLevel >= SSL_LOG_DEBUG) {
- BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
- BIO_set_callback_arg(SSL_get_rbio(ssl), ssl);
- }
-
- return;
-}
-
-void ssl_io_filter_register(apr_pool_t *p)
-{
- ap_register_input_filter (ssl_io_filter, ssl_io_filter_Input, AP_FTYPE_CONNECTION + 5);
- ap_register_output_filter (ssl_io_filter, ssl_io_filter_Output, AP_FTYPE_CONNECTION + 5);
- return;
-}
-
-/* _________________________________________________________________
-**
-** I/O Data Debugging
-** _________________________________________________________________
-*/
-
-#define DUMP_WIDTH 16
-
-static void ssl_io_data_dump(server_rec *srvr, const char *s, long len)
-{
- char buf[256];
- char tmp[64];
- int i, j, rows, trunc;
- unsigned char ch;
-
- trunc = 0;
- for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--)
- trunc++;
- rows = (len / DUMP_WIDTH);
- if ((rows * DUMP_WIDTH) < len)
- rows++;
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "+-------------------------------------------------------------------------+");
- for(i = 0 ; i< rows; i++) {
- apr_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
- apr_cpystrn(buf, tmp, sizeof(buf));
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len)
- apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- else {
- ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
- apr_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
- apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
- }
- }
- apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len)
- apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- else {
- ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
- apr_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
- apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
- }
- }
- apr_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf);
- }
- if (trunc > 0)
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "| %04x - <SPACES/NULS>", len + trunc);
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "+-------------------------------------------------------------------------+");
- return;
-}
-
-long ssl_io_data_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long rc)
-{
- SSL *ssl;
- conn_rec *c;
- server_rec *s;
-
- if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
- return rc;
- if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
- return rc;
- s = c->base_server;
-
- if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
- || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
- if (rc >= 0) {
- ssl_log(s, SSL_LOG_DEBUG,
- "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s",
- SSL_LIBRARY_NAME,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
- rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
- bio, argp,
- (argp != NULL ? "(BIO dump follows)" : "(Ops, no memory buffer?)"));
- if (argp != NULL)
- ssl_io_data_dump(s, argp, rc);
- }
- else {
- ssl_log(s, SSL_LOG_DEBUG,
- "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
- SSL_LIBRARY_NAME, argi,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
- bio, argp);
- }
- }
- return rc;
-}