diff options
author | rcritten <> | 2006-08-09 20:11:45 +0000 |
---|---|---|
committer | rcritten <> | 2006-08-09 20:11:45 +0000 |
commit | a2c56687f17bdefe258c63b17264d80be2cbd44c (patch) | |
tree | 21a4cc83b8f4aeae50778f598faea587d585e91c /nss_engine_kernel.c | |
parent | ecf3a7e8c544b351ed3923ff01806759e7abbb75 (diff) | |
download | mod_nss-a2c56687f17bdefe258c63b17264d80be2cbd44c.tar.gz mod_nss-a2c56687f17bdefe258c63b17264d80be2cbd44c.tar.xz mod_nss-a2c56687f17bdefe258c63b17264d80be2cbd44c.zip |
Merge in changes from http://svn.apache.org/viewvc?view=rev&revision=290965
Implement a (bounded) buffer of request body data to provide a limited
but safe fix for the mod_nss renegotiation-vs-requests-with-bodies
bug:
* mod_nss.h (nss_io_buffer_fill): Add prototype.
* nss_engine_io.c (nss_io_buffer_fill,
nss_io_filter_buffer): New functions.
* nss_engine_kernel.c (nss_hook_Access): If a renegotiation is needed,
and the request has a non-zero content-length, or a t-e header (and
100-continue was not requested), call nss_io_buffer_fill to set aside
the request body data if possible, then proceed with the negotiation.
PR: 12355
Diffstat (limited to 'nss_engine_kernel.c')
-rw-r--r-- | nss_engine_kernel.c | 90 |
1 files changed, 26 insertions, 64 deletions
diff --git a/nss_engine_kernel.c b/nss_engine_kernel.c index baa8c49..6a73007 100644 --- a/nss_engine_kernel.c +++ b/nss_engine_kernel.c @@ -312,73 +312,35 @@ int nss_hook_Access(request_rec *r) } } - /* - * SSL renegotiations in conjunction with HTTP - * requests using the POST method are not supported. - * - * 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. + /* If a renegotiation is now required for this location, and the + * request includes a message body (and the client has not + * requested a "100 Continue" response), then the client will be + * streaming the request body over the wire already. In that + * case, it is not possible to stop and perform a new SSL + * handshake immediately; once the SSL library moves to the + * "accept" state, it will reject the SSL packets which the client + * is sending for the request body. * - * !! BUT ALL THIS IS STILL NOT RE-IMPLEMENTED FOR APACHE 2.0 !! + * To allow authentication to complete in this auth hook, the + * solution used here is to fill a (bounded) buffer with the + * request body, and then to reinject that request body later. */ - if (renegotiate && !renegotiate_quick && (r->method_number == M_POST)) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, - "SSL Re-negotiation in conjunction " - "with POST method not supported!" - "hint: try NSSOptions +OptRenegotiate"); + if (renegotiate && !renegotiate_quick + && (apr_table_get(r->headers_in, "transfer-encoding") + || (apr_table_get(r->headers_in, "content-length") + && strcmp(apr_table_get(r->headers_in, "content-length"), "0"))) + && !r->expecting_100) { + int rv; - return HTTP_METHOD_NOT_ALLOWED; + /* Fill the I/O buffer with the request body if possible. */ + rv = nss_io_buffer_fill(r); + + if (rv) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, + "could not buffer message body to allow " + "SSL renegotiation to proceed"); + return rv; + } } /* |