From c0b7206652b2852bc574694e7ba07ba1c2acdc00 Mon Sep 17 00:00:00 2001 From: hongbotian Date: Mon, 30 Nov 2015 03:10:21 -0500 Subject: delete app Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2 Signed-off-by: hongbotian --- .../app/httpd-2.0.64/modules/ssl/ssl_engine_io.c | 1746 -------------------- 1 file changed, 1746 deletions(-) delete mode 100644 rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c (limited to 'rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c') diff --git a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c b/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c deleted file mode 100644 index c5fe6b8c..00000000 --- a/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c +++ /dev/null @@ -1,1746 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_engine_io.c - * I/O Functions - */ - /* ``MY HACK: This universe. - Just one little problem: - core keeps dumping.'' - -- Unknown */ -#include "mod_ssl.h" - -/* _________________________________________________________________ -** -** I/O Hooks -** _________________________________________________________________ -*/ - -/* This file is designed to be the bridge between OpenSSL and httpd. - * However, we really don't expect anyone (let alone ourselves) to - * remember what is in this file. So, first, a quick overview. - * - * In this file, you will find: - * - ssl_io_filter_input (Apache input filter) - * - ssl_io_filter_output (Apache output filter) - * - * - bio_filter_in_* (OpenSSL input filter) - * - bio_filter_out_* (OpenSSL output filter) - * - * The input chain is roughly: - * - * ssl_io_filter_input->ssl_io_input_read->SSL_read->... - * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter - * - * In mortal terminology, we do the following: - * - Receive a request for data to the SSL input filter - * - Call a helper function once we know we should perform a read - * - Call OpenSSL's SSL_read() - * - SSL_read() will then call bio_filter_in_read - * - bio_filter_in_read will then try to fetch data from the next httpd filter - * - bio_filter_in_read will flatten that data and return it to SSL_read - * - SSL_read will then decrypt the data - * - ssl_io_input_read will then receive decrypted data as a char* and - * ensure that there were no read errors - * - The char* is placed in a brigade and returned - * - * Since connection-level input filters in httpd need to be able to - * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings), - * ssl_io_input_getline which will handle this special case. - * - * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have - * 'leftover' decoded data which must be setaside for the next read. That - * is currently handled by the char_buffer_{read|write} functions. So, - * ssl_io_input_read may be able to fulfill reads without invoking - * SSL_read(). - * - * Note that the filter context of ssl_io_filter_input and bio_filter_in_* - * are shared as bio_filter_in_ctx_t. - * - * Note that the filter is by choice limited to reading at most - * AP_IOBUFSIZE (8192 bytes) per call. - * - */ - -/* 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_filter_out_ctrl() -> bio_filter_out_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 { - SSL *pssl; - BIO *pbioRead; - BIO *pbioWrite; - ap_filter_t *pInputFilter; - ap_filter_t *pOutputFilter; - int nobuffer; /* non-zero to prevent buffering */ - SSLConnRec *config; -} ssl_filter_ctx_t; - -typedef struct { - ssl_filter_ctx_t *filter_ctx; - conn_rec *c; - apr_bucket_brigade *bb; - apr_size_t length; - char buffer[AP_IOBUFSIZE]; - apr_size_t blen; - apr_status_t rc; -} bio_filter_out_ctx_t; - -static bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx, - conn_rec *c) -{ - bio_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx)); - - outctx->filter_ctx = filter_ctx; - outctx->c = c; - outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); - outctx->blen = 0; - outctx->length = 0; - - return outctx; -} - -static int bio_filter_out_flush(BIO *bio) -{ - bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); - apr_bucket *e; - - if (!(outctx->blen || outctx->length)) { - outctx->rc = APR_SUCCESS; - return 1; - } - - if (outctx->blen) { - e = apr_bucket_transient_create(outctx->buffer, outctx->blen, - outctx->bb->bucket_alloc); - /* we filled this buffer first so add it to the - * head of the brigade - */ - APR_BRIGADE_INSERT_HEAD(outctx->bb, e); - outctx->blen = 0; - } - - outctx->length = 0; - e = apr_bucket_flush_create(outctx->bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(outctx->bb, e); - - outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next, - outctx->bb); - /* Fail if the connection was reset: */ - if (outctx->rc == APR_SUCCESS && outctx->c->aborted) { - outctx->rc = APR_ECONNRESET; - } - return (outctx->rc == APR_SUCCESS) ? 1 : -1; -} - -static int bio_filter_create(BIO *bio) -{ - bio->shutdown = 1; - bio->init = 1; - bio->num = -1; - bio->ptr = NULL; - - return 1; -} - -static int bio_filter_destroy(BIO *bio) -{ - if (bio == NULL) { - return 0; - } - - /* nothing to free here. - * apache will destroy the bucket brigade for us - */ - return 1; -} - -static int bio_filter_out_read(BIO *bio, char *out, int outl) -{ - /* this is never called */ - return -1; -} - -static int bio_filter_out_write(BIO *bio, const char *in, int inl) -{ - bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); - - /* Abort early if the client has initiated a renegotiation. */ - if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { - outctx->rc = APR_ECONNABORTED; - return -1; - } - - /* 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 (!outctx->length && (inl + outctx->blen < sizeof(outctx->buffer)) && - !outctx->filter_ctx->nobuffer) { - /* 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(&outctx->buffer[outctx->blen], in, inl); - outctx->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, - outctx->bb->bucket_alloc); - - outctx->length += inl; - APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket); - - if (bio_filter_out_flush(bio) < 0) { - return -1; - } - } - - return inl; -} - -static long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr) -{ - long ret = 1; - char **pptr; - - bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr); - - switch (cmd) { - case BIO_CTRL_RESET: - outctx->blen = outctx->length = 0; - break; - case BIO_CTRL_EOF: - ret = (long)((outctx->blen + outctx->length) == 0); - break; - case BIO_C_SET_BUF_MEM_EOF_RETURN: - outctx->blen = outctx->length = (apr_size_t)num; - break; - case BIO_CTRL_INFO: - ret = (long)(outctx->blen + outctx->length); - if (ptr) { - pptr = (char **)ptr; - *pptr = (char *)&(outctx->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)(outctx->blen + outctx->length); - break; - case BIO_CTRL_FLUSH: - ret = bio_filter_out_flush(bio); - 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_filter_out_gets(BIO *bio, char *buf, int size) -{ - /* this is never called */ - return -1; -} - -static int bio_filter_out_puts(BIO *bio, const char *str) -{ - /* this is never called */ - return -1; -} - -static BIO_METHOD bio_filter_out_method = { - BIO_TYPE_MEM, - "APR output filter", - bio_filter_out_write, - bio_filter_out_read, /* read is never called */ - bio_filter_out_puts, /* puts is never called */ - bio_filter_out_gets, /* gets is never called */ - bio_filter_out_ctrl, - bio_filter_create, - bio_filter_destroy, -#ifdef OPENSSL_VERSION_NUMBER - NULL /* sslc does not have the callback_ctrl field */ -#endif -}; - -typedef struct { - int length; - char *value; -} char_buffer_t; - -typedef struct { - SSL *ssl; - BIO *bio_out; - ap_filter_t *f; - apr_status_t rc; - ap_input_mode_t mode; - apr_read_type_e block; - apr_bucket_brigade *bb; - char_buffer_t cbuf; - apr_pool_t *pool; - char buffer[AP_IOBUFSIZE]; - ssl_filter_ctx_t *filter_ctx; -} bio_filter_in_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. - */ - -/* Copy up to INL bytes from the char_buffer BUFFER into IN. Note - * that due to the strange way this API is designed/used, the - * char_buffer object is used to cache a segment of inctx->buffer, and - * then this function called to copy (part of) that segment to the - * beginning of inctx->buffer. So the segments to copy cannot be - * presumed to be non-overlapping, and memmove must be used. */ -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 */ - memmove(in, buffer->value, inl); - buffer->value += inl; - buffer->length -= inl; - } - else { - /* swallow remainder of the buffer */ - memmove(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 function will read from a brigade and discard the read buckets as it - * proceeds. It will read at most *len bytes. - */ -static apr_status_t brigade_consume(apr_bucket_brigade *bb, - apr_read_type_e block, - char *c, apr_size_t *len) -{ - apr_size_t actual = 0; - apr_status_t status = APR_SUCCESS; - - while (!APR_BRIGADE_EMPTY(bb)) { - apr_bucket *b = APR_BRIGADE_FIRST(bb); - const char *str; - apr_size_t str_len; - apr_size_t consume; - - /* Justin points out this is an http-ism that might - * not fit if brigade_consume is added to APR. Perhaps - * apr_bucket_read(eos_bucket) should return APR_EOF? - * Then this becomes mainline instead of a one-off. - */ - if (APR_BUCKET_IS_EOS(b)) { - status = APR_EOF; - break; - } - - /* The reason I'm not offering brigade_consume yet - * across to apr-util is that the following call - * illustrates how borked that API really is. For - * this sort of case (caller provided buffer) it - * would be much more trivial for apr_bucket_consume - * to do all the work that follows, based on the - * particular characteristics of the bucket we are - * consuming here. - */ - status = apr_bucket_read(b, &str, &str_len, block); - - if (status != APR_SUCCESS) { - if (APR_STATUS_IS_EOF(status)) { - /* This stream bucket was consumed */ - apr_bucket_delete(b); - continue; - } - break; - } - - if (str_len > 0) { - /* Do not block once some data has been consumed */ - block = APR_NONBLOCK_READ; - - /* Assure we don't overflow. */ - consume = (str_len + actual > *len) ? *len - actual : str_len; - - memcpy(c, str, consume); - - c += consume; - actual += consume; - - if (consume >= b->length) { - /* This physical bucket was consumed */ - apr_bucket_delete(b); - } - else { - /* Only part of this physical bucket was consumed */ - b->start += consume; - b->length -= consume; - } - } - else if (b->length == 0) { - apr_bucket_delete(b); - } - - /* This could probably be actual == *len, but be safe from stray - * photons. */ - if (actual >= *len) { - break; - } - } - - *len = actual; - return status; -} - -/* - * this is the function called by SSL_read() - */ -static int bio_filter_in_read(BIO *bio, char *in, int inlen) -{ - apr_size_t inl = inlen; - bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr); - apr_read_type_e block = inctx->block; - SSLConnRec *sslconn = myConnConfig(inctx->f->c); - - inctx->rc = APR_SUCCESS; - - /* OpenSSL catches this case, so should we. */ - if (!in) - return 0; - - /* Abort early if the client has initiated a renegotiation. */ - if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { - inctx->rc = APR_ECONNABORTED; - return -1; - } - - /* XXX: flush here only required for SSLv2; - * OpenSSL calls BIO_flush() at the appropriate times for - * the other protocols. - */ - if ((SSL_version(inctx->ssl) == SSL2_VERSION) || sslconn->is_proxy) { - if (bio_filter_out_flush(inctx->bio_out) < 0) { - bio_filter_out_ctx_t *outctx = - (bio_filter_out_ctx_t *)(inctx->bio_out->ptr); - inctx->rc = outctx->rc; - return -1; - } - } - - BIO_clear_retry_flags(bio); - - if (!inctx->bb) { - inctx->rc = APR_EOF; - return -1; - } - - if (APR_BRIGADE_EMPTY(inctx->bb)) { - - inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb, - AP_MODE_READBYTES, block, - inl); - - /* Not a problem, there was simply no data ready yet. - */ - if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc) - || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) { - BIO_set_retry_read(bio); - return 0; - } - - if (inctx->rc != APR_SUCCESS) { - /* Unexpected errors discard the brigade */ - apr_brigade_cleanup(inctx->bb); - inctx->bb = NULL; - return -1; - } - } - - inctx->rc = brigade_consume(inctx->bb, block, in, &inl); - - if (inctx->rc == APR_SUCCESS) { - return (int)inl; - } - - if (APR_STATUS_IS_EAGAIN(inctx->rc) - || APR_STATUS_IS_EINTR(inctx->rc)) { - BIO_set_retry_read(bio); - return (int)inl; - } - - /* Unexpected errors and APR_EOF clean out the brigade. - * Subsequent calls will return APR_EOF. - */ - apr_brigade_cleanup(inctx->bb); - inctx->bb = NULL; - - if (APR_STATUS_IS_EOF(inctx->rc) && inl) { - /* Provide the results of this read pass, - * without resetting the BIO retry_read flag - */ - return (int)inl; - } - - return -1; -} - - -static BIO_METHOD bio_filter_in_method = { - BIO_TYPE_MEM, - "APR input filter", - NULL, /* write is never called */ - bio_filter_in_read, - NULL, /* puts is never called */ - NULL, /* gets is never called */ - NULL, /* ctrl is never called */ - bio_filter_create, - bio_filter_destroy, -#ifdef OPENSSL_VERSION_NUMBER - NULL /* sslc does not have the callback_ctrl field */ -#endif -}; - - -static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx, - char *buf, - apr_size_t *len) -{ - apr_size_t wanted = *len; - apr_size_t bytes = 0; - int rc; - - *len = 0; - - /* If we have something leftover from last time, try that first. */ - if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) { - *len = bytes; - if (inctx->mode == AP_MODE_SPECULATIVE) { - /* We want to rollback this read. */ - if (inctx->cbuf.length > 0) { - inctx->cbuf.value -= bytes; - inctx->cbuf.length += bytes; - } else { - char_buffer_write(&inctx->cbuf, buf, (int)bytes); - } - return APR_SUCCESS; - } - /* This could probably be *len == wanted, but be safe from stray - * photons. - */ - if (*len >= wanted) { - return APR_SUCCESS; - } - if (inctx->mode == AP_MODE_GETLINE) { - if (memchr(buf, APR_ASCII_LF, *len)) { - return APR_SUCCESS; - } - } - else { - /* Down to a nonblock pattern as we have some data already - */ - inctx->block = APR_NONBLOCK_READ; - } - } - - while (1) { - - if (!inctx->filter_ctx->pssl) { - /* Ensure a non-zero error code is returned */ - if (inctx->rc == APR_SUCCESS) { - inctx->rc = APR_EGENERAL; - } - break; - } - - /* SSL_read may not read because we haven't taken enough data - * from the stack. This is where we want to consider all of - * the blocking and SPECULATIVE semantics - */ - rc = SSL_read(inctx->filter_ctx->pssl, buf + bytes, wanted - bytes); - - if (rc > 0) { - *len += rc; - if (inctx->mode == AP_MODE_SPECULATIVE) { - /* We want to rollback this read. */ - char_buffer_write(&inctx->cbuf, buf, rc); - } - return inctx->rc; - } - else if (rc == 0) { - /* If EAGAIN, we will loop given a blocking read, - * otherwise consider ourselves at EOF. - */ - if (APR_STATUS_IS_EAGAIN(inctx->rc) - || APR_STATUS_IS_EINTR(inctx->rc)) { - /* Already read something, return APR_SUCCESS instead. - * On win32 in particular, but perhaps on other kernels, - * a blocking call isn't 'always' blocking. - */ - if (*len > 0) { - inctx->rc = APR_SUCCESS; - break; - } - if (inctx->block == APR_NONBLOCK_READ) { - break; - } - } - else { - if (*len > 0) { - inctx->rc = APR_SUCCESS; - } - else { - inctx->rc = APR_EOF; - } - break; - } - } - else /* (rc < 0) */ { - int ssl_err = SSL_get_error(inctx->filter_ctx->pssl, rc); - conn_rec *c = (conn_rec*)SSL_get_app_data(inctx->filter_ctx->pssl); - - if (ssl_err == SSL_ERROR_WANT_READ) { - /* - * If OpenSSL wants to read more, and we were nonblocking, - * report as an EAGAIN. Otherwise loop, pulling more - * data from network filter. - * - * (This is usually the case when the client forces an SSL - * renegotation which is handled implicitly by OpenSSL.) - */ - inctx->rc = APR_EAGAIN; - - if (*len > 0) { - inctx->rc = APR_SUCCESS; - break; - } - if (inctx->block == APR_NONBLOCK_READ) { - break; - } - continue; /* Blocking and nothing yet? Try again. */ - } - else if (ssl_err == SSL_ERROR_SYSCALL) { - if (APR_STATUS_IS_EAGAIN(inctx->rc) - || APR_STATUS_IS_EINTR(inctx->rc)) { - /* Already read something, return APR_SUCCESS instead. */ - if (*len > 0) { - inctx->rc = APR_SUCCESS; - break; - } - if (inctx->block == APR_NONBLOCK_READ) { - break; - } - continue; /* Blocking and nothing yet? Try again. */ - } - else { - ap_log_error(APLOG_MARK, APLOG_INFO, inctx->rc, c->base_server, - "SSL input filter read failed."); - } - } - else /* if (ssl_err == SSL_ERROR_SSL) */ { - /* - * Log SSL errors and any unexpected conditions. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, inctx->rc, c->base_server, - "SSL library error %d reading data", ssl_err); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - - } - if (inctx->rc == APR_SUCCESS) { - inctx->rc = APR_EGENERAL; - } - break; - } - } - return inctx->rc; -} - -static apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx, - 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(inctx, 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(&inctx->cbuf, value, length); - - *len = bytes; - } - - return APR_SUCCESS; -} - - -static apr_status_t ssl_filter_write(ap_filter_t *f, - const char *data, - apr_size_t len) -{ - ssl_filter_ctx_t *filter_ctx = f->ctx; - bio_filter_out_ctx_t *outctx; - int res; - - /* write SSL */ - if (filter_ctx->pssl == NULL) { - return APR_EGENERAL; - } - - outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr; - res = SSL_write(filter_ctx->pssl, (unsigned char *)data, len); - - if (res < 0) { - int ssl_err = SSL_get_error(filter_ctx->pssl, res); - conn_rec *c = (conn_rec*)SSL_get_app_data(outctx->filter_ctx->pssl); - - if (ssl_err == SSL_ERROR_WANT_WRITE) { - /* - * If OpenSSL wants to write more, and we were nonblocking, - * report as an EAGAIN. Otherwise loop, pushing more - * data at the network filter. - * - * (This is usually the case when the client forces an SSL - * renegotation which is handled implicitly by OpenSSL.) - */ - outctx->rc = APR_EAGAIN; - } - else if (ssl_err == SSL_ERROR_SYSCALL) { - ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, - "SSL output filter write failed."); - } - else /* if (ssl_err == SSL_ERROR_SSL) */ { - /* - * Log SSL errors - */ - ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, - "SSL library error %d writing data", ssl_err); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - } - if (outctx->rc == APR_SUCCESS) { - outctx->rc = APR_EGENERAL; - } - } - else if ((apr_size_t)res != len) { - conn_rec *c = f->c; - char *reason = "reason unknown"; - - /* XXX: probably a better way to determine this */ - if (SSL_total_renegotiations(filter_ctx->pssl)) { - reason = "likely due to failed renegotiation"; - } - - ap_log_error(APLOG_MARK, APLOG_INFO, outctx->rc, c->base_server, - "failed to write %d of %d bytes (%s)", - len - (apr_size_t)res, len, reason); - - outctx->rc = APR_EGENERAL; - } - return outctx->rc; -} - -/* Just use a simple request. Any request will work for this, because - * we use a flag in the conn_rec->conn_vector now. The fake request just - * gets the request back to the Apache core so that a response can be sent. - * - * To avoid calling back for more data from the socket, use an HTTP/0.9 - * request, and tack on an EOS bucket. - */ -#define HTTP_ON_HTTPS_PORT \ - "GET /" CRLF - -#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \ - apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \ - sizeof(HTTP_ON_HTTPS_PORT) - 1, \ - alloc) - -static void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f) -{ - bio_filter_in_ctx_t *inctx = f->ctx; - SSL_free(inctx->ssl); - sslconn->ssl = NULL; - inctx->ssl = NULL; - inctx->filter_ctx->pssl = NULL; -} - -static apr_status_t ssl_io_filter_error(ap_filter_t *f, - apr_bucket_brigade *bb, - apr_status_t status) -{ - SSLConnRec *sslconn = myConnConfig(f->c); - apr_bucket *bucket; - - switch (status) { - case HTTP_BAD_REQUEST: - /* log the situation */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - f->c->base_server, - "SSL handshake failed: HTTP spoken on HTTPS port; " - "trying to send HTML error page"); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server); - - sslconn->non_ssl_request = 1; - ssl_io_filter_disable(sslconn, f); - - /* fake the request line */ - bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); - break; - - default: - return status; - } - - APR_BRIGADE_INSERT_TAIL(bb, bucket); - bucket = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bucket); - - return APR_SUCCESS; -} - -static const char ssl_io_filter[] = "SSL/TLS Filter"; -static const char ssl_io_buffer[] = "SSL/TLS Buffer"; - -/* - * Close the SSL part of the socket connection - * (called immediately _before_ the socket is closed) - * or called with - */ -static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx, - conn_rec *c, - int abortive) -{ - SSL *ssl = filter_ctx->pssl; - const char *type = ""; - SSLConnRec *sslconn = myConnConfig(c); - int shutdown_type; - - if (!ssl) { - return APR_SUCCESS; - } - - /* - * Now close the SSL layer of the connection. We've to take - * the TLSv1 standard into account here: - * - * | 7.2.1. Closure alerts - * | - * | The client and the server must share knowledge that the connection is - * | ending in order to avoid a truncation attack. Either party may - * | initiate the exchange of closing messages. - * | - * | close_notify - * | This message notifies the recipient that the sender will not send - * | any more messages on this connection. The session becomes - * | unresumable if any connection is terminated without proper - * | close_notify messages with level equal to warning. - * | - * | Either party may initiate a close by sending a close_notify alert. - * | Any data received after a closure alert is ignored. - * | - * | Each party is required to send a close_notify alert before closing - * | the write side of the connection. It is required that the other party - * | respond with a close_notify alert of its own and close down the - * | connection immediately, discarding any pending writes. It is not - * | required for the initiator of the close to wait for the responding - * | close_notify alert before closing the read side of the connection. - * - * This means we've to send a close notify message, but haven't to wait - * for the close notify of the client. Actually we cannot wait for the - * close notify of the client because some clients (including Netscape - * 4.x) don't send one, so we would hang. - */ - - /* - * exchange close notify messages, but allow the user - * to force the type of handshake via SetEnvIf directive - */ - if (abortive) { - shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; - type = "abortive"; - } - else switch (sslconn->shutdown_type) { - case SSL_SHUTDOWN_TYPE_UNCLEAN: - /* perform no close notify handshake at all - (violates the SSL/TLS standard!) */ - shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN; - type = "unclean"; - break; - case SSL_SHUTDOWN_TYPE_ACCURATE: - /* send close notify and wait for clients close notify - (standard compliant, but usually causes connection hangs) */ - shutdown_type = 0; - type = "accurate"; - break; - default: - /* - * case SSL_SHUTDOWN_TYPE_UNSET: - * case SSL_SHUTDOWN_TYPE_STANDARD: - */ - /* send close notify, but don't wait for clients close notify - (standard compliant and safe, so it's the DEFAULT!) */ - shutdown_type = SSL_RECEIVED_SHUTDOWN; - type = "standard"; - break; - } - - SSL_set_shutdown(ssl, shutdown_type); - SSL_smart_shutdown(ssl); - - /* and finally log the fact that we've closed the connection */ - if (c->base_server->loglevel >= APLOG_INFO) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, - "Connection to child %ld closed with %s shutdown" - "(server %s, client %s)", - c->id, type, - ssl_util_vhostid(c->pool, c->base_server), - c->remote_ip ? c->remote_ip : "unknown"); - } - - /* deallocate the SSL connection */ - if (sslconn->client_cert) { - X509_free(sslconn->client_cert); - sslconn->client_cert = NULL; - } - SSL_free(ssl); - sslconn->ssl = NULL; - filter_ctx->pssl = NULL; /* so filters know we've been shutdown */ - - if (abortive) { - /* prevent any further I/O */ - c->aborted = 1; - } - - return APR_SUCCESS; -} - -static apr_status_t ssl_io_filter_cleanup(void *data) -{ - ssl_filter_ctx_t *filter_ctx = data; - - if (filter_ctx->pssl) { - conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); - SSLConnRec *sslconn = myConnConfig(c); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, - "SSL connection destroyed without being closed"); - - SSL_free(filter_ctx->pssl); - sslconn->ssl = filter_ctx->pssl = NULL; - } - - return APR_SUCCESS; -} - -/* - * The hook is NOT registered with ap_hook_process_connection. Instead, it is - * called manually from the churn () before it tries to read any data. - * There is some problem if I accept conn_rec *. Still investigating.. - * Adv. if conn_rec * can be accepted is we can hook this function using the - * ap_hook_process_connection hook. - */ -static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl); - SSLConnRec *sslconn = myConnConfig(c); - SSLSrvConfigRec *sc = mySrvConfig(c->base_server); - X509 *cert; - int n; - int ssl_err; - long verify_result; - - if (SSL_is_init_finished(filter_ctx->pssl)) { - return APR_SUCCESS; - } - - if (sslconn->is_proxy) { - if ((n = SSL_connect(filter_ctx->pssl)) <= 0) { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - c->base_server, - "SSL Proxy connect failed"); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - return ssl_filter_io_shutdown(filter_ctx, c, 1); - } - - return APR_SUCCESS; - } - - if ((n = SSL_accept(filter_ctx->pssl)) <= 0) { - bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *) - (filter_ctx->pbioRead->ptr); - bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *) - (filter_ctx->pbioWrite->ptr); - apr_status_t rc = inctx->rc ? inctx->rc : outctx->rc ; - ssl_err = SSL_get_error(filter_ctx->pssl, n); - - if (ssl_err == SSL_ERROR_ZERO_RETURN) { - /* - * The case where the connection was closed before any data - * was transferred. That's not a real error and can occur - * sporadically with some clients. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, rc, - c->base_server, - "SSL handshake stopped: connection was closed"); - } - else if (ssl_err == SSL_ERROR_WANT_READ) { - /* - * This is in addition to what was present earlier. It is - * borrowed from openssl_state_machine.c [mod_tls]. - * TBD. - */ - outctx->rc = APR_EAGAIN; - return SSL_ERROR_WANT_READ; - } - else if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL && - ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) { - /* - * The case where OpenSSL has recognized a HTTP request: - * This means the client speaks plain HTTP on our HTTPS port. - * ssl_io_filter_error will disable the ssl filters when it - * sees this status code. - */ - return HTTP_BAD_REQUEST; - } - else if (ssl_err == SSL_ERROR_SYSCALL) { - ap_log_error(APLOG_MARK, APLOG_INFO, rc, c->base_server, - "SSL handshake interrupted by system " - "[Hint: Stop button pressed in browser?!]"); - } - else /* if (ssl_err == SSL_ERROR_SSL) */ { - /* - * Log SSL errors and any unexpected conditions. - */ - ap_log_error(APLOG_MARK, APLOG_INFO, rc, c->base_server, - "SSL library error %d in handshake " - "(server %s, client %s)", ssl_err, - ssl_util_vhostid(c->pool, c->base_server), - c->remote_ip ? c->remote_ip : "unknown"); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - - } - if (inctx->rc == APR_SUCCESS) { - inctx->rc = APR_EGENERAL; - } - - return ssl_filter_io_shutdown(filter_ctx, c, 1); - } - - /* - * Check for failed client authentication - */ - verify_result = SSL_get_verify_result(filter_ctx->pssl); - - if ((verify_result != X509_V_OK) || - sslconn->verify_error) - { - if (ssl_verify_error_is_optional(verify_result) && - (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA)) - { - /* leaving this log message as an error for the moment, - * according to the mod_ssl docs: - * "level optional_no_ca is actually against the idea - * of authentication (but can be used to establish - * SSL test pages, etc.)" - * optional_no_ca doesn't appear to work as advertised - * in 1.x - */ - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - c->base_server, - "SSL client authentication failed, " - "accepting certificate based on " - "\"SSLVerifyClient optional_no_ca\" " - "configuration"); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - } - else { - const char *error = sslconn->verify_error ? - sslconn->verify_error : - X509_verify_cert_error_string(verify_result); - - ap_log_error(APLOG_MARK, APLOG_INFO, 0, - c->base_server, - "SSL client authentication failed: %s", - error ? error : "unknown"); - ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server); - - return ssl_filter_io_shutdown(filter_ctx, c, 1); - } - } - - /* - * Remember the peer certificate's DN - */ - if ((cert = SSL_get_peer_certificate(filter_ctx->pssl))) { - if (sslconn->client_cert) { - X509_free(sslconn->client_cert); - } - sslconn->client_cert = cert; - sslconn->client_dn = NULL; - } - - /* - * Make really sure that when a peer certificate - * is required we really got one... (be paranoid) - */ - if ((sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE) && - !sslconn->client_cert) - { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, c->base_server, - "No acceptable peer certificate available"); - - return ssl_filter_io_shutdown(filter_ctx, c, 1); - } - - 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; - bio_filter_in_ctx_t *inctx = f->ctx; - - apr_size_t len = sizeof(inctx->buffer); - int is_init = (mode == AP_MODE_INIT); - - if (f->c->aborted) { - /* XXX: Ok, if we aborted, we ARE at the EOS. We also have - * aborted. This 'double protection' is probably redundant, - * but also effective against just about anything. - */ - apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bucket); - return APR_ECONNABORTED; - } - - if (!inctx->ssl) { - return ap_get_brigade(f->next, bb, mode, block, readbytes); - } - - /* 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; - } - - inctx->mode = mode; - inctx->block = block; - - /* XXX: we could actually move ssl_io_filter_connect 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. - */ - if ((status = ssl_io_filter_connect(inctx->filter_ctx)) != 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 (inctx->mode == AP_MODE_READBYTES || - inctx->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(inctx, inctx->buffer, &len); - } - else if (inctx->mode == AP_MODE_GETLINE) { - status = ssl_io_input_getline(inctx, inctx->buffer, &len); - } - else { - /* We have no idea what you are talking about, so return an error. */ - status = APR_ENOTIMPL; - } - - /* It is possible for mod_ssl's BIO to be used outside of the - * direct control of mod_ssl's input or output filter -- notably, - * when mod_ssl initiates a renegotiation. Switching the BIO mode - * back to "blocking" here ensures such operations don't fail with - * SSL_ERROR_WANT_READ. */ - inctx->block = APR_BLOCK_READ; - - /* Handle custom errors. */ - if (status != APR_SUCCESS) { - return ssl_io_filter_error(f, bb, status); - } - - /* Create a transient bucket out of the decrypted data. */ - if (len > 0) { - apr_bucket *bucket = - apr_bucket_transient_create(inctx->buffer, len, f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, bucket); - } - - 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; - ssl_filter_ctx_t *filter_ctx = f->ctx; - bio_filter_in_ctx_t *inctx; - bio_filter_out_ctx_t *outctx; - apr_read_type_e rblock = APR_NONBLOCK_READ; - - if (f->c->aborted) { - apr_brigade_cleanup(bb); - return APR_ECONNABORTED; - } - - if (!filter_ctx->pssl) { - /* ssl_filter_io_shutdown was called */ - return ap_pass_brigade(f->next, bb); - } - - inctx = (bio_filter_in_ctx_t *)filter_ctx->pbioRead->ptr; - outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr; - - /* When we are the writer, we must initialize the inctx - * mode so that we block for any required ssl input, because - * output filtering is always nonblocking. - */ - inctx->mode = AP_MODE_READBYTES; - inctx->block = APR_BLOCK_READ; - - if ((status = ssl_io_filter_connect(filter_ctx)) != APR_SUCCESS) { - return ssl_io_filter_error(f, bb, status); - } - - 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)) { - if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) { - status = outctx->rc; - break; - } - - 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_filter_out_flush() already passed down a flush bucket - * if there was any data to be flushed. - */ - apr_bucket_delete(bucket); - } - } - else if (AP_BUCKET_IS_EOC(bucket)) { - /* The special "EOC" bucket means a shutdown is needed; - * - turn off buffering in bio_filter_out_write - * - issue the SSL_shutdown - */ - filter_ctx->nobuffer = 1; - status = ssl_filter_io_shutdown(filter_ctx, f->c, 0); - if (status != APR_SUCCESS) { - ap_log_error(APLOG_MARK, APLOG_INFO, status, NULL, - "SSL filter error shutting down I/O"); - } - if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) { - return status; - } - break; - } - else { - /* filter output */ - const char *data; - apr_size_t len; - - status = apr_bucket_read(bucket, &data, &len, rblock); - - if (APR_STATUS_IS_EAGAIN(status)) { - /* No data available: flush... */ - if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) { - status = outctx->rc; - break; - } - rblock = APR_BLOCK_READ; - continue; /* and try again with a blocking read. */ - } - - rblock = APR_NONBLOCK_READ; - - if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) { - break; - } - - status = ssl_filter_write(f, data, len); - apr_bucket_delete(bucket); - - if (status != APR_SUCCESS) { - break; - } - } - } - - return status; -} - -/* 128K maximum buffer size by default. */ -#ifndef SSL_MAX_IO_BUFFER -#define SSL_MAX_IO_BUFFER (128 * 1024) -#endif - -struct modssl_buffer_ctx { - apr_bucket_brigade *bb; - apr_pool_t *pool; -}; - -int ssl_io_buffer_fill(request_rec *r) -{ - conn_rec *c = r->connection; - struct modssl_buffer_ctx *ctx; - apr_bucket_brigade *tempb; - apr_off_t total = 0; /* total length buffered */ - int eos = 0; /* non-zero once EOS is seen */ - - /* Create the context which will be passed to the input filter; - * containing a setaside pool and a brigade which constrain the - * lifetime of the buffered data. */ - ctx = apr_palloc(r->pool, sizeof *ctx); - apr_pool_create(&ctx->pool, r->pool); - ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc); - - /* ... and a temporary brigade. */ - tempb = apr_brigade_create(r->pool, c->bucket_alloc); - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "filling buffer"); - - do { - apr_status_t rv; - apr_bucket *e, *next; - - /* The request body is read from the protocol-level input - * filters; the buffering filter will reinject it from that - * level, allowing content/resource filters to run later, if - * necessary. */ - - rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES, - APR_BLOCK_READ, 8192); - if (rv) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "could not read request body for SSL buffer"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* Iterate through the returned brigade: setaside each bucket - * into the context's pool and move it into the brigade. */ - for (e = APR_BRIGADE_FIRST(tempb); - e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) { - const char *data; - apr_size_t len; - - next = APR_BUCKET_NEXT(e); - - if (APR_BUCKET_IS_EOS(e)) { - eos = 1; - } else if (!APR_BUCKET_IS_METADATA(e)) { - rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "could not read bucket for SSL buffer"); - return HTTP_INTERNAL_SERVER_ERROR; - } - total += len; - } - - rv = apr_bucket_setaside(e, ctx->pool); - if (rv != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, - "could not setaside bucket for SSL buffer"); - return HTTP_INTERNAL_SERVER_ERROR; - } - - APR_BUCKET_REMOVE(e); - APR_BRIGADE_INSERT_TAIL(ctx->bb, e); - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, - "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d", - total, eos); - - /* Fail if this exceeds the maximum buffer size. */ - if (total > SSL_MAX_IO_BUFFER) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "request body exceeds maximum size for SSL buffer"); - return HTTP_REQUEST_ENTITY_TOO_LARGE; - } - - } while (!eos); - - apr_brigade_destroy(tempb); - - /* Insert the filter which will supply the buffered data. */ - ap_add_input_filter(ssl_io_buffer, ctx, r, c); - - return 0; -} - -/* This input filter supplies the buffered request body to the caller - * from the brigade stored in f->ctx. */ -static apr_status_t ssl_io_filter_buffer(ap_filter_t *f, - apr_bucket_brigade *bb, - ap_input_mode_t mode, - apr_read_type_e block, - apr_off_t bytes) -{ - struct modssl_buffer_ctx *ctx = f->ctx; - apr_status_t rv; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, - "read from buffered SSL brigade, mode %d, " - "%" APR_OFF_T_FMT " bytes", - mode, bytes); - - if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { - return APR_ENOTIMPL; - } - - if (mode == AP_MODE_READBYTES) { - apr_bucket *e; - - /* Partition the buffered brigade. */ - rv = apr_brigade_partition(ctx->bb, bytes, &e); - if (rv && rv != APR_INCOMPLETE) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "could not partition buffered SSL brigade"); - ap_remove_input_filter(f); - return rv; - } - - /* If the buffered brigade contains less then the requested - * length, just pass it all back. */ - if (rv == APR_INCOMPLETE) { - APR_BRIGADE_CONCAT(bb, ctx->bb); - } else { - apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb); - - e = APR_BUCKET_PREV(e); - - /* Unsplice the partitioned segment and move it into the - * passed-in brigade; no convenient way to do this with - * the APR_BRIGADE_* macros. */ - APR_RING_UNSPLICE(d, e, link); - APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link); - - APR_BRIGADE_CHECK_CONSISTENCY(bb); - APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb); - } - } - else { - /* Split a line into the passed-in brigade. */ - rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes); - - if (rv) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r, - "could not split line from buffered SSL brigade"); - ap_remove_input_filter(f); - return rv; - } - } - - if (APR_BRIGADE_EMPTY(ctx->bb)) { - apr_bucket *e = APR_BRIGADE_LAST(bb); - - /* Ensure that the brigade is terminated by an EOS if the - * buffered request body has been entirely consumed. */ - if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) { - e = apr_bucket_eos_create(f->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bb, e); - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, f->r, - "buffered SSL brigade now exhausted; removing filter"); - ap_remove_input_filter(f); - } - - return APR_SUCCESS; -} - -static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, - SSL *ssl) -{ - bio_filter_in_ctx_t *inctx; - - inctx = apr_palloc(c->pool, sizeof(*inctx)); - - filter_ctx->pInputFilter = ap_add_input_filter(ssl_io_filter, inctx, NULL, c); - - filter_ctx->pbioRead = BIO_new(&bio_filter_in_method); - filter_ctx->pbioRead->ptr = (void *)inctx; - - inctx->ssl = ssl; - inctx->bio_out = filter_ctx->pbioWrite; - inctx->f = filter_ctx->pInputFilter; - inctx->rc = APR_SUCCESS; - inctx->mode = AP_MODE_READBYTES; - inctx->cbuf.length = 0; - inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc); - inctx->block = APR_BLOCK_READ; - inctx->pool = c->pool; - inctx->filter_ctx = filter_ctx; -} - -void ssl_io_filter_init(conn_rec *c, SSL *ssl) -{ - ssl_filter_ctx_t *filter_ctx; - - filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t)); - - filter_ctx->config = myConnConfig(c); - - filter_ctx->nobuffer = 0; - filter_ctx->pOutputFilter = ap_add_output_filter(ssl_io_filter, - filter_ctx, NULL, c); - - filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); - filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); - - ssl_io_input_add_filter(filter_ctx, c, ssl); - - SSL_set_bio(ssl, filter_ctx->pbioRead, filter_ctx->pbioWrite); - filter_ctx->pssl = ssl; - - apr_pool_cleanup_register(c->pool, (void*)filter_ctx, - ssl_io_filter_cleanup, apr_pool_cleanup_null); - - if (c->base_server->loglevel >= APLOG_DEBUG) { - BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb); - BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl); - } - - return; -} - -void ssl_io_filter_register(apr_pool_t *p) -{ - ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5); - ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5); - - ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1); - - return; -} - -/* _________________________________________________________________ -** -** I/O Data Debugging -** _________________________________________________________________ -*/ - -#define DUMP_WIDTH 16 - -static void ssl_io_data_dump(server_rec *srvr, - MODSSL_BIO_CB_ARG_TYPE *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++; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, - "+-------------------------------------------------------------------------+"); - 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)); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, - "%s", buf); - } - if (trunc > 0) - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, - "| %04ld - ", len + trunc); - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, srvr, - "+-------------------------------------------------------------------------+"); - return; -} - -long ssl_io_data_cb(BIO *bio, int cmd, - MODSSL_BIO_CB_ARG_TYPE *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) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: %s %ld/%d bytes %s BIO#%pp [mem: %pp] %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)" : "(Oops, no memory buffer?)")); - if (argp != NULL) - ssl_io_data_dump(s, argp, rc); - } - else { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "%s: I/O error, %d bytes expected to %s on BIO#%pp [mem: %pp]", - SSL_LIBRARY_NAME, argi, - (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"), - bio, argp); - } - } - return rc; -} -- cgit 1.2.3-korg