summaryrefslogtreecommitdiffstats
path: root/usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c
diff options
context:
space:
mode:
authorhenning <henning@openbsd.org>2014-04-22 14:47:23 +0000
committerhenning <henning@openbsd.org>2014-04-22 14:47:23 +0000
commitd98f7e048a396e24ae64ddd378bc54773464aaaa (patch)
treef51a6e7ca8ee49dc43679c82497118fddcd7dff3 /usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c
parentFinally remove KERBEROS5? from the Makefile infrastructure. (diff)
downloadwireguard-openbsd-d98f7e048a396e24ae64ddd378bc54773464aaaa.tar.xz
wireguard-openbsd-d98f7e048a396e24ae64ddd378bc54773464aaaa.zip
this commit is really florian@'s, since he's the one who made removal
of our forked apache possible by his work on nginx and slowcgi, but he doesn't want it - so it is my pleasure to tedu it. I spent so much work on chroot in it 10 years ago - and am very happy to see it go now, nginx is a far better choice today. Bye bye, Apache, won't miss you.
Diffstat (limited to 'usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c')
-rw-r--r--usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c545
1 files changed, 0 insertions, 545 deletions
diff --git a/usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c b/usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c
deleted file mode 100644
index 3d6fcc467ab..00000000000
--- a/usr.sbin/httpd/src/modules/ssl/ssl_engine_io.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/* _ _
-** _ __ ___ ___ __| | ___ ___| | mod_ssl
-** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
-** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
-** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
-** |_____|
-** ssl_engine_io.c
-** I/O Functions
-*/
-
-/* ====================================================================
- * Copyright (c) 1998-2003 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;
- }
- 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) {
- 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
-** _________________________________________________________________
-*/
-
-#include <sys/types.h>
-#include <sys/uio.h>
-
-static int ssl_io_hook_read(BUFF *fb, char *buf, int len);
-static int ssl_io_hook_write(BUFF *fb, char *buf, int len);
-static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt);
-
-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);
- ap_hook_register("ap::buff::writev", ssl_io_hook_writev, AP_HOOK_NOCTX);
- 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);
- ap_hook_unregister("ap::buff::writev", ssl_io_hook_writev);
- 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
- * renegotiation 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,
- "SSL error on reading data");
- }
- /*
- * read(2) returns only the generic error number -1
- */
- if (rc < 0)
- rc = -1;
- }
- else
- rc = read(fb->fd_in, buf, len);
- return rc;
-}
-
-static int ssl_io_hook_write(BUFF *fb, char *buf, int len)
-{
- SSL *ssl;
- conn_rec *c;
- int rc;
-
- if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
- rc = SSL_write(ssl, buf, len);
- /*
- * Simulate an EINTR in case OpenSSL wants to write more.
- */
- if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
- 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,
- "SSL error on writing data");
- }
- /*
- * write(2) returns only the generic error number -1
- */
- if (rc < 0)
- rc = -1;
- }
- else
- rc = write(fb->fd, buf, len);
- return rc;
-}
-
-/* the prototype for our own SSL_writev() */
-static int SSL_writev(SSL *, const struct iovec *, int);
-
-static int ssl_io_hook_writev(BUFF *fb, const struct iovec *iov, int iovcnt)
-{
- SSL *ssl;
- conn_rec *c;
- int rc;
-
- if ((ssl = ap_ctx_get(fb->ctx, "ssl")) != NULL) {
- rc = SSL_writev(ssl, iov, iovcnt);
- /*
- * Simulate an EINTR in case OpenSSL wants to write more.
- */
- if (rc < 0 && SSL_get_error(ssl, rc) == SSL_ERROR_WANT_WRITE)
- 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,
- "SSL error on writing data");
- }
- /*
- * writev(2) returns only the generic error number -1
- */
- if (rc < 0)
- rc = -1;
- }
- else
- rc = writev(fb->fd, iov, iovcnt);
- return rc;
-}
-
-
-/* _________________________________________________________________
-**
-** Special Functions for OpenSSL
-** _________________________________________________________________
-*/
-
-
-/*
- * There is no SSL_writev() provided by OpenSSL. The reason is mainly because
- * OpenSSL has to fragment the data itself again for the SSL record layer, so a
- * writev() like interface makes not much sense. What we do is to emulate it
- * to at least being able to use the write() like interface. But keep in mind
- * that the network I/O performance is not write() like, of course.
- */
-static int SSL_writev(SSL *ssl, const struct iovec *iov, int iovcnt)
-{
- int i;
- int n;
- int rc;
-
- rc = 0;
- for (i = 0; i < iovcnt; i++) {
- if ((n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len)) == -1) {
- rc = -1;
- break;
- }
- rc += n;
- }
- return rc;
-}
-
-/* _________________________________________________________________
-**
-** I/O Data Debugging
-** _________________________________________________________________
-*/
-
-#define DUMP_WIDTH 16
-
-static void ssl_io_data_dump(server_rec *srvr, const char *s, long len)
-{
- char buf[256];
- char tmp[64];
- int i, j, rows, trunc;
- unsigned char ch;
-
- trunc = 0;
- for(; (len > 0) && ((s[len-1] == ' ') || (s[len-1] == '\0')); len--)
- trunc++;
- rows = (len / DUMP_WIDTH);
- if ((rows * DUMP_WIDTH) < len)
- rows++;
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "+-------------------------------------------------------------------------+");
- for(i = 0 ; i< rows; i++) {
- ap_snprintf(tmp, sizeof(tmp), "| %04x: ", i * DUMP_WIDTH);
- ap_cpystrn(buf, tmp, sizeof(buf));
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len)
- ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- else {
- ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
- ap_snprintf(tmp, sizeof(tmp), "%02x%c", ch , j==7 ? '-' : ' ');
- ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
- }
- }
- ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- for (j = 0; j < DUMP_WIDTH; j++) {
- if (((i * DUMP_WIDTH) + j) >= len)
- ap_cpystrn(buf+strlen(buf), " ", sizeof(buf)-strlen(buf));
- else {
- ch = ((unsigned char)*((char *)(s) + i * DUMP_WIDTH + j)) & 0xff;
- ap_snprintf(tmp, sizeof(tmp), "%c", ((ch >= ' ') && (ch <= '~')) ? ch : '.');
- ap_cpystrn(buf+strlen(buf), tmp, sizeof(buf)-strlen(buf));
- }
- }
- ap_cpystrn(buf+strlen(buf), " |", sizeof(buf)-strlen(buf));
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID, "%s", buf);
- }
- if (trunc > 0)
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "| %04x - <SPACES/NULS>", len + trunc);
- ssl_log(srvr, SSL_LOG_DEBUG|SSL_NO_TIMESTAMP|SSL_NO_LEVELID,
- "+-------------------------------------------------------------------------+");
- return;
-}
-
-long ssl_io_data_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long rc)
-{
- SSL *ssl;
- conn_rec *c;
- server_rec *s;
-
- if ((ssl = (SSL *)BIO_get_callback_arg(bio)) == NULL)
- return rc;
- if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
- return rc;
- s = c->server;
-
- if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
- || cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
- if (rc >= 0) {
- ssl_log(s, SSL_LOG_DEBUG,
- "%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s",
- SSL_LIBRARY_NAME,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
- rc, argi, (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "to" : "from"),
- bio, argp,
- (argp != NULL ? "(BIO dump follows)" : "(Ops, no memory buffer?)"));
- if (argp != NULL)
- ssl_io_data_dump(s, argp, rc);
- }
- else {
- ssl_log(s, SSL_LOG_DEBUG,
- "%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
- SSL_LIBRARY_NAME, argi,
- (cmd == (BIO_CB_WRITE|BIO_CB_RETURN) ? "write" : "read"),
- bio, argp);
- }
- }
- return rc;
-}
-