diff options
Diffstat (limited to 'modules/ssl/ssl_engine_io.c')
-rw-r--r-- | modules/ssl/ssl_engine_io.c | 994 |
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; -} |