ssl_engine_io.c revision 574f6ff9ee80ef4f772649c5c8319b764a8abe42
/* _ _
** _ __ ___ ___ __| | ___ ___| | mod_ssl
** | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
** | | | | | | (_) | (_| | \__ \__ \ | www.modssl.org
** |_| |_| |_|\___/ \__,_|___|___/___/_| ftp.modssl.org
** |_____|
** I/O Functions
*/
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. 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
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``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 THE APACHE SOFTWARE FOUNDATION OR
* ITS 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 Hooks
** _________________________________________________________________
*/
/* XXX THIS STUFF NEEDS A MAJOR CLEANUP -RSE XXX */
static const char ssl_io_filter[] = "SSL/TLS Filter";
{
int rc;
return -1;
}
if (rc < 0) {
if (ssl_err == SSL_ERROR_WANT_READ) {
/*
* 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.)
*/
}
else if (ssl_err == SSL_ERROR_SSL) {
/*
* Log SSL errors
*/
"SSL error on reading data");
}
/*
* XXX - Just trying to reflect the behaviour in
* openssl_state_machine.c [mod_tls]. TBD
*/
rc = -1;
}
return rc;
}
{
int rc;
return -1;
}
if (rc < 0) {
if (ssl_err == SSL_ERROR_WANT_WRITE) {
/*
* Simulate an EINTR in case OpenSSL wants to write more.
*/
}
else if (ssl_err == SSL_ERROR_SSL) {
/*
* Log SSL errors
*/
"SSL error on writing data");
}
/*
* XXX - Just trying to reflect the behaviour in
* openssl_state_machine.c [mod_tls]. TBD
*/
rc = 0;
}
return rc;
}
{
apr_pool_t *p = f->c->pool;
/* we've been shutdown */
return APR_EOF;
}
/*
* use the BIO memory buffer that has already been allocated,
* rather than making another copy of it.
* use bm directly here is *much* faster than calling BIO_read()
*/
/* XXX: it may be possible to not always flush */
}
return APR_SUCCESS;
}
#define bio_is_renegotiating(bio) \
#define HTTP_ON_HTTPS_PORT "GET /mod_ssl:error:HTTP-request HTTP/1.0\r\n"
{
conn_rec *c = f->c;
apr_pool_t *p = c->pool;
apr_bucket *e;
int found_eos = 0, n;
char buf[1024];
/* Flush the output buffers. */
/* We have something in the processed brigade. Use that first. */
if (!APR_BRIGADE_EMPTY(ctx->b)) {
return APR_SUCCESS;
}
/* If we have nothing in the raw brigade, get some more. */
if (rv != APR_SUCCESS)
return rv;
/* Can't make any progress here. */
if (*readbytes == 0)
{
/* This means that we have nothing else to read ever. */
if (eMode == AP_MODE_BLOCKING) {
}
return APR_SUCCESS;
}
}
/* Process anything we have that we haven't done so already. */
const char *data;
if (APR_BUCKET_IS_EOS(e)) {
found_eos = 1;
break;
}
/* read from the bucket */
if (rv != APR_SUCCESS)
return rv;
/* Write it to our BIO */
if ((apr_size_t)n != len) {
/* this should never really happen, since we're just writing
* into a memory buffer, unless, of course, we run out of
* memory
*/
"attempting to write %d bytes to rbio, only wrote %d",
len, n);
return APR_ENOMEM;
}
/* If we reached here, we read the bucket successfully, so toss
* it from the raw brigade. */
}
/* Flush the output buffers. */
/* Before we actually read any unencrypted data, go ahead and
* let ssl_hook_process_connection have a shot at it.
*/
/* Flush again. */
if (rv != APR_SUCCESS) {
/* if process connection says HTTP_BAD_REQUEST, we've seen a
* HTTP on HTTPS error.
*
* The case where OpenSSL has recognized a HTTP request:
* This means the client speaks plain HTTP on our HTTPS port.
* Hmmmm... At least for this error we can be more friendly
* and try to provide him with a HTML error page. We have only
* one problem:OpenSSL has already read some bytes from the HTTP
* request. So we have to skip the request line manually and
* instead provide a faked one in order to continue the internal
* Apache processing.
*
*/
if (rv == HTTP_BAD_REQUEST) {
/* log the situation */
"SSL handshake failed: HTTP spoken on HTTPS port; "
"trying to send HTML error page");
/* fake the request line */
sizeof(HTTP_ON_HTTPS_PORT) - 1);
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
return APR_SUCCESS;
}
if (rv == SSL_ERROR_WANT_READ) {
}
return rv;
}
/* try to pass along all of the current BIO to ctx->b */
/* FIXME: If there's an error and there was EOS, we may not really
* reach EOS.
*/
char *pbuf;
e = apr_bucket_pool_create(pbuf, n, p);
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
/* Flush the output buffers. */
}
}
if (found_eos) {
}
return churn_output(pRec);
}
{
while (!APR_BRIGADE_EMPTY(bb)) {
const char *data;
apr_size_t len, n;
/* If it is a flush or EOS, we need to pass this down.
* These types do not require translation by OpenSSL.
*/
return ret;
}
if (ret != APR_SUCCESS) {
return ret;
}
/* By definition, nothing can come after EOS. */
if (APR_BUCKET_IS_EOS(bucket)) {
break;
}
}
else {
/* read filter */
/* write SSL */
if (n != len) {
conn_rec *c = f->c;
char *reason = "reason unknown";
/* XXX: probably a better way to determine this */
reason = "likely due to failed renegotiation";
}
"failed to write %d of %d bytes (%s)",
ret = APR_EINVAL;
break;
}
/* churn the state machine */
break;
}
}
}
return ret;
}
{
apr_bucket *e;
/* XXX: we don't currently support peek or readbytes == -1 */
return APR_ENOTIMPL;
}
/* Return the requested amount or less. */
if (*readbytes)
{
/* churn the state machine */
if (ret != APR_SUCCESS)
return ret;
/* ### This is bad. */
APR_BRIGADE_NORMALIZE(ctx->b);
}
else {
}
return APR_SUCCESS;
}
/* Readbytes == 0 implies we only want a LF line.
* 1024 seems like a good number for now. */
if (APR_BRIGADE_EMPTY(ctx->b)) {
tempread = 1024;
if (rv != APR_SUCCESS)
return rv;
/* We have already blocked. */
}
while (!APR_BRIGADE_EMPTY(ctx->b)) {
e = APR_BRIGADE_FIRST(ctx->b);
/* Sure, we'll call this is a line. Whatever. */
if (APR_BUCKET_IS_EOS(e)) {
break;
}
AP_MODE_NONBLOCKING)) != APR_SUCCESS) {
return rv;
}
/* We found a match. */
return APR_SUCCESS;
}
/* Hey, we're about to be starved - go fetch more data. */
if (APR_BRIGADE_EMPTY(ctx->b)) {
tempread = 1024;
if (ret != APR_SUCCESS)
return ret;
}
}
return APR_SUCCESS;
}
{
/* already been shutdown */
return APR_SUCCESS;
}
"Error in ssl_hook_CloseConnection");
}
return ret;
}
{
/* XXX: this will currently get wiped out if renegotiation
* happens in ssl_hook_Access
*/
}
return;
}
void ssl_io_filter_register(apr_pool_t *p)
{
return;
}
/* _________________________________________________________________
**
** I/O Data Debugging
** _________________________________________________________________
*/
#define DUMP_WIDTH 16
{
char buf[256];
char tmp[64];
unsigned char ch;
trunc = 0;
trunc++;
rows++;
"+-------------------------------------------------------------------------+");
for(i = 0 ; i< rows; i++) {
for (j = 0; j < DUMP_WIDTH; j++) {
if (((i * DUMP_WIDTH) + j) >= len)
else {
}
}
for (j = 0; j < DUMP_WIDTH; j++) {
if (((i * DUMP_WIDTH) + j) >= len)
else {
}
}
}
if (trunc > 0)
"+-------------------------------------------------------------------------+");
return;
}
{
conn_rec *c;
server_rec *s;
return rc;
return rc;
s = c->base_server;
if (rc >= 0) {
ssl_log(s, SSL_LOG_DEBUG,
"%s: %s %ld/%d bytes %s BIO#%08X [mem: %08lX] %s",
}
else {
ssl_log(s, SSL_LOG_DEBUG,
"%s: I/O error, %d bytes expected to %s on BIO#%08X [mem: %08lX]",
}
}
return rc;
}