ssl_engine_io.c revision b76a31daaa6e83bb0fd627a04f20e82bffcf1df4
842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * http://www.apache.org/licenses/LICENSE-2.0
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Unless required by applicable law or agreed to in writing, software
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distributed under the License is distributed on an "AS IS" BASIS,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * See the License for the specific language governing permissions and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * limitations under the License.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* _ _
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * _ __ ___ ___ __| | ___ ___| | mod_ssl
e8f95a682820a599fe41b22977010636be5c2717jim * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | | | | | | (_) | (_| | \__ \__ \ |
e8f95a682820a599fe41b22977010636be5c2717jim * |_| |_| |_|\___/ \__,_|___|___/___/_|
1747d30b98aa1bdbc43994c02cd46ab4cb9319e4fielding * |_____|
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ssl_engine_io.c
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * I/O Functions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ``MY HACK: This universe.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes Just one little problem:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes core keeps dumping.''
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes -- Unknown */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "ssl_private.h"
11f2c481e1d57bedb3f758565307501e9a2730ddtrawick#include "apr_date.h"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* _________________________________________________________________
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes**
5c0419d51818eb02045cf923a9fe456127a44c60wrowe** I/O Hooks
5c0419d51818eb02045cf923a9fe456127a44c60wrowe** _________________________________________________________________
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* This file is designed to be the bridge between OpenSSL and httpd.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * However, we really don't expect anyone (let alone ourselves) to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * remember what is in this file. So, first, a quick overview.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * In this file, you will find:
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * - ssl_io_filter_input (Apache input filter)
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * - ssl_io_filter_output (Apache output filter)
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes *
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * - bio_filter_in_* (OpenSSL input filter)
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * - bio_filter_out_* (OpenSSL output filter)
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes *
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes * The input chain is roughly:
22f8da8087791fcb95b836c8a81937c5a9bba202bnicholes *
cd3bbd6d2df78d6c75e5d159a81ef8bdd5f70df9trawick * ssl_io_filter_input->ssl_io_input_read->SSL_read->...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter
0f60998368b493f90120180a93fc2e1e74490872covener *
0f60998368b493f90120180a93fc2e1e74490872covener * In mortal terminology, we do the following:
0f60998368b493f90120180a93fc2e1e74490872covener * - Receive a request for data to the SSL input filter
0f60998368b493f90120180a93fc2e1e74490872covener * - Call a helper function once we know we should perform a read
0f60998368b493f90120180a93fc2e1e74490872covener * - Call OpenSSL's SSL_read()
0f60998368b493f90120180a93fc2e1e74490872covener * - SSL_read() will then call bio_filter_in_read
0f60998368b493f90120180a93fc2e1e74490872covener * - bio_filter_in_read will then try to fetch data from the next httpd filter
0f60998368b493f90120180a93fc2e1e74490872covener * - bio_filter_in_read will flatten that data and return it to SSL_read
87587593f1a53030e840acc0dec6cc881022ea40covener * - SSL_read will then decrypt the data
87587593f1a53030e840acc0dec6cc881022ea40covener * - ssl_io_input_read will then receive decrypted data as a char* and
87587593f1a53030e840acc0dec6cc881022ea40covener * ensure that there were no read errors
87587593f1a53030e840acc0dec6cc881022ea40covener * - The char* is placed in a brigade and returned
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
43997561b2302d13dee973998e77743a3ddd2374trawick * Since connection-level input filters in httpd need to be able to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings),
0568280364eb026393be492ebc732795c4934643jorton * ssl_io_input_getline which will handle this special case.
0568280364eb026393be492ebc732795c4934643jorton *
0568280364eb026393be492ebc732795c4934643jorton * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have
0568280364eb026393be492ebc732795c4934643jorton * 'leftover' decoded data which must be setaside for the next read. That
0568280364eb026393be492ebc732795c4934643jorton * is currently handled by the char_buffer_{read|write} functions. So,
0568280364eb026393be492ebc732795c4934643jorton * ssl_io_input_read may be able to fulfill reads without invoking
0568280364eb026393be492ebc732795c4934643jorton * SSL_read().
0568280364eb026393be492ebc732795c4934643jorton *
0568280364eb026393be492ebc732795c4934643jorton * Note that the filter context of ssl_io_filter_input and bio_filter_in_*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * are shared as bio_filter_in_ctx_t.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener *
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * Note that the filter is by choice limited to reading at most
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AP_IOBUFSIZE (8192 bytes) per call.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* this custom BIO allows us to hook SSL_write directly into
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * an apr_bucket_brigade and use transient buckets with the SSL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * malloc-ed buffer, rather than copying into a mem BIO.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * also allows us to pass the brigade as data is being written
796e4a7141265d8ed7036e4628161c6eafb2a789jorton * rather than buffering up the entire response in the mem BIO.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush()
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * which will trigger a call to bio_filter_out_ctrl() -> bio_filter_out_flush().
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * so we only need to flush the output ourselves if we receive an
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * EOS or FLUSH bucket. this was not possible with the mem BIO where we
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * had to flush all over the place not really knowing when it was required
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to do so.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSL *pssl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO *pbioRead;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO *pbioWrite;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_filter_t *pInputFilter;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_filter_t *pOutputFilter;
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe int nobuffer; /* non-zero to prevent buffering */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSLConnRec *config;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe} ssl_filter_ctx_t;
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowetypedef struct {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_filter_ctx_t *filter_ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn_rec *c;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_bucket_brigade *bb; /* Brigade used as a buffer. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t length; /* Number of bytes stored in ->bb brigade. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char buffer[AP_IOBUFSIZE]; /* Fixed-size buffer */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t blen; /* Number of bytes of ->buffer used. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_status_t rc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} bio_filter_out_ctx_t;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
a1790fb35c4b352dab721370985c623a9f8f5062rpluemstatic bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx,
713a2b68bac4aeb1e9c48785006c0732451039depquerna conn_rec *c)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->filter_ctx = filter_ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->c = c;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe outctx->blen = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->length = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return outctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int bio_filter_out_flush(BIO *bio)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener apr_bucket *e;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!(outctx->blen || outctx->length)) {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes outctx->rc = APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (outctx->blen) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes e = apr_bucket_transient_create(outctx->buffer, outctx->blen,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->bb->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we filled this buffer first so add it to the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * head of the brigade
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_HEAD(outctx->bb, e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->blen = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->length = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes e = apr_bucket_flush_create(outctx->bb->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_TAIL(outctx->bb, e);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->bb);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* Fail if the connection was reset: */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (outctx->rc == APR_SUCCESS && outctx->c->aborted) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->rc = APR_ECONNRESET;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (outctx->rc == APR_SUCCESS) ? 1 : -1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int bio_filter_create(BIO *bio)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio->shutdown = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio->init = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio->num = -1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener bio->ptr = NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int bio_filter_destroy(BIO *bio)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (bio == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* nothing to free here.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * apache will destroy the bucket brigade for us
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int bio_filter_out_read(BIO *bio, char *out, int outl)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
1f299703465bd9975d94e9f229f76af807442de2covener /* this is never called */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return -1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int bio_filter_out_write(BIO *bio, const char *in, int inl)
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Abort early if the client has initiated a renegotiation. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj outctx->rc = APR_ECONNABORTED;
9ad7b260be233be7d7b5576979825cac72e15498rederpj return -1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes /* when handshaking we'll have a small number of bytes.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * max size SSL will pass us here is about 16k.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (16413 bytes to be exact)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO_clear_retry_flags(bio);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!outctx->length && (inl + outctx->blen < sizeof(outctx->buffer)) &&
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes !outctx->filter_ctx->nobuffer) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* the first two SSL_writes (of 1024 and 261 bytes)
3e6d7277b90d3011db832139afc20efb5f17e203rederpj * need to be in the same packet (vec[0].iov_base)
3e6d7277b90d3011db832139afc20efb5f17e203rederpj */
3e6d7277b90d3011db832139afc20efb5f17e203rederpj /* XXX: could use apr_brigade_write() to make code look cleaner
3e6d7277b90d3011db832139afc20efb5f17e203rederpj * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and free() of it later
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes */
e8f95a682820a599fe41b22977010636be5c2717jim memcpy(&outctx->buffer[outctx->blen], in, inl);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->blen += inl;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener else {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* pass along the encrypted data
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * need to flush since we're using SSL's malloc-ed buffer
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * which will be overwritten once we leave here
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener apr_bucket *bucket = apr_bucket_transient_create(in, inl,
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->bb->bucket_alloc);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->length += inl;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (bio_filter_out_flush(bio) < 0) {
6683642c1e0032eeeed5f99e8c14880692ef84c5sf return -1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
6683642c1e0032eeeed5f99e8c14880692ef84c5sf return inl;
6683642c1e0032eeeed5f99e8c14880692ef84c5sf}
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovenerstatic long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener long ret = 1;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener char **pptr;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener switch (cmd) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_RESET:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->blen = outctx->length = 0;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_EOF:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ret = (long)((outctx->blen + outctx->length) == 0);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_C_SET_BUF_MEM_EOF_RETURN:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener outctx->blen = outctx->length = (apr_size_t)num;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case BIO_CTRL_INFO:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ret = (long)(outctx->blen + outctx->length);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (ptr) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener pptr = (char **)ptr;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener *pptr = (char *)&(outctx->buffer[0]);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_GET_CLOSE:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ret = (long)bio->shutdown;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_SET_CLOSE:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener bio->shutdown = (int)num;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_PENDING:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* _PENDING is interpreted as "pending to read" - since this
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * is a *write* buffer, return zero. */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener ret = 0L;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener break;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener case BIO_CTRL_WPENDING:
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener /* _WPENDING is interpreted as "pending to write" - return the
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * number of bytes in ->bb plus buffer. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ret = (long)(outctx->blen + outctx->length);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case BIO_CTRL_FLUSH:
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes ret = bio_filter_out_flush(bio);
0e05808dc59a321566303084c84b9826a4353cefrederpj break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case BIO_CTRL_DUP:
b08925593f214f621161742925dcf074a8047e0acovener ret = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* N/A */
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj case BIO_C_SET_BUF_MEM:
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf case BIO_C_GET_BUF_MEM_PTR:
465bb68501690d7a47bfd2a6129580047d76d8f1rederpj /* we don't care */
e8f95a682820a599fe41b22977010636be5c2717jim case BIO_CTRL_PUSH:
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes case BIO_CTRL_POP:
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes default:
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ret = 0;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes break;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return ret;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
ebe5305f8b22507374358f32b74d12fb50c05a25covenerstatic int bio_filter_out_gets(BIO *bio, char *buf, int size)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* this is never called */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return -1;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
513b324e774c559b579896df131fd7c8471ed529rederpjstatic int bio_filter_out_puts(BIO *bio, const char *str)
513b324e774c559b579896df131fd7c8471ed529rederpj{
513b324e774c559b579896df131fd7c8471ed529rederpj /* this is never called */
513b324e774c559b579896df131fd7c8471ed529rederpj return -1;
513b324e774c559b579896df131fd7c8471ed529rederpj}
513b324e774c559b579896df131fd7c8471ed529rederpj
513b324e774c559b579896df131fd7c8471ed529rederpjstatic BIO_METHOD bio_filter_out_method = {
513b324e774c559b579896df131fd7c8471ed529rederpj BIO_TYPE_MEM,
513b324e774c559b579896df131fd7c8471ed529rederpj "APR output filter",
513b324e774c559b579896df131fd7c8471ed529rederpj bio_filter_out_write,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes bio_filter_out_read, /* read is never called */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_puts, /* puts is never called */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_gets, /* gets is never called */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_ctrl,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_create,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes bio_filter_destroy,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes#ifdef OPENSSL_VERSION_NUMBER
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes NULL /* sslc does not have the callback_ctrl field */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes#endif
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes};
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholestypedef struct {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes int length;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes char *value;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes} char_buffer_t;
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpjtypedef struct {
9ad7b260be233be7d7b5576979825cac72e15498rederpj SSL *ssl;
9ad7b260be233be7d7b5576979825cac72e15498rederpj BIO *bio_out;
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_filter_t *f;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_status_t rc;
9ad7b260be233be7d7b5576979825cac72e15498rederpj ap_input_mode_t mode;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_read_type_e block;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_bucket_brigade *bb;
9ad7b260be233be7d7b5576979825cac72e15498rederpj char_buffer_t cbuf;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_pool_t *pool;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes char buffer[AP_IOBUFSIZE];
54d22ed1c429b903b029bbd62621f11a9e286137minfrin ssl_filter_ctx_t *filter_ctx;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes} bio_filter_in_ctx_t;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
ebe5305f8b22507374358f32b74d12fb50c05a25covener/*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * this char_buffer api might seem silly, but we don't need to copy
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * any of this data and we need to remember the length.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes/* Copy up to INL bytes from the char_buffer BUFFER into IN. Note
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * that due to the strange way this API is designed/used, the
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * char_buffer object is used to cache a segment of inctx->buffer, and
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * then this function called to copy (part of) that segment to the
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * beginning of inctx->buffer. So the segments to copy cannot be
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * presumed to be non-overlapping, and memmove must be used. */
ebe5305f8b22507374358f32b74d12fb50c05a25covenerstatic int char_buffer_read(char_buffer_t *buffer, char *in, int inl)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes{
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!buffer->length) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return 0;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (buffer->length > inl) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* we have have enough to fill the caller's buffer */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes memmove(in, buffer->value, inl);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes buffer->value += inl;
b08925593f214f621161742925dcf074a8047e0acovener buffer->length -= inl;
b08925593f214f621161742925dcf074a8047e0acovener }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* swallow remainder of the buffer */
9ad7b260be233be7d7b5576979825cac72e15498rederpj memmove(in, buffer->value, buffer->length);
9ad7b260be233be7d7b5576979825cac72e15498rederpj inl = buffer->length;
128a5d93141a86e3afa151e921035a07297c9833rederpj buffer->value = NULL;
9ad7b260be233be7d7b5576979825cac72e15498rederpj buffer->length = 0;
9ad7b260be233be7d7b5576979825cac72e15498rederpj }
128a5d93141a86e3afa151e921035a07297c9833rederpj
128a5d93141a86e3afa151e921035a07297c9833rederpj return inl;
9ad7b260be233be7d7b5576979825cac72e15498rederpj}
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpjstatic int char_buffer_write(char_buffer_t *buffer, char *in, int inl)
9ad7b260be233be7d7b5576979825cac72e15498rederpj{
128a5d93141a86e3afa151e921035a07297c9833rederpj buffer->value = in;
9ad7b260be233be7d7b5576979825cac72e15498rederpj buffer->length = inl;
9ad7b260be233be7d7b5576979825cac72e15498rederpj return inl;
9ab21648975dff7e1b680daf8aea627227ba28f7trawick}
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj/* This function will read from a brigade and discard the read buckets as it
9ad7b260be233be7d7b5576979825cac72e15498rederpj * proceeds. It will read at most *len bytes.
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
87587593f1a53030e840acc0dec6cc881022ea40covenerstatic apr_status_t brigade_consume(apr_bucket_brigade *bb,
87587593f1a53030e840acc0dec6cc881022ea40covener apr_read_type_e block,
9ad7b260be233be7d7b5576979825cac72e15498rederpj char *c, apr_size_t *len)
9ad7b260be233be7d7b5576979825cac72e15498rederpj{
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_size_t actual = 0;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_status_t status = APR_SUCCESS;
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj while (!APR_BRIGADE_EMPTY(bb)) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_bucket *b = APR_BRIGADE_FIRST(bb);
9ad7b260be233be7d7b5576979825cac72e15498rederpj const char *str;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_size_t str_len;
9ad7b260be233be7d7b5576979825cac72e15498rederpj apr_size_t consume;
9ad7b260be233be7d7b5576979825cac72e15498rederpj
9ad7b260be233be7d7b5576979825cac72e15498rederpj /* Justin points out this is an http-ism that might
9ad7b260be233be7d7b5576979825cac72e15498rederpj * not fit if brigade_consume is added to APR. Perhaps
9ab21648975dff7e1b680daf8aea627227ba28f7trawick * apr_bucket_read(eos_bucket) should return APR_EOF?
9ad7b260be233be7d7b5576979825cac72e15498rederpj * Then this becomes mainline instead of a one-off.
9ad7b260be233be7d7b5576979825cac72e15498rederpj */
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (APR_BUCKET_IS_EOS(b)) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj status = APR_EOF;
9ad7b260be233be7d7b5576979825cac72e15498rederpj break;
7add8f7fb048534390571801b7794f71cd9e127abnicholes }
7add8f7fb048534390571801b7794f71cd9e127abnicholes
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* The reason I'm not offering brigade_consume yet
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * across to apr-util is that the following call
7add8f7fb048534390571801b7794f71cd9e127abnicholes * illustrates how borked that API really is. For
7add8f7fb048534390571801b7794f71cd9e127abnicholes * this sort of case (caller provided buffer) it
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * would be much more trivial for apr_bucket_consume
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * to do all the work that follows, based on the
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * particular characteristics of the bucket we are
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * consuming here.
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes status = apr_bucket_read(b, &str, &str_len, block);
7add8f7fb048534390571801b7794f71cd9e127abnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (status != APR_SUCCESS) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (APR_STATUS_IS_EOF(status)) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* This stream bucket was consumed */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_bucket_delete(b);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes continue;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes break;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (str_len > 0) {
7add8f7fb048534390571801b7794f71cd9e127abnicholes /* Do not block once some data has been consumed */
7add8f7fb048534390571801b7794f71cd9e127abnicholes block = APR_NONBLOCK_READ;
141e1368614dc7564e1627671361b01b4869b491bnicholes
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes /* Assure we don't overflow. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes consume = (str_len + actual > *len) ? *len - actual : str_len;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes memcpy(c, str, consume);
e8f95a682820a599fe41b22977010636be5c2717jim
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes c += consume;
ebe5305f8b22507374358f32b74d12fb50c05a25covener actual += consume;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (consume >= b->length) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* This physical bucket was consumed */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_bucket_delete(b);
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes else {
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes /* Only part of this physical bucket was consumed */
3dfeb02cfb853d8717ca0cc259b59fea610173f5bnicholes b->start += consume;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf b->length -= consume;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf else if (b->length == 0) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_bucket_delete(b);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* This could probably be actual == *len, but be safe from stray
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * photons. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (actual >= *len) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf break;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf *len = actual;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return status;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf}
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf/*
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * this is the function called by SSL_read()
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes */
e8f95a682820a599fe41b22977010636be5c2717jimstatic int bio_filter_in_read(BIO *bio, char *in, int inlen)
7dbf29be626018bc389ef94c1846aeac4b72633bsf{
7dbf29be626018bc389ef94c1846aeac4b72633bsf apr_size_t inl = inlen;
7dbf29be626018bc389ef94c1846aeac4b72633bsf bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)(bio->ptr);
7dbf29be626018bc389ef94c1846aeac4b72633bsf apr_read_type_e block = inctx->block;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf inctx->rc = APR_SUCCESS;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* OpenSSL catches this case, so should we. */
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (!in)
7dbf29be626018bc389ef94c1846aeac4b72633bsf return 0;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* Abort early if the client has initiated a renegotiation. */
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf inctx->rc = APR_ECONNABORTED;
7dbf29be626018bc389ef94c1846aeac4b72633bsf return -1;
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* In theory, OpenSSL should flush as necessary, but it is known
7dbf29be626018bc389ef94c1846aeac4b72633bsf * not to do so correctly in some cases; see PR 46952.
7dbf29be626018bc389ef94c1846aeac4b72633bsf *
7dbf29be626018bc389ef94c1846aeac4b72633bsf * Historically, this flush call was performed only for an SSLv2
7dbf29be626018bc389ef94c1846aeac4b72633bsf * connection or for a proxy connection. Calling _out_flush
7dbf29be626018bc389ef94c1846aeac4b72633bsf * should be very cheap in cases where it is unnecessary (and no
7dbf29be626018bc389ef94c1846aeac4b72633bsf * output is buffered) so the performance impact of doing it
7dbf29be626018bc389ef94c1846aeac4b72633bsf * unconditionally should be minimal.
7dbf29be626018bc389ef94c1846aeac4b72633bsf */
7dbf29be626018bc389ef94c1846aeac4b72633bsf if (bio_filter_out_flush(inctx->bio_out) < 0) {
7dbf29be626018bc389ef94c1846aeac4b72633bsf bio_filter_out_ctx_t *outctx = inctx->bio_out->ptr;
7dbf29be626018bc389ef94c1846aeac4b72633bsf inctx->rc = outctx->rc;
7dbf29be626018bc389ef94c1846aeac4b72633bsf return -1;
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf BIO_clear_retry_flags(bio);
7dbf29be626018bc389ef94c1846aeac4b72633bsf
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (!inctx->bb) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes inctx->rc = APR_EOF;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return -1;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (APR_BRIGADE_EMPTY(inctx->bb)) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes inctx->rc = ap_get_brigade(inctx->f->next, inctx->bb,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes AP_MODE_READBYTES, block,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes inl);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* If the read returns EAGAIN or success with an empty
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * brigade, return an error after setting the retry flag;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * SSL_read() will then return -1, and SSL_get_error() will
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes * indicate SSL_ERROR_WANT_READ. */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (APR_STATUS_IS_EAGAIN(inctx->rc) || APR_STATUS_IS_EINTR(inctx->rc)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes || (inctx->rc == APR_SUCCESS && APR_BRIGADE_EMPTY(inctx->bb))) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes BIO_set_retry_read(bio);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return -1;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (inctx->rc != APR_SUCCESS) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* Unexpected errors discard the brigade */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes apr_brigade_cleanup(inctx->bb);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes inctx->bb = NULL;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return -1;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes inctx->rc = brigade_consume(inctx->bb, block, in, &inl);
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (inctx->rc == APR_SUCCESS) {
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes return (int)inl;
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes }
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes if (APR_STATUS_IS_EAGAIN(inctx->rc)
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes || APR_STATUS_IS_EINTR(inctx->rc)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO_set_retry_read(bio);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (int)inl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Unexpected errors and APR_EOF clean out the brigade.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * Subsequent calls will return APR_EOF.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_brigade_cleanup(inctx->bb);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf inctx->bb = NULL;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (APR_STATUS_IS_EOF(inctx->rc) && inl) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* Provide the results of this read pass,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * without resetting the BIO retry_read flag
e8f95a682820a599fe41b22977010636be5c2717jim */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return (int)inl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return -1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsfstatic BIO_METHOD bio_filter_in_method = {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf BIO_TYPE_MEM,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "APR input filter",
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf NULL, /* write is never called */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf bio_filter_in_read,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf NULL, /* puts is never called */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf NULL, /* gets is never called */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf NULL, /* ctrl is never called */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf bio_filter_create,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes bio_filter_destroy,
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes#ifdef OPENSSL_VERSION_NUMBER
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes NULL /* sslc does not have the callback_ctrl field */
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes#endif
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes};
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sfstatic apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf char *buf,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf apr_size_t *len)
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t wanted = *len;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t bytes = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int rc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
54d22ed1c429b903b029bbd62621f11a9e286137minfrin *len = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d330a801b1e5d63a4b8b4fd431542ad0903fd71bbnicholes /* If we have something leftover from last time, try that first. */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if ((bytes = char_buffer_read(&inctx->cbuf, buf, wanted))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *len = bytes;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->mode == AP_MODE_SPECULATIVE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* We want to rollback this read. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->cbuf.length > 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->cbuf.value -= bytes;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->cbuf.length += bytes;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin } else {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin char_buffer_write(&inctx->cbuf, buf, (int)bytes);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return APR_SUCCESS;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* This could probably be *len == wanted, but be safe from stray
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * photons.
54d22ed1c429b903b029bbd62621f11a9e286137minfrin */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (*len >= wanted) {
e8f95a682820a599fe41b22977010636be5c2717jim return APR_SUCCESS;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
8a03cd420b800a2428f49f4617293de9b2387b20jorton if (inctx->mode == AP_MODE_GETLINE) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (memchr(buf, APR_ASCII_LF, *len)) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin return APR_SUCCESS;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin else {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Down to a nonblock pattern as we have some data already
54d22ed1c429b903b029bbd62621f11a9e286137minfrin */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin inctx->block = APR_NONBLOCK_READ;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin }
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin while (1) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (!inctx->filter_ctx->pssl) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin /* Ensure a non-zero error code is returned */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (inctx->rc == APR_SUCCESS) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin inctx->rc = APR_EGENERAL;
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener }
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener break;
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener }
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener /* SSL_read may not read because we haven't taken enough data
6999a76d8eb5ef6b4b295e51df0b2fb6064bd373covener * from the stack. This is where we want to consider all of
54d22ed1c429b903b029bbd62621f11a9e286137minfrin * the blocking and SPECULATIVE semantics
54d22ed1c429b903b029bbd62621f11a9e286137minfrin */
54d22ed1c429b903b029bbd62621f11a9e286137minfrin rc = SSL_read(inctx->filter_ctx->pssl, buf + bytes, wanted - bytes);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (rc > 0) {
54d22ed1c429b903b029bbd62621f11a9e286137minfrin *len += rc;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin if (inctx->mode == AP_MODE_SPECULATIVE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* We want to rollback this read. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char_buffer_write(&inctx->cbuf, buf, rc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return inctx->rc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (rc == 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If EAGAIN, we will loop given a blocking read,
e8f95a682820a599fe41b22977010636be5c2717jim * otherwise consider ourselves at EOF.
e8f95a682820a599fe41b22977010636be5c2717jim */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (APR_STATUS_IS_EAGAIN(inctx->rc)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes || APR_STATUS_IS_EINTR(inctx->rc)) {
e8f95a682820a599fe41b22977010636be5c2717jim /* Already read something, return APR_SUCCESS instead.
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * On win32 in particular, but perhaps on other kernels,
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * a blocking call isn't 'always' blocking.
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe */
f0f6f1b90ab582896f8a7d56d85bd62a55e57d90covener if (*len > 0) {
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe inctx->rc = APR_SUCCESS;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin break;
560fd0658902ab57754616c172d8953e69fc4722bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->block == APR_NONBLOCK_READ) {
e8f95a682820a599fe41b22977010636be5c2717jim break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
9ad7b260be233be7d7b5576979825cac72e15498rederpj else {
9ad7b260be233be7d7b5576979825cac72e15498rederpj if (*len > 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->rc = APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->rc = APR_EOF;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
560fd0658902ab57754616c172d8953e69fc4722bnicholes }
560fd0658902ab57754616c172d8953e69fc4722bnicholes }
560fd0658902ab57754616c172d8953e69fc4722bnicholes else /* (rc < 0) */ {
560fd0658902ab57754616c172d8953e69fc4722bnicholes int ssl_err = SSL_get_error(inctx->filter_ctx->pssl, rc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn_rec *c = (conn_rec*)SSL_get_app_data(inctx->filter_ctx->pssl);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ssl_err == SSL_ERROR_WANT_READ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If OpenSSL wants to read more, and we were nonblocking,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * report as an EAGAIN. Otherwise loop, pulling more
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * data from network filter.
e8f95a682820a599fe41b22977010636be5c2717jim *
e8f95a682820a599fe41b22977010636be5c2717jim * (This is usually the case when the client forces an SSL
e8f95a682820a599fe41b22977010636be5c2717jim * renegotiation which is handled implicitly by OpenSSL.)
e8f95a682820a599fe41b22977010636be5c2717jim */
e8f95a682820a599fe41b22977010636be5c2717jim inctx->rc = APR_EAGAIN;
e8f95a682820a599fe41b22977010636be5c2717jim
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener if (*len > 0) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe inctx->rc = APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->block == APR_NONBLOCK_READ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes continue; /* Blocking and nothing yet? Try again. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (ssl_err == SSL_ERROR_SYSCALL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APR_STATUS_IS_EAGAIN(inctx->rc)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes || APR_STATUS_IS_EINTR(inctx->rc)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Already read something, return APR_SUCCESS instead. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*len > 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->rc = APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->block == APR_NONBLOCK_READ) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes continue; /* Blocking and nothing yet? Try again. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,
560fd0658902ab57754616c172d8953e69fc4722bnicholes "SSL input filter read failed.");
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else /* if (ssl_err == SSL_ERROR_SSL) */ {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Log SSL errors and any unexpected conditions.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL library error %d reading data", ssl_err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, mySrvFromConn(c));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (inctx->rc == APR_SUCCESS) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->rc = APR_EGENERAL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return inctx->rc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Read a line of input from the SSL input layer into buffer BUF of
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * length *LEN; updating *len to reflect the length of the line
0e05808dc59a321566303084c84b9826a4353cefrederpj * including the LF character. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ssl_io_input_getline(bio_filter_in_ctx_t *inctx,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *buf,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t *len)
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener{
0e05808dc59a321566303084c84b9826a4353cefrederpj const char *pos = NULL;
ebe5305f8b22507374358f32b74d12fb50c05a25covener apr_status_t status;
ebe5305f8b22507374358f32b74d12fb50c05a25covener apr_size_t tmplen = *len, buflen = *len, offset = 0;
ebe5305f8b22507374358f32b74d12fb50c05a25covener
ebe5305f8b22507374358f32b74d12fb50c05a25covener *len = 0;
ebe5305f8b22507374358f32b74d12fb50c05a25covener
ebe5305f8b22507374358f32b74d12fb50c05a25covener /*
ebe5305f8b22507374358f32b74d12fb50c05a25covener * in most cases we get all the headers on the first SSL_read.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * however, in certain cases SSL_read will only get a partial
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener * chunk of the headers, so we try to read until LF is seen.
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener */
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener while (tmplen > 0) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener status = ssl_io_input_read(inctx, buf + offset, &tmplen);
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if (status != APR_SUCCESS) {
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return status;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener }
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener
0e05808dc59a321566303084c84b9826a4353cefrederpj *len += tmplen;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener if ((pos = memchr(buf, APR_ASCII_LF, *len))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener offset += tmplen;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes tmplen = buflen - offset;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (pos) {
9ad7b260be233be7d7b5576979825cac72e15498rederpj char *value;
9ad7b260be233be7d7b5576979825cac72e15498rederpj int length;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin apr_size_t bytes = pos - buf;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin bytes += 1;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin value = buf + bytes;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin length = *len - bytes;
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
560fd0658902ab57754616c172d8953e69fc4722bnicholes char_buffer_write(&inctx->cbuf, value, length);
54d22ed1c429b903b029bbd62621f11a9e286137minfrin
54d22ed1c429b903b029bbd62621f11a9e286137minfrin *len = bytes;
ae1981fc94adf2b231e2d0e15d2f895b2138c969covener }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener return APR_SUCCESS;
4e9c24785b525d2956e6e381015c0f2bd0a72f4bcovener}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ssl_filter_write(ap_filter_t *f,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *data,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_size_t len)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_filter_ctx_t *filter_ctx = f->ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_out_ctx_t *outctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int res;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* write SSL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (filter_ctx->pssl == NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return APR_EGENERAL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes res = SSL_write(filter_ctx->pssl, (unsigned char *)data, len);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (res < 0) {
e8f95a682820a599fe41b22977010636be5c2717jim int ssl_err = SSL_get_error(filter_ctx->pssl, res);
e8f95a682820a599fe41b22977010636be5c2717jim conn_rec *c = (conn_rec*)SSL_get_app_data(outctx->filter_ctx->pssl);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (ssl_err == SSL_ERROR_WANT_WRITE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If OpenSSL wants to write more, and we were nonblocking,
e8f95a682820a599fe41b22977010636be5c2717jim * report as an EAGAIN. Otherwise loop, pushing more
e8f95a682820a599fe41b22977010636be5c2717jim * data at the network filter.
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (This is usually the case when the client forces an SSL
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * renegotiation which is handled implicitly by OpenSSL.)
e8f95a682820a599fe41b22977010636be5c2717jim */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->rc = APR_EAGAIN;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (ssl_err == SSL_ERROR_SYSCALL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL output filter write failed.");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else /* if (ssl_err == SSL_ERROR_SSL) */ {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /*
e8f95a682820a599fe41b22977010636be5c2717jim * Log SSL errors
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL library error %d writing data", ssl_err);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, mySrvFromConn(c));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (outctx->rc == APR_SUCCESS) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->rc = APR_EGENERAL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if ((apr_size_t)res != len) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn_rec *c = f->c;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *reason = "reason unknown";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX: probably a better way to determine this */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (SSL_total_renegotiations(filter_ctx->pssl)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes reason = "likely due to failed renegotiation";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "failed to write %" APR_SSIZE_T_FMT
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes " of %" APR_SIZE_T_FMT " bytes (%s)",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes len - (apr_size_t)res, len, reason);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes outctx->rc = APR_EGENERAL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return outctx->rc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim/* Just use a simple request. Any request will work for this, because
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * we use a flag in the conn_rec->conn_vector now. The fake request just
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * gets the request back to the Apache core so that a response can be sent.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * To avoid calling back for more data from the socket, use an HTTP/0.9
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * request, and tack on an EOS bucket.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define HTTP_ON_HTTPS_PORT \
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "GET /" CRLF
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \
e8f95a682820a599fe41b22977010636be5c2717jim apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sizeof(HTTP_ON_HTTPS_PORT) - 1, \
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes alloc)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Custom apr_status_t error code, used when a plain HTTP request is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * recevied on an SSL port. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define MODSSL_ERROR_HTTP_ON_HTTPS (APR_OS_START_USERERR + 0)
43c3e6a4b559b76b750c245ee95e2782c15b4296jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Custom apr_status_t error code, used when the proxy cannot
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * establish an outgoing SSL connection. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define MODSSL_ERROR_BAD_GATEWAY (APR_OS_START_USERERR + 1)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholesstatic void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f)
43c3e6a4b559b76b750c245ee95e2782c15b4296jim{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_in_ctx_t *inctx = f->ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSL_free(inctx->ssl);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sslconn->ssl = NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->ssl = NULL;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener inctx->filter_ctx->pssl = NULL;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener}
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
37af4b0cf648275b68ff41c866c665b4ccf4667dcovenerstatic apr_status_t ssl_io_filter_error(ap_filter_t *f,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_bucket_brigade *bb,
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_status_t status)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe{
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes SSLConnRec *sslconn = myConnConfig(f->c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_bucket *bucket;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf switch (status) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf case MODSSL_ERROR_HTTP_ON_HTTPS:
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /* log the situation */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "SSL handshake failed: HTTP spoken on HTTPS port; "
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf "trying to send HTML error page");
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, sslconn->server);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf sslconn->non_ssl_request = 1;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ssl_io_filter_disable(sslconn, f);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* fake the request line */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case MODSSL_ERROR_BAD_GATEWAY:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bucket = ap_bucket_error_create(HTTP_BAD_REQUEST, NULL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes f->c->pool,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes f->c->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL handshake failed: sending 502");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes default:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return status;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_TAIL(bb, bucket);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bucket = apr_bucket_eos_create(f->c->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_TAIL(bb, bucket);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim return APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
e8f95a682820a599fe41b22977010636be5c2717jimstatic const char ssl_io_filter[] = "SSL/TLS Filter";
e8f95a682820a599fe41b22977010636be5c2717jimstatic const char ssl_io_buffer[] = "SSL/TLS Buffer";
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Close the SSL part of the socket connection
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (called immediately _before_ the socket is closed)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * or called with
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn_rec *c, int abortive)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSL *ssl = filter_ctx->pssl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *type = "";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSLConnRec *sslconn = myConnConfig(c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int shutdown_type;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int loglevel = APLOG_DEBUG;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim if (!ssl) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Now close the SSL layer of the connection. We've to take
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * the TLSv1 standard into account here:
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe *
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * | 7.2.1. Closure alerts
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * |
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | The client and the server must share knowledge that the connection is
e8f95a682820a599fe41b22977010636be5c2717jim * | ending in order to avoid a truncation attack. Either party may
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | initiate the exchange of closing messages.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * |
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | close_notify
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | This message notifies the recipient that the sender will not send
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | any more messages on this connection. The session becomes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | unresumable if any connection is terminated without proper
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * | close_notify messages with level equal to warning.
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * |
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * | Either party may initiate a close by sending a close_notify alert.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | Any data received after a closure alert is ignored.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * |
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | Each party is required to send a close_notify alert before closing
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | the write side of the connection. It is required that the other party
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | respond with a close_notify alert of its own and close down the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | connection immediately, discarding any pending writes. It is not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | required for the initiator of the close to wait for the responding
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * | close_notify alert before closing the read side of the connection.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This means we've to send a close notify message, but haven't to wait
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for the close notify of the client. Actually we cannot wait for the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * close notify of the client because some clients (including Netscape
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 4.x) don't send one, so we would hang.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * exchange close notify messages, but allow the user
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to force the type of handshake via SetEnvIf directive
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (abortive) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
e8f95a682820a599fe41b22977010636be5c2717jim type = "abortive";
e8f95a682820a599fe41b22977010636be5c2717jim loglevel = APLOG_INFO;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe }
e8f95a682820a599fe41b22977010636be5c2717jim else switch (sslconn->shutdown_type) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case SSL_SHUTDOWN_TYPE_UNCLEAN:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* perform no close notify handshake at all
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (violates the SSL/TLS standard!) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes type = "unclean";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes case SSL_SHUTDOWN_TYPE_ACCURATE:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send close notify and wait for clients close notify
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (standard compliant, but usually causes connection hangs) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes shutdown_type = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes type = "accurate";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes default:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * case SSL_SHUTDOWN_TYPE_UNSET:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * case SSL_SHUTDOWN_TYPE_STANDARD:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* send close notify, but don't wait for clients close notify
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (standard compliant and safe, so it's the DEFAULT!) */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes shutdown_type = SSL_RECEIVED_SHUTDOWN;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj type = "standard";
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj break;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj SSL_set_shutdown(ssl, shutdown_type);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj SSL_smart_shutdown(ssl);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* and finally log the fact that we've closed the connection */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APLOG_CS_IS_LEVEL(c, mySrvFromConn(c), loglevel)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cserror(APLOG_MARK, loglevel, 0, c, mySrvFromConn(c),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Connection closed to child %ld with %s shutdown "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "(server %s)",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes c->id, type,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_util_vhostid(c->pool, mySrvFromConn(c)));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* deallocate the SSL connection */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (sslconn->client_cert) {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes X509_free(sslconn->client_cert);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sslconn->client_cert = NULL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSL_free(ssl);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sslconn->ssl = NULL;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener filter_ctx->pssl = NULL; /* so filters know we've been shutdown */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener if (abortive) {
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener /* prevent any further I/O */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener c->aborted = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ssl_io_filter_cleanup(void *data)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf ssl_filter_ctx_t *filter_ctx = data;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf if (filter_ctx->pssl) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf SSLConnRec *sslconn = myConnConfig(c);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf SSL_free(filter_ctx->pssl);
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf sslconn->ssl = filter_ctx->pssl = NULL;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return APR_SUCCESS;
e8f95a682820a599fe41b22977010636be5c2717jim}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/*
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The hook is NOT registered with ap_hook_process_connection. Instead, it is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * called manually from the churn () before it tries to read any data.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * There is some problem if I accept conn_rec *. Still investigating..
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Adv. if conn_rec * can be accepted is we can hook this function using the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ap_hook_process_connection hook.
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Perform the SSL handshake (whether in client or server mode), if
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * necessary, for the given connection. */
e8f95a682820a599fe41b22977010636be5c2717jimstatic apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe{
e8f95a682820a599fe41b22977010636be5c2717jim conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl);
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe SSLConnRec *sslconn = myConnConfig(c);
e8f95a682820a599fe41b22977010636be5c2717jim SSLSrvConfigRec *sc;
e8f95a682820a599fe41b22977010636be5c2717jim X509 *cert;
e8f95a682820a599fe41b22977010636be5c2717jim int n;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe int ssl_err;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe long verify_result;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj server_rec *server;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (SSL_is_init_finished(filter_ctx->pssl)) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return APR_SUCCESS;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem server = sslconn->server;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (sslconn->is_proxy) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj const char *hostname_note;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes sc = mySrvConfig(server);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((n = SSL_connect(filter_ctx->pssl)) <= 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL Proxy connect failed");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* ensure that the SSL structures etc are freed, etc: */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_filter_io_shutdown(filter_ctx, c, 1);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return MODSSL_ERROR_BAD_GATEWAY;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (sc->proxy_ssl_check_peer_expire != SSL_ENABLED_FALSE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes cert = SSL_get_peer_certificate(filter_ctx->pssl);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!cert
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes || (X509_cmp_current_time(
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes X509_get_notBefore(cert)) >= 0)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes || (X509_cmp_current_time(
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes X509_get_notAfter(cert)) <= 0)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "SSL Proxy: Peer certificate is expired");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (cert) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes X509_free(cert);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ensure that the SSL structures etc are freed, etc: */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ssl_filter_io_shutdown(filter_ctx, c, 1);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return HTTP_BAD_GATEWAY;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem X509_free(cert);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((sc->proxy_ssl_check_peer_cn != SSL_ENABLED_FALSE)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem && ((hostname_note =
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_table_get(c->notes, "proxy-request-hostname")) != NULL)) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *hostname;
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj hostname = ssl_var_lookup(NULL, server, c, NULL,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "SSL_CLIENT_S_DN_CN");
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_table_unset(c->notes, "proxy-request-hostname");
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (strcasecmp(hostname, hostname_note)) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "SSL Proxy: Peer certificate CN mismatch:"
8869662bb1a4078297020e94ae5e928626d877c6rederpj " Certificate CN: %s Requested hostname: %s",
8869662bb1a4078297020e94ae5e928626d877c6rederpj hostname, hostname_note);
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* ensure that the SSL structures etc are freed, etc: */
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_filter_io_shutdown(filter_ctx, c, 1);
8869662bb1a4078297020e94ae5e928626d877c6rederpj return HTTP_BAD_GATEWAY;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8869662bb1a4078297020e94ae5e928626d877c6rederpj return APR_SUCCESS;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((n = SSL_accept(filter_ctx->pssl)) <= 0) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj bio_filter_in_ctx_t *inctx = (bio_filter_in_ctx_t *)
8869662bb1a4078297020e94ae5e928626d877c6rederpj (filter_ctx->pbioRead->ptr);
8869662bb1a4078297020e94ae5e928626d877c6rederpj bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)
8869662bb1a4078297020e94ae5e928626d877c6rederpj (filter_ctx->pbioWrite->ptr);
8869662bb1a4078297020e94ae5e928626d877c6rederpj apr_status_t rc = inctx->rc ? inctx->rc : outctx->rc ;
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_err = SSL_get_error(filter_ctx->pssl, n);
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (ssl_err == SSL_ERROR_ZERO_RETURN) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /*
8869662bb1a4078297020e94ae5e928626d877c6rederpj * The case where the connection was closed before any data
6733d943c9e8d0f27dd077a04037e8c49eb090ffcovener * was transferred. That's not a real error and can occur
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * sporadically with some clients.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "SSL handshake stopped: connection was closed");
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf else if (ssl_err == SSL_ERROR_WANT_READ) {
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf /*
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * This is in addition to what was present earlier. It is
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * borrowed from openssl_state_machine.c [mod_tls].
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf * TBD.
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf */
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf outctx->rc = APR_EAGAIN;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return APR_EAGAIN;
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf }
8869662bb1a4078297020e94ae5e928626d877c6rederpj else if (ERR_GET_LIB(ERR_peek_error()) == ERR_LIB_SSL &&
8869662bb1a4078297020e94ae5e928626d877c6rederpj ERR_GET_REASON(ERR_peek_error()) == SSL_R_HTTP_REQUEST) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /*
8869662bb1a4078297020e94ae5e928626d877c6rederpj * The case where OpenSSL has recognized a HTTP request:
8869662bb1a4078297020e94ae5e928626d877c6rederpj * This means the client speaks plain HTTP on our HTTPS port.
8869662bb1a4078297020e94ae5e928626d877c6rederpj * ssl_io_filter_error will disable the ssl filters when it
8869662bb1a4078297020e94ae5e928626d877c6rederpj * sees this status code.
8869662bb1a4078297020e94ae5e928626d877c6rederpj */
8869662bb1a4078297020e94ae5e928626d877c6rederpj return MODSSL_ERROR_HTTP_ON_HTTPS;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj else if (ssl_err == SSL_ERROR_SYSCALL) {
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rc, c,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "SSL handshake interrupted by system "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "[Hint: Stop button pressed in browser?!]");
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj else /* if (ssl_err == SSL_ERROR_SSL) */ {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /*
8869662bb1a4078297020e94ae5e928626d877c6rederpj * Log SSL errors and any unexpected conditions.
8869662bb1a4078297020e94ae5e928626d877c6rederpj */
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "SSL library error %d in handshake "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "(server %s)", ssl_err,
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_util_vhostid(c->pool, server));
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server);
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (inctx->rc == APR_SUCCESS) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx->rc = APR_EGENERAL;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_filter_io_shutdown(filter_ctx, c, 1);
8869662bb1a4078297020e94ae5e928626d877c6rederpj return inctx->rc;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem sc = mySrvConfig(sslconn->server);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /*
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Check for failed client authentication
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem verify_result = SSL_get_verify_result(filter_ctx->pssl);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8869662bb1a4078297020e94ae5e928626d877c6rederpj if ((verify_result != X509_V_OK) ||
8869662bb1a4078297020e94ae5e928626d877c6rederpj sslconn->verify_error)
8869662bb1a4078297020e94ae5e928626d877c6rederpj {
8869662bb1a4078297020e94ae5e928626d877c6rederpj if (ssl_verify_error_is_optional(verify_result) &&
8869662bb1a4078297020e94ae5e928626d877c6rederpj (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
8869662bb1a4078297020e94ae5e928626d877c6rederpj {
8869662bb1a4078297020e94ae5e928626d877c6rederpj /* leaving this log message as an error for the moment,
8869662bb1a4078297020e94ae5e928626d877c6rederpj * according to the mod_ssl docs:
8869662bb1a4078297020e94ae5e928626d877c6rederpj * "level optional_no_ca is actually against the idea
8869662bb1a4078297020e94ae5e928626d877c6rederpj * of authentication (but can be used to establish
8869662bb1a4078297020e94ae5e928626d877c6rederpj * SSL test pages, etc.)"
8869662bb1a4078297020e94ae5e928626d877c6rederpj * optional_no_ca doesn't appear to work as advertised
8869662bb1a4078297020e94ae5e928626d877c6rederpj * in 1.x
8869662bb1a4078297020e94ae5e928626d877c6rederpj */
8869662bb1a4078297020e94ae5e928626d877c6rederpj ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "SSL client authentication failed, "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "accepting certificate based on "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "\"SSLVerifyClient optional_no_ca\" "
8869662bb1a4078297020e94ae5e928626d877c6rederpj "configuration");
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server);
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj else {
8869662bb1a4078297020e94ae5e928626d877c6rederpj const char *error = sslconn->verify_error ?
8869662bb1a4078297020e94ae5e928626d877c6rederpj sslconn->verify_error :
8869662bb1a4078297020e94ae5e928626d877c6rederpj X509_verify_cert_error_string(verify_result);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
8869662bb1a4078297020e94ae5e928626d877c6rederpj "SSL client authentication failed: %s",
8869662bb1a4078297020e94ae5e928626d877c6rederpj error ? error : "unknown");
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server);
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj ssl_filter_io_shutdown(filter_ctx, c, 1);
8869662bb1a4078297020e94ae5e928626d877c6rederpj return APR_ECONNABORTED;
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj }
8869662bb1a4078297020e94ae5e928626d877c6rederpj
8869662bb1a4078297020e94ae5e928626d877c6rederpj /*
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj * Remember the peer certificate's DN
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((cert = SSL_get_peer_certificate(filter_ctx->pssl))) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (sslconn->client_cert) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem X509_free(sslconn->client_cert);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem sslconn->client_cert = cert;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj sslconn->client_dn = NULL;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /*
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * Make really sure that when a peer certificate
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * is required we really got one... (be paranoid)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE) &&
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem !sslconn->client_cert)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "No acceptable peer certificate available");
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ssl_filter_io_shutdown(filter_ctx, c, 1);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return APR_ECONNABORTED;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return APR_SUCCESS;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem}
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluemstatic apr_status_t ssl_io_filter_input(ap_filter_t *f,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_bucket_brigade *bb,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ap_input_mode_t mode,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_read_type_e block,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_off_t readbytes)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem{
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_status_t status;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem bio_filter_in_ctx_t *inctx = f->ctx;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem const char *start = inctx->buffer; /* start of block to return */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_size_t len = sizeof(inctx->buffer); /* length of block to return */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem int is_init = (mode == AP_MODE_INIT);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (f->c->aborted) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* XXX: Ok, if we aborted, we ARE at the EOS. We also have
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * aborted. This 'double protection' is probably redundant,
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj * but also effective against just about anything.
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_bucket *bucket = apr_bucket_eos_create(f->c->bucket_alloc);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem APR_BRIGADE_INSERT_TAIL(bb, bucket);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return APR_ECONNABORTED;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj if (!inctx->ssl) {
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj return ap_get_brigade(f->next, bb, mode, block, readbytes);
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj }
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj /* XXX: we don't currently support anything other than these modes. */
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE &&
0e05808dc59a321566303084c84b9826a4353cefrederpj mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) {
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg return APR_ENOTIMPL;
a9c4332dc6241dc11dd104826bd179d42ccc0f12fuankg }
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj inctx->mode = mode;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj inctx->block = block;
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* XXX: we could actually move ssl_io_filter_handshake to an
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * ap_hook_process_connection but would still need to call it for
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * AP_MODE_INIT for protocols that may upgrade the connection
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * rather than have SSLEngine On configured.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if ((status = ssl_io_filter_handshake(inctx->filter_ctx)) != APR_SUCCESS) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return ssl_io_filter_error(f, bb, status);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
11ca38a20ab9b2d00258f745620e2724838e7e21rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (is_init) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* protocol module needs to handshake before sending
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * data to client (e.g. NNTP or FTP)
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return APR_SUCCESS;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (inctx->mode == AP_MODE_READBYTES ||
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx->mode == AP_MODE_SPECULATIVE) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Protected from truncation, readbytes < MAX_SIZE_T
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * FIXME: No, it's *not* protected. -- jre */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (readbytes < len) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj len = (apr_size_t)readbytes;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj status = ssl_io_input_read(inctx, inctx->buffer, &len);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj else if (inctx->mode == AP_MODE_GETLINE) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj const char *pos;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Satisfy the read directly out of the buffer if possible;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * invoking ssl_io_input_getline will mean the entire buffer
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj * is copied once (unnecessarily) for each GETLINE call. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem if (inctx->cbuf.length
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem && (pos = memchr(inctx->cbuf.value, APR_ASCII_LF,
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx->cbuf.length)) != NULL) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem start = inctx->cbuf.value;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj len = 1 + pos - start; /* +1 to include LF */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Buffer contents now consumed. */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj inctx->cbuf.value += len;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj inctx->cbuf.length -= len;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj status = APR_SUCCESS;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj else {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* Otherwise fall back to the hard way. */
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj status = ssl_io_input_getline(inctx, inctx->buffer, &len);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj else {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* We have no idea what you are talking about, so return an error. */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj status = APR_ENOTIMPL;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* It is possible for mod_ssl's BIO to be used outside of the
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * direct control of mod_ssl's input or output filter -- notably,
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * when mod_ssl initiates a renegotiation. Switching the BIO mode
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * back to "blocking" here ensures such operations don't fail with
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * SSL_ERROR_WANT_READ. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx->block = APR_BLOCK_READ;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Handle custom errors. */
0e05808dc59a321566303084c84b9826a4353cefrederpj if (status != APR_SUCCESS) {
0e05808dc59a321566303084c84b9826a4353cefrederpj return ssl_io_filter_error(f, bb, status);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj /* Create a transient bucket out of the decrypted data. */
0e05808dc59a321566303084c84b9826a4353cefrederpj if (len > 0) {
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_bucket *bucket =
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_bucket_transient_create(start, len, f->c->bucket_alloc);
0e05808dc59a321566303084c84b9826a4353cefrederpj APR_BRIGADE_INSERT_TAIL(bb, bucket);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj return APR_SUCCESS;
0e05808dc59a321566303084c84b9826a4353cefrederpj}
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpjstatic apr_status_t ssl_io_filter_output(ap_filter_t *f,
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_bucket_brigade *bb)
0e05808dc59a321566303084c84b9826a4353cefrederpj{
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_status_t status = APR_SUCCESS;
0e05808dc59a321566303084c84b9826a4353cefrederpj ssl_filter_ctx_t *filter_ctx = f->ctx;
0e05808dc59a321566303084c84b9826a4353cefrederpj bio_filter_in_ctx_t *inctx;
0e05808dc59a321566303084c84b9826a4353cefrederpj bio_filter_out_ctx_t *outctx;
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_read_type_e rblock = APR_NONBLOCK_READ;
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (f->c->aborted) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_brigade_cleanup(bb);
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj return APR_ECONNABORTED;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (!filter_ctx->pssl) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* ssl_filter_io_shutdown was called */
0e05808dc59a321566303084c84b9826a4353cefrederpj return ap_pass_brigade(f->next, bb);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx = (bio_filter_in_ctx_t *)filter_ctx->pbioRead->ptr;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem outctx = (bio_filter_out_ctx_t *)filter_ctx->pbioWrite->ptr;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* When we are the writer, we must initialize the inctx
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * mode so that we block for any required ssl input, because
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * output filtering is always nonblocking.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem inctx->mode = AP_MODE_READBYTES;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj inctx->block = APR_BLOCK_READ;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((status = ssl_io_filter_handshake(filter_ctx)) != APR_SUCCESS) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem return ssl_io_filter_error(f, bb, status);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj while (!APR_BRIGADE_EMPTY(bb)) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* If it is a flush or EOS, we need to pass this down.
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * These types do not require translation by OpenSSL.
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (APR_BUCKET_IS_EOS(bucket) || APR_BUCKET_IS_FLUSH(bucket)) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj status = outctx->rc;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem break;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (APR_BUCKET_IS_EOS(bucket)) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /*
0e05808dc59a321566303084c84b9826a4353cefrederpj * By definition, nothing can come after EOS.
0e05808dc59a321566303084c84b9826a4353cefrederpj * which also means we can pass the rest of this brigade
0e05808dc59a321566303084c84b9826a4353cefrederpj * without creating a new one since it only contains the
0e05808dc59a321566303084c84b9826a4353cefrederpj * EOS bucket.
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem */
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
0e05808dc59a321566303084c84b9826a4353cefrederpj return status;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj break;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj else {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* bio_filter_out_flush() already passed down a flush bucket
0e05808dc59a321566303084c84b9826a4353cefrederpj * if there was any data to be flushed.
0e05808dc59a321566303084c84b9826a4353cefrederpj */
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_bucket_delete(bucket);
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj else if (AP_BUCKET_IS_EOC(bucket)) {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj /* The special "EOC" bucket means a shutdown is needed;
0e05808dc59a321566303084c84b9826a4353cefrederpj * - turn off buffering in bio_filter_out_write
40a1aee60a66f7c8dbd0835fdd4f09334e12fc15rpluem * - issue the SSL_shutdown
0e05808dc59a321566303084c84b9826a4353cefrederpj */
0e05808dc59a321566303084c84b9826a4353cefrederpj filter_ctx->nobuffer = 1;
40a1aee60a66f7c8dbd0835fdd4f09334e12fc15rpluem ssl_filter_io_shutdown(filter_ctx, f->c, 0);
0e05808dc59a321566303084c84b9826a4353cefrederpj if ((status = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
0e05808dc59a321566303084c84b9826a4353cefrederpj return status;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj break;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj else {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* filter output */
0e05808dc59a321566303084c84b9826a4353cefrederpj const char *data;
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_size_t len;
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj status = apr_bucket_read(bucket, &data, &len, rblock);
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (APR_STATUS_IS_EAGAIN(status)) {
0e05808dc59a321566303084c84b9826a4353cefrederpj /* No data available: flush... */
0e05808dc59a321566303084c84b9826a4353cefrederpj if (bio_filter_out_flush(filter_ctx->pbioWrite) < 0) {
0e05808dc59a321566303084c84b9826a4353cefrederpj status = outctx->rc;
0e05808dc59a321566303084c84b9826a4353cefrederpj break;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj rblock = APR_BLOCK_READ;
0e05808dc59a321566303084c84b9826a4353cefrederpj continue; /* and try again with a blocking read. */
0e05808dc59a321566303084c84b9826a4353cefrederpj }
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj rblock = APR_NONBLOCK_READ;
0e05808dc59a321566303084c84b9826a4353cefrederpj
0e05808dc59a321566303084c84b9826a4353cefrederpj if (!APR_STATUS_IS_EOF(status) && (status != APR_SUCCESS)) {
0e05808dc59a321566303084c84b9826a4353cefrederpj break;
0e05808dc59a321566303084c84b9826a4353cefrederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj status = ssl_filter_write(f, data, len);
0e05808dc59a321566303084c84b9826a4353cefrederpj apr_bucket_delete(bucket);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj if (status != APR_SUCCESS) {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem break;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem }
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj return status;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj}
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpjstruct modssl_buffer_ctx {
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_bucket_brigade *bb;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj};
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpjint ssl_io_buffer_fill(request_rec *r, apr_size_t maxlen)
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem{
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem conn_rec *c = r->connection;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem struct modssl_buffer_ctx *ctx;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_bucket_brigade *tempb;
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj apr_off_t total = 0; /* total length buffered */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj int eos = 0; /* non-zero once EOS is seen */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* Create the context which will be passed to the input filter;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * containing a setaside pool and a brigade which constrain the
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * lifetime of the buffered data. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ctx = apr_palloc(r->pool, sizeof *ctx);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ctx->bb = apr_brigade_create(r->pool, c->bucket_alloc);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* ... and a temporary brigade. */
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj tempb = apr_brigade_create(r->pool, c->bucket_alloc);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c, "filling buffer, max size "
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem "%" APR_SIZE_T_FMT " bytes", maxlen);
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem do {
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_status_t rv;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem apr_bucket *e, *next;
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem /* The request body is read from the protocol-level input
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj * filters; the buffering filter will reinject it from that
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * level, allowing content/resource filters to run later, if
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem * necessary. */
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem
8445dae5cc606ba8ba04efc341cc1e081d95920drpluem rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj APR_BLOCK_READ, 8192);
85da6b76d07b7af570cbbec208a87697ba9c44f5rederpj if (rv) {
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj "could not read request body for SSL buffer");
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj return HTTP_INTERNAL_SERVER_ERROR;
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj }
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj
3f5585f7f4a7d74f2f94ec729ea8c1879d419e35rederpj /* Iterate through the returned brigade: setaside each bucket
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe * into the context's pool and move it into the brigade. */
e8f95a682820a599fe41b22977010636be5c2717jim for (e = APR_BRIGADE_FIRST(tempb);
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) {
e8f95a682820a599fe41b22977010636be5c2717jim const char *data;
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe apr_size_t len;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes next = APR_BUCKET_NEXT(e);
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APR_BUCKET_IS_EOS(e)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes eos = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes } else if (!APR_BUCKET_IS_METADATA(e)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (rv != APR_SUCCESS) {
f05787953018140838ad51456c86c965d6a86267jim ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "could not read bucket for SSL buffer");
f05787953018140838ad51456c86c965d6a86267jim return HTTP_INTERNAL_SERVER_ERROR;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes total += len;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = apr_bucket_setaside(e, r->pool);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (rv != APR_SUCCESS) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "could not setaside bucket for SSL buffer");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_INTERNAL_SERVER_ERROR;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe APR_BUCKET_REMOVE(e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes total, eos);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Fail if this exceeds the maximum buffer size. */
e8f95a682820a599fe41b22977010636be5c2717jim if (total > maxlen) {
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "request body exceeds maximum size (%" APR_SIZE_T_FMT
e8f95a682820a599fe41b22977010636be5c2717jim ") for SSL buffer", maxlen);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return HTTP_REQUEST_ENTITY_TOO_LARGE;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes } while (!eos);
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim apr_brigade_destroy(tempb);
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* After consuming all protocol-level input, remove all protocol-level
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * filters. It should strictly only be necessary to remove filters
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * at exactly ftype == AP_FTYPE_PROTOCOL, since this filter will
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * precede all > AP_FTYPE_PROTOCOL anyway. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (r->proto_input_filters->frec->ftype < AP_FTYPE_CONNECTION) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_remove_input_filter(r->proto_input_filters);
e8f95a682820a599fe41b22977010636be5c2717jim }
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim /* Insert the filter which will supply the buffered content. */
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ap_add_input_filter(ssl_io_buffer, ctx, r, c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener return 0;
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener}
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener/* This input filter supplies the buffered request body to the caller
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener * from the brigade stored in f->ctx. Note that the placement of this
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener * filter in the filter stack is important; it must be the first
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener * r->proto_input_filter; lower-typed filters will not be preserved
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener * across internal redirects (see PR 43738). */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic apr_status_t ssl_io_filter_buffer(ap_filter_t *f,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_bucket_brigade *bb,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_input_mode_t mode,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_read_type_e block,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_off_t bytes)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes struct modssl_buffer_ctx *ctx = f->ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_status_t rv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "read from buffered SSL brigade, mode %d, "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "%" APR_OFF_T_FMT " bytes",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes mode, bytes);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return APR_ENOTIMPL;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APR_BRIGADE_EMPTY(ctx->bb)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Suprisingly (and perhaps, wrongly), the request body can be
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes * pulled from the input filter stack more than once; a
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * handler may read it, and ap_discard_request_body() will
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * attempt to do so again after *every* request. So input
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * filters must be prepared to give up an EOS if invoked after
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * initially reading the request. The HTTP_IN filter does this
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener * with its ->eos_sent flag. */
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_eos_create(f->c->bucket_alloc));
4be9c459920a7c1cfe62d654327dae5c4bb6b284sf return APR_SUCCESS;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (mode == AP_MODE_READBYTES) {
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes apr_bucket *e;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Partition the buffered brigade. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = apr_brigade_partition(ctx->bb, bytes, &e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (rv && rv != APR_INCOMPLETE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "could not partition buffered SSL brigade");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_remove_input_filter(f);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return rv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If the buffered brigade contains less then the requested
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * length, just pass it all back. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (rv == APR_INCOMPLETE) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_CONCAT(bb, ctx->bb);
e8f95a682820a599fe41b22977010636be5c2717jim } else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes e = APR_BUCKET_PREV(e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe /* Unsplice the partitioned segment and move it into the
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe * passed-in brigade; no convenient way to do this with
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the APR_BRIGADE_* macros. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_RING_UNSPLICE(d, e, link);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_CHECK_CONSISTENCY(bb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Split a line into the passed-in brigade. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rv = apr_brigade_split_line(bb, ctx->bb, block, bytes);
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (rv) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "could not split line from buffered SSL brigade");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_remove_input_filter(f);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return rv;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APR_BRIGADE_EMPTY(ctx->bb)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_bucket *e = APR_BRIGADE_LAST(bb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Ensure that the brigade is terminated by an EOS if the
e8f95a682820a599fe41b22977010636be5c2717jim * buffered request body has been entirely consumed. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes e = apr_bucket_eos_create(f->c->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes APR_BRIGADE_INSERT_TAIL(bb, e);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c,
7dbf29be626018bc389ef94c1846aeac4b72633bsf "buffered SSL brigade exhausted");
7dbf29be626018bc389ef94c1846aeac4b72633bsf /* Note that the filter must *not* be removed here; it may be
7dbf29be626018bc389ef94c1846aeac4b72633bsf * invoked again, see comment above. */
7dbf29be626018bc389ef94c1846aeac4b72633bsf }
7dbf29be626018bc389ef94c1846aeac4b72633bsf
7dbf29be626018bc389ef94c1846aeac4b72633bsf return APR_SUCCESS;
7dbf29be626018bc389ef94c1846aeac4b72633bsf}
7dbf29be626018bc389ef94c1846aeac4b72633bsf
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* The request_rec pointer is passed in here only to ensure that the
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes * filter chain is modified correctly when doing a TLS upgrade. It
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * must *not* be used otherwise. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes request_rec *r, SSL *ssl)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes bio_filter_in_ctx_t *inctx;
7dbf29be626018bc389ef94c1846aeac4b72633bsf
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx = apr_palloc(c->pool, sizeof(*inctx));
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pInputFilter = ap_add_input_filter(ssl_io_filter, inctx, r, c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pbioRead = BIO_new(&bio_filter_in_method);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pbioRead->ptr = (void *)inctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->ssl = ssl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->bio_out = filter_ctx->pbioWrite;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->f = filter_ctx->pInputFilter;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->rc = APR_SUCCESS;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->mode = AP_MODE_READBYTES;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->cbuf.length = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->bb = apr_brigade_create(c->pool, c->bucket_alloc);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->block = APR_BLOCK_READ;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->pool = c->pool;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes inctx->filter_ctx = filter_ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes}
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* The request_rec pointer is passed in here only to ensure that the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * filter chain is modified correctly when doing a TLS upgrade. It
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * must *not* be used otherwise. */
8bdea88407c848c1c2693655e2f8b23abde12307bnicholesvoid ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_filter_ctx_t *filter_ctx;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx = apr_palloc(c->pool, sizeof(ssl_filter_ctx_t));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->config = myConnConfig(c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim filter_ctx->nobuffer = 0;
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe filter_ctx->pOutputFilter = ap_add_output_filter(ssl_io_filter,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx, r, c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* We insert a clogging input filter. Let the core know. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes c->clogging_input_filters = 1;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_io_input_add_filter(filter_ctx, c, r, ssl);
e8f95a682820a599fe41b22977010636be5c2717jim
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes SSL_set_bio(ssl, filter_ctx->pbioRead, filter_ctx->pbioWrite);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes filter_ctx->pssl = ssl;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes apr_pool_cleanup_register(c->pool, (void*)filter_ctx,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ssl_io_filter_cleanup, apr_pool_cleanup_null);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (APLOG_CS_IS_LEVEL(c, mySrvFromConn(c), APLOG_TRACE4)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl);
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes }
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
e8f95a682820a599fe41b22977010636be5c2717jim return;
e8f95a682820a599fe41b22977010636be5c2717jim}
e8f95a682820a599fe41b22977010636be5c2717jim
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowevoid ssl_io_filter_register(apr_pool_t *p)
e8f95a682820a599fe41b22977010636be5c2717jim{
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ap_register_input_filter (ssl_io_filter, ssl_io_filter_input, NULL, AP_FTYPE_CONNECTION + 5);
e8f95a682820a599fe41b22977010636be5c2717jim ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_register_input_filter (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes}
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes/* _________________________________________________________________
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes**
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes** I/O Data Debugging
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes** _________________________________________________________________
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#define DUMP_WIDTH 16
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic void ssl_io_data_dump(server_rec *srvr,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes MODSSL_BIO_CB_ARG_TYPE *s,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes long len)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes{
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char buf[256];
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char tmp[64];
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int i, j, rows, trunc;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned char ch;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes trunc = 0;
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes trunc++;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes rows = (len / DUMP_WIDTH);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((rows * DUMP_WIDTH) < len)
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes rows++;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "+-------------------------------------------------------------------------+");
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe for(i = 0 ; i< rows; i++) {
e8f95a682820a599fe41b22977010636be5c2717jim#if APR_CHARSET_EBCDIC
e8f95a682820a599fe41b22977010636be5c2717jim char ebcdic_text[DUMP_WIDTH];
8113dac419143273351446c3ad653f3fe5ba5cfdwrowe j = DUMP_WIDTH;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((i * DUMP_WIDTH + j) > len)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes j = len % DUMP_WIDTH;
8bdea88407c848c1c2693655e2f8b23abde12307bnicholes if (j == 0)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes j = DUMP_WIDTH;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes memcpy(ebcdic_text,(char *)(s) + i * DUMP_WIDTH, j);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_xlate_proto_from_ascii(ebcdic_text, j);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes#endif /* APR_CHARSET_EBCDIC */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
f05787953018140838ad51456c86c965d6a86267jim apr_cpystrn(buf, tmp, sizeof(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes for (j = 0; j < DUMP_WIDTH; j++) {
f05787953018140838ad51456c86c965d6a86267jim if (((i * DUMP_WIDTH) + j) >= len)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
e8f95a682820a599fe41b22977010636be5c2717jim apr_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes for (j = 0; j < DUMP_WIDTH; j++) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (((i * DUMP_WIDTH) + j) >= len)
e8f95a682820a599fe41b22977010636be5c2717jim apr_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe else {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes#if APR_CHARSET_EBCDIC
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_snprintf(tmp, sizeof(tmp), "%c", (ch >= 0x20 && ch <= 0x7F) ? ebcdic_text[j] : '.');
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes#else /* APR_CHARSET_EBCDIC */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes#endif /* APR_CHARSET_EBCDIC */
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes apr_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
e8f95a682820a599fe41b22977010636be5c2717jim }
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe apr_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr,
e8f95a682820a599fe41b22977010636be5c2717jim "%s", buf);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (trunc > 0)
e8f95a682820a599fe41b22977010636be5c2717jim ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "| %04ld - <SPACES/NULS>", len + trunc);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_error(APLOG_MARK, APLOG_TRACE7, 0, srvr,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "+-------------------------------------------------------------------------+");
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes}
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholeslong ssl_io_data_cb(BIO *bio, int cmd,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes MODSSL_BIO_CB_ARG_TYPE *argp,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes int argi, long argl, long rc)
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener{
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener SSL *ssl;
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener conn_rec *c;
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener server_rec *s;
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener
d64dd2fd4516c2b1b664c5e59c0628d9aff26984covener if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener return rc;
c4f16f709c79bb7e2ddffb532bc7708eab9a9691covener if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return rc;
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes s = mySrvFromConn(c);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if (rc >= 0) {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_cserror(APLOG_MARK, APLOG_TRACE4, 0, c, s,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "%s: %s %ld/%d bytes %s BIO#%pp [mem: %pp] %s",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes SSL_LIBRARY_NAME,
e8f95a682820a599fe41b22977010636be5c2717jim (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes bio, argp,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes (argp != NULL ? "(BIO dump follows)" : "(Oops, no memory buffer?)"));
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes if ((argp != NULL) && APLOG_CS_IS_LEVEL(c, s, APLOG_TRACE7))
482f676c6c19b1c5bb5cca04dad11509c1da3a4cwrowe ssl_io_data_dump(s, argp, rc);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes else {
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes ap_log_cserror(APLOG_MARK, APLOG_TRACE4, 0, c, s,
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes "%s: I/O error, %d bytes expected to %s on BIO#%pp [mem: %pp]",
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes SSL_LIBRARY_NAME, argi,
f43b67c5a9d29b572eac916f8335cedc80c908bebnicholes (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes bio, argp);
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes }
03f4448f864e31ade79856ac8c264a5e6dce3b10bnicholes return rc;
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener}
37af4b0cf648275b68ff41c866c665b4ccf4667dcovener