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

📄 ssl_engine_io.c

📁 mod_ssl-2.8.31-1.3.41.tar.gz 好用的ssl工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/*                      _             _**  _ __ ___   ___   __| |    ___ ___| |  mod_ssl** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org**                      |_____|**  ssl_engine_io.c**  I/O Functions*//* ==================================================================== * Copyright (c) 1998-2006 Ralf S. Engelschall. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following *    disclaimer in the documentation and/or other materials *    provided with the distribution. * * 3. All advertising materials mentioning features or use of this *    software must display the following acknowledgment: *    "This product includes software developed by *     Ralf S. Engelschall <rse@engelschall.com> for use in the *     mod_ssl project (http://www.modssl.org/)." * * 4. The names "mod_ssl" must not be used to endorse or promote *    products derived from this software without prior written *    permission. For written permission, please contact *    rse@engelschall.com. * * 5. Products derived from this software may not be called "mod_ssl" *    nor may "mod_ssl" appear in their names without prior *    written permission of Ralf S. Engelschall. * * 6. Redistributions of any form whatsoever must retain the following *    acknowledgment: *    "This product includes software developed by *     Ralf S. Engelschall <rse@engelschall.com> for use in the *     mod_ssl project (http://www.modssl.org/)." * * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL RALF S. ENGELSCHALL OR * HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */                             /* ``MY HACK: This universe.                                  Just one little problem:                                  core keeps dumping.''                                            -- Unknown    */#include "mod_ssl.h"/*  _________________________________________________________________****  I/O Request Body Sucking and Re-Injection**  _________________________________________________________________*/#ifndef SSL_CONSERVATIVE/* * Background: * * 1. When the client sends a HTTP/HTTPS request, Apache's core code * reads only the request line ("METHOD /path HTTP/x.y") and the * attached MIME headers ("Foo: bar") up to the terminating line ("CR * LF"). An attached request body (for instance the data of a POST * method) is _NOT_ read. Instead it is read by mod_cgi's content * handler and directly passed to the CGI script. * * 2. mod_ssl supports per-directory re-configuration of SSL parameters. * This is implemented by performing an SSL renegotiation of the * re-configured parameters after the request is read, but before the * response is sent. In more detail: the renegotiation happens after the * request line and MIME headers were read, but _before_ the attached * request body is read. The reason simply is that in the HTTP protocol * usually there is no acknowledgment step between the headers and the * body (there is the 100-continue feature and the chunking facility * only), so Apache has no API hook for this step. * * 3. the problem now occurs when the client sends a POST request for * URL /foo via HTTPS the server and the server has SSL parameters * re-configured on a per-URL basis for /foo. Then mod_ssl has to * perform an SSL renegotiation after the request was read and before * the response is sent. But the problem is the pending POST body data * in the receive buffer of SSL (which Apache still has not read - it's * pending until mod_cgi sucks it in). When mod_ssl now tries to perform * the renegotiation the pending data leads to an I/O error. * * Solution Idea: * * There are only two solutions: Either to simply state that POST * requests to URLs with SSL re-configurations are not allowed, or to * renegotiate really after the _complete_ request (i.e. including * the POST body) was read. Obviously the latter would be preferred, * but it cannot be done easily inside Apache, because as already * mentioned, there is no API step between the body reading and the body * processing. And even when we mod_ssl would hook directly into the * loop of mod_cgi, we wouldn't solve the problem for other handlers, of * course. So the only general solution is to suck in the pending data * of the request body from the OpenSSL BIO into the Apache BUFF. Then * the renegotiation can be done and after this step Apache can proceed * processing the request as before. * * Solution Implementation: * * We cannot simply suck in the data via an SSL_read-based loop because of * HTTP chunking. Instead we _have_ to use the Apache API for this step which * is aware of HTTP chunking. So the trick is to suck in the pending request * data via the Apache API (which uses Apache's BUFF code and in the * background mod_ssl's I/O glue code) and re-inject it later into the Apache * BUFF code again. This way the data flows twice through the Apache BUFF, of * course. But this way the solution doesn't depend on any Apache specifics * and is fully transparent to Apache modules. */struct ssl_io_suck_st {    BOOL  active;    char *bufptr;    int   buflen;    char *pendptr;    int   pendlen;};/* prepare request_rec structure for input sucking */static void ssl_io_suck_start(request_rec *r){    struct ssl_io_suck_st *ss;    ss = ap_ctx_get(r->ctx, "ssl::io::suck");    if (ss == NULL) {        ss = ap_palloc(r->pool, sizeof(struct ssl_io_suck_st));        ap_ctx_set(r->ctx, "ssl::io::suck", ss);        ss->buflen  = 8192;        ss->bufptr  = ap_palloc(r->pool, ss->buflen);    }    ss->pendptr = ss->bufptr;    ss->pendlen = 0;    ss->active = FALSE;    return;}/* record a sucked input chunk */static void ssl_io_suck_record(request_rec *r, char *buf, int len){    struct ssl_io_suck_st *ss;        if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)        return;    if (((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) < len) {        /* "expand" buffer: actually we cannot really expand the buffer           here, because Apache's pool system doesn't support expanding chunks           of memory. Instead we have to either reuse processed data or           allocate a new chunk of memory in advance if we really need more           memory. */        int newlen;        char *newptr;        if ((  (ss->pendptr - ss->bufptr)              + ((ss->bufptr + ss->buflen) - (ss->pendptr + ss->pendlen)) ) >= len) {            /* make memory available by reusing already processed data */            memmove(ss->bufptr, ss->pendptr, ss->pendlen);            ss->pendptr = ss->bufptr;        }        else {            /* too bad, we have to allocate a new larger buffer */            newlen = (ss->buflen * 2) + len;            newptr = ap_palloc(r->pool, newlen);            ss->bufptr  = newptr;            ss->buflen  = newlen;            memcpy(ss->bufptr, ss->pendptr, ss->pendlen);            ss->pendptr = ss->bufptr;        }    }    memcpy(ss->pendptr+ss->pendlen, buf, len);    ss->pendlen += len;    return;}/* finish request_rec after input sucking */static void ssl_io_suck_end(request_rec *r){    struct ssl_io_suck_st *ss;        if ((ss = ap_ctx_get(r->ctx, "ssl::io::suck")) == NULL)        return;    ss->active = TRUE;    r->read_body    = REQUEST_NO_BODY;    r->read_length  = 0;    r->read_chunked = 0;    r->remaining    = 0;    ap_bsetflag(r->connection->client, B_CHUNK, 0);    return;}void ssl_io_suck(request_rec *r, SSL *ssl){    int rc;    int len;    char *buf;    int buflen;    char c;    int sucked;    if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK)) == OK) {        if (ap_should_client_block(r)) {            /* read client request block through Apache API */            buflen = HUGE_STRING_LEN;            buf = ap_palloc(r->pool, buflen);            ap_hard_timeout("SSL I/O request body pre-sucking", r);            sucked = 0;            ssl_io_suck_start(r);            while ((len = ap_get_client_block(r, buf, buflen)) > 0) {                ssl_io_suck_record(r, buf, len);                sucked += len;                ap_reset_timeout(r);            }            ssl_io_suck_end(r);            ap_kill_timeout(r);            /* suck trailing data (usually CR LF) which                is still in the Apache BUFF layer */            ap_hard_timeout("SSL I/O request trailing data pre-sucking", r);            while (ap_bpeekc(r->connection->client) != EOF) {                c = ap_bgetc(r->connection->client);                ssl_io_suck_record(r, &c, 1);                sucked++;            }            ap_kill_timeout(r);            ssl_log(r->server, SSL_LOG_TRACE,                     "I/O: sucked %d bytes of input data from SSL/TLS I/O layer "                    "for delayed injection into Apache I/O layer", sucked);        }    }    return;}    /* the SSL_read replacement routine which knows about the suck buffer */static int ssl_io_suck_read(SSL *ssl, char *buf, int len){    ap_ctx *actx;    struct ssl_io_suck_st *ss;    request_rec *r = NULL;    int rv;    actx = (ap_ctx *)SSL_get_app_data2(ssl);    if (actx != NULL)        r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec");    rv = -1;    if (r != NULL && r->ctx != NULL) {        ss = ap_ctx_get(r->ctx, "ssl::io::suck");        if (ss != NULL) {            if (ss->active && ss->pendlen > 0) {                /* ok, there is pre-sucked data */                len = (ss->pendlen > len ? len : ss->pendlen);                memcpy(buf, ss->pendptr, len);                ss->pendptr += len;                ss->pendlen -= len;                ssl_log(r->server, SSL_LOG_TRACE,                         "I/O: injecting %d bytes of pre-sucked data "                        "into Apache I/O layer", len);                rv = len;            }        }    }    if (rv == -1)        rv = SSL_read(ssl, buf, len);    return rv;}/* override SSL_read in the following code... */#define SSL_read ssl_io_suck_read#endif /* !SSL_CONSERVATIVE *//*  _________________________________________________________________****  I/O Hooks**  _________________________________________________________________*/#ifndef NO_WRITEV#include <sys/types.h>#include <sys/uio.h>#endifstatic int ssl_io_hook_read(BUFF *fb, char *buf, int len);static int ssl_io_hook_write(BUFF *fb, char *buf, int len);#ifndef NO_WRITEVstatic int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt);#endif#ifdef WIN32static int ssl_io_hook_recvwithtimeout(BUFF *fb, char *buf, int len);static int ssl_io_hook_sendwithtimeout(BUFF *fb, const char *buf, int len);#endif /* WIN32 */void ssl_io_register(void){    ap_hook_register("ap::buff::read",   ssl_io_hook_read,  AP_HOOK_NOCTX);    ap_hook_register("ap::buff::write",  ssl_io_hook_write, AP_HOOK_NOCTX);#ifndef NO_WRITEV    ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX);#endif#ifdef WIN32    ap_hook_register("ap::buff::recvwithtimeout",                     ssl_io_hook_recvwithtimeout, AP_HOOK_NOCTX);    ap_hook_register("ap::buff::sendwithtimeout",                     ssl_io_hook_sendwithtimeout, AP_HOOK_NOCTX);#endif    return;}void ssl_io_unregister(void){    ap_hook_unregister("ap::buff::read",   ssl_io_hook_read);    ap_hook_unregister("ap::buff::write",  ssl_io_hook_write);#ifndef NO_WRITEV    ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev);#endif#ifdef WIN32    ap_hook_unregister("ap::buff::recvwithtimeout", ssl_io_hook_recvwithtimeout);    ap_hook_unregister("ap::buff::sendwithtimeout", ssl_io_hook_sendwithtimeout);#endif    return;}static int ssl_io_hook_read(BUFF *fb, char *buf, int len){    SSL *ssl;    conn_rec *c;    int rc;    if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {        rc = SSL_read(ssl, buf, len);        /*         * Simulate an EINTR in case OpenSSL wants to read more.         * (This is usually the case when the client forces an SSL         * renegotation which is handled implicitly by OpenSSL.)         */        if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_READ)            errno = EINTR;        /*         * Log SSL errors         */        if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_SSL) {            c = (conn_rec *)SSL_get_app_data(ssl);            ssl_log(c->server, SSL_LOG_ERROR|SSL_ADD_SSLERR,

⌨️ 快捷键说明

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