summaryrefslogtreecommitdiffstats
path: root/rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c
diff options
context:
space:
mode:
authorhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
committerhongbotian <hongbo.tianhongbo@huawei.com>2015-11-30 03:10:21 -0500
commitc0b7206652b2852bc574694e7ba07ba1c2acdc00 (patch)
tree5cb95cb0e19e03610525903df46279df2c3b7eb1 /rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c
parentb6d3d6e668b793220f2d3af1bc3e828553dc3fe6 (diff)
delete app
Change-Id: Id4c572809969ebe89e946e88063eaed262cff3f2 Signed-off-by: hongbotian <hongbo.tianhongbo@huawei.com>
Diffstat (limited to 'rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c')
-rw-r--r--rubbos/app/httpd-2.0.64/modules/ssl/ssl_engine_io.c1746
1 files changed, 0 insertions, 1746 deletions
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 - <SPACES/NULS>", 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;
-}