⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssl_engine_io.c

📁 Apache HTTP Server 是一个功能强大的灵活的与HTTP/1.1相兼容的web服务器.这里给出的是Apache HTTP服务器的源码。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//*                      _             _ *  _ __ ___   ___   __| |    ___ ___| |  mod_ssl * | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL * | | | | | | (_) | (_| |   \__ \__ \ | * |_| |_| |_|\___/ \__,_|___|___/___/_| *                      |_____| *  ssl_engine_io.c *  I/O Functions */                             /* ``MY HACK: This universe.                                  Just one little problem:                                  core keeps dumping.''                                            -- Unknown    */#include "mod_ssl.h"/*  _________________________________________________________________****  I/O Hooks**  _________________________________________________________________*//* This file is designed to be the bridge between OpenSSL and httpd. * However, we really don't expect anyone (let alone ourselves) to * remember what is in this file.  So, first, a quick overview. * * In this file, you will find: * - ssl_io_filter_input    (Apache input filter) * - ssl_io_filter_output   (Apache output filter) * * - bio_filter_in_*        (OpenSSL input filter) * - bio_filter_out_*       (OpenSSL output filter) * * The input chain is roughly: * * ssl_io_filter_input->ssl_io_input_read->SSL_read->... * ...->bio_filter_in_read->ap_get_brigade/next-httpd-filter * * In mortal terminology, we do the following: * - Receive a request for data to the SSL input filter * - Call a helper function once we know we should perform a read * - Call OpenSSL's SSL_read() * - SSL_read() will then call bio_filter_in_read * - bio_filter_in_read will then try to fetch data from the next httpd filter * - bio_filter_in_read will flatten that data and return it to SSL_read * - SSL_read will then decrypt the data * - ssl_io_input_read will then receive decrypted data as a char* and *   ensure that there were no read errors * - The char* is placed in a brigade and returned * * Since connection-level input filters in httpd need to be able to * handle AP_MODE_GETLINE calls (namely identifying LF-terminated strings),  * ssl_io_input_getline which will handle this special case. * * Due to AP_MODE_GETLINE and AP_MODE_SPECULATIVE, we may sometimes have  * 'leftover' decoded data which must be setaside for the next read.  That * is currently handled by the char_buffer_{read|write} functions.  So, * ssl_io_input_read may be able to fulfill reads without invoking * SSL_read(). * * Note that the filter context of ssl_io_filter_input and bio_filter_in_* * are shared as bio_filter_in_ctx_t. * * Note that the filter is by choice limited to reading at most * AP_IOBUFSIZE (8192 bytes) per call. * *//* this custom BIO allows us to hook SSL_write directly into  * an apr_bucket_brigade and use transient buckets with the SSL * malloc-ed buffer, rather than copying into a mem BIO. * also allows us to pass the brigade as data is being written * rather than buffering up the entire response in the mem BIO. * * when SSL needs to flush (e.g. SSL_accept()), it will call BIO_flush() * which will trigger a call to bio_filter_out_ctrl() -> bio_filter_out_flush(). * so we only need to flush the output ourselves if we receive an * EOS or FLUSH bucket. this was not possible with the mem BIO where we * had to flush all over the place not really knowing when it was required * to do so. */typedef struct {    SSL                *pssl;    BIO                *pbioRead;    BIO                *pbioWrite;    ap_filter_t        *pInputFilter;    ap_filter_t        *pOutputFilter;    int                nobuffer; /* non-zero to prevent buffering */} ssl_filter_ctx_t;typedef struct {    ssl_filter_ctx_t *filter_ctx;    conn_rec *c;    apr_bucket_brigade *bb;    apr_size_t length;    char buffer[AP_IOBUFSIZE];    apr_size_t blen;    apr_status_t rc;} bio_filter_out_ctx_t;static bio_filter_out_ctx_t *bio_filter_out_ctx_new(ssl_filter_ctx_t *filter_ctx,                                                    conn_rec *c){    bio_filter_out_ctx_t *outctx = apr_palloc(c->pool, sizeof(*outctx));    outctx->filter_ctx = filter_ctx;    outctx->c = c;    outctx->bb = apr_brigade_create(c->pool, c->bucket_alloc);    outctx->blen = 0;    outctx->length = 0;    return outctx;}static int bio_filter_out_flush(BIO *bio){    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);    apr_bucket *e;    if (!(outctx->blen || outctx->length)) {        outctx->rc = APR_SUCCESS;        return 1;    }    if (outctx->blen) {        e = apr_bucket_transient_create(outctx->buffer, outctx->blen,                                        outctx->bb->bucket_alloc);        /* we filled this buffer first so add it to the          * head of the brigade         */        APR_BRIGADE_INSERT_HEAD(outctx->bb, e);        outctx->blen = 0;    }    outctx->length = 0;    e = apr_bucket_flush_create(outctx->bb->bucket_alloc);    APR_BRIGADE_INSERT_TAIL(outctx->bb, e);    outctx->rc = ap_pass_brigade(outctx->filter_ctx->pOutputFilter->next,                                 outctx->bb);    /* Fail if the connection was reset: */    if (outctx->rc == APR_SUCCESS && outctx->c->aborted) {        outctx->rc = APR_ECONNRESET;    }    return (outctx->rc == APR_SUCCESS) ? 1 : -1;}static int bio_filter_create(BIO *bio){    bio->shutdown = 1;    bio->init = 1;    bio->num = -1;    bio->ptr = NULL;    return 1;}static int bio_filter_destroy(BIO *bio){    if (bio == NULL) {        return 0;    }    /* nothing to free here.     * apache will destroy the bucket brigade for us     */    return 1;}	static int bio_filter_out_read(BIO *bio, char *out, int outl){    /* this is never called */    return -1;}static int bio_filter_out_write(BIO *bio, const char *in, int inl){    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);    /* when handshaking we'll have a small number of bytes.     * max size SSL will pass us here is about 16k.     * (16413 bytes to be exact)     */    BIO_clear_retry_flags(bio);    if (!outctx->length && (inl + outctx->blen < sizeof(outctx->buffer)) &&        !outctx->filter_ctx->nobuffer) {        /* the first two SSL_writes (of 1024 and 261 bytes)         * need to be in the same packet (vec[0].iov_base)         */        /* XXX: could use apr_brigade_write() to make code look cleaner         * but this way we avoid the malloc(APR_BUCKET_BUFF_SIZE)         * and free() of it later         */        memcpy(&outctx->buffer[outctx->blen], in, inl);        outctx->blen += inl;    }    else {        /* pass along the encrypted data         * need to flush since we're using SSL's malloc-ed buffer          * which will be overwritten once we leave here         */        apr_bucket *bucket = apr_bucket_transient_create(in, inl,                                             outctx->bb->bucket_alloc);        outctx->length += inl;        APR_BRIGADE_INSERT_TAIL(outctx->bb, bucket);        if (bio_filter_out_flush(bio) < 0) {            return -1;        }    }    return inl;}static long bio_filter_out_ctrl(BIO *bio, int cmd, long num, void *ptr){    long ret = 1;    char **pptr;    bio_filter_out_ctx_t *outctx = (bio_filter_out_ctx_t *)(bio->ptr);    switch (cmd) {      case BIO_CTRL_RESET:        outctx->blen = outctx->length = 0;        break;      case BIO_CTRL_EOF:        ret = (long)((outctx->blen + outctx->length) == 0);        break;      case BIO_C_SET_BUF_MEM_EOF_RETURN:        outctx->blen = outctx->length = (apr_size_t)num;        break;      case BIO_CTRL_INFO:        ret = (long)(outctx->blen + outctx->length);        if (ptr) {            pptr = (char **)ptr;            *pptr = (char *)&(outctx->buffer[0]);        }        break;      case BIO_CTRL_GET_CLOSE:        ret = (long)bio->shutdown;        break;      case BIO_CTRL_SET_CLOSE:        bio->shutdown = (int)num;        break;      case BIO_CTRL_WPENDING:        ret = 0L;        break;      case BIO_CTRL_PENDING:        ret = (long)(outctx->blen + outctx->length);        break;      case BIO_CTRL_FLUSH:        ret = bio_filter_out_flush(bio);        break;      case BIO_CTRL_DUP:        ret = 1;        break;        /* N/A */      case BIO_C_SET_BUF_MEM:      case BIO_C_GET_BUF_MEM_PTR:        /* we don't care */      case BIO_CTRL_PUSH:      case BIO_CTRL_POP:      default:        ret = 0;        break;    }    return ret;}static int bio_filter_out_gets(BIO *bio, char *buf, int size){    /* this is never called */    return -1;}static int bio_filter_out_puts(BIO *bio, const char *str){    /* this is never called */    return -1;}static BIO_METHOD bio_filter_out_method = {    BIO_TYPE_MEM,    "APR output filter",    bio_filter_out_write,    bio_filter_out_read,     /* read is never called */    bio_filter_out_puts,     /* puts is never called */    bio_filter_out_gets,     /* gets is never called */    bio_filter_out_ctrl,    bio_filter_create,    bio_filter_destroy,#ifdef OPENSSL_VERSION_NUMBER    NULL /* sslc does not have the callback_ctrl field */#endif};typedef struct {    int length;    char *value;} char_buffer_t;typedef struct {    SSL *ssl;    BIO *bio_out;    ap_filter_t *f;    apr_status_t rc;    ap_input_mode_t mode;    apr_read_type_e block;    apr_bucket_brigade *bb;    char_buffer_t cbuf;    apr_pool_t *pool;    char buffer[AP_IOBUFSIZE];    ssl_filter_ctx_t *filter_ctx;} bio_filter_in_ctx_t;/* * this char_buffer api might seem silly, but we don't need to copy * any of this data and we need to remember the length. */static int char_buffer_read(char_buffer_t *buffer, char *in, int inl){    if (!buffer->length) {        return 0;    }    if (buffer->length > inl) {        /* we have have enough to fill the caller's buffer */        memcpy(in, buffer->value, inl);        buffer->value += inl;        buffer->length -= inl;    }    else {        /* swallow remainder of the buffer */        memcpy(in, buffer->value, buffer->length);        inl = buffer->length;        buffer->value = NULL;        buffer->length = 0;    }    return inl;}static int char_buffer_write(char_buffer_t *buffer, char *in, int inl){    buffer->value = in;    buffer->length = inl;    return inl;}/* This function will read from a brigade and discard the read buckets as it * proceeds.  It will read at most *len bytes. */static apr_status_t brigade_consume(apr_bucket_brigade *bb,                                    apr_read_type_e block,                                    char *c, apr_size_t *len){    apr_size_t actual = 0;    apr_status_t status = APR_SUCCESS;     while (!APR_BRIGADE_EMPTY(bb)) {        apr_bucket *b = APR_BRIGADE_FIRST(bb);        const char *str;        apr_size_t str_len;        apr_size_t consume;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -