Commit 4d19c21e authored by Brian Pane's avatar Brian Pane
Browse files

forward-port the latest versions of mod_ssl and mod_setenvif from the 2.3...

forward-port the latest versions of mod_ssl and mod_setenvif from the 2.3 trunk to the async-dev branch so t/TEST will work once again

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/async-dev@306538 13f79535-47bb-0310-9956-ffa450edef68
parent f835fb50
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -947,16 +947,16 @@ static int apprentice(server_rec *s, apr_pool_t *p)
    /* parse it */
    for (lineno = 1; apr_file_gets(line, BUFSIZ, f) == APR_SUCCESS; lineno++) {
	int ws_offset;
        char *last = line + strlen(line) - 1; /* guaranteed that len >= 1 */
        char *last = line + strlen(line) - 1; /* guaranteed that len >= 1 since an
                                               * "empty" line contains a '\n'
                                               */

	/* delete newline and potential carriage return */
        if (*last == '\n') {
	/* delete newline and any other trailing whitespace */
        while (last >= line
               && apr_isspace(*last)) {
            *last = '\0';
            --last;
        }
        if (*last == '\r') {
            *last = '\0';
        }
        
	/* skip leading whitespace */
	ws_offset = 0;
+5 −4
Original line number Diff line number Diff line
@@ -123,7 +123,7 @@ typedef struct {

module AP_MODULE_DECLARE_DATA setenvif_module;

static APR_OPTIONAL_FN_TYPE(ssl_extlist_by_oid) *ssl_extlist_by_oid_func = NULL;
static APR_OPTIONAL_FN_TYPE(ssl_ext_list) *ssl_ext_list_func = NULL;

/*
 * These routines, the create- and merge-config functions, are called
@@ -531,7 +531,7 @@ static int match_headers(request_rec *r)
                break;
            case SPECIAL_OID_VALUE:
                /* If mod_ssl is not loaded, the accessor function is NULL */
                if (ssl_extlist_by_oid_func != NULL)
                if (ssl_ext_list_func != NULL)
                {
                    apr_array_header_t *oid_array;
                    char **oid_value;
@@ -539,7 +539,8 @@ static int match_headers(request_rec *r)
                    char *retval = NULL;

                    /* The given oid can occur multiple times. Concatenate the values */
                    if ((oid_array = ssl_extlist_by_oid_func(r, b->name)) != NULL) {
                    if ((oid_array = ssl_ext_list_func(r->pool, r->connection, 1,
                                                       b->name)) != NULL) {
                        oid_value = (char **) oid_array->elts;
                        /* pass 1: determine the size of the string */
                        for (len=j=0; j < oid_array->nelts; j++) {
@@ -630,7 +631,7 @@ static int match_headers(request_rec *r)
static int setenvif_post_config(apr_pool_t *pconf, apr_pool_t *plog,
                                apr_pool_t *ptemp, server_rec *s)
{
    ssl_extlist_by_oid_func = APR_RETRIEVE_OPTIONAL_FN(ssl_extlist_by_oid);
    ssl_ext_list_func = APR_RETRIEVE_OPTIONAL_FN(ssl_ext_list);
    return OK;
}

+0 −2
Original line number Diff line number Diff line
@@ -504,8 +504,6 @@ static void ssl_register_hooks(apr_pool_t *p)

    APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable);
    APR_REGISTER_OPTIONAL_FN(ssl_engine_disable);

    APR_REGISTER_OPTIONAL_FN(ssl_extlist_by_oid);
}

module AP_MODULE_DECLARE_DATA ssl_module = {
+13 −10
Original line number Diff line number Diff line
@@ -36,15 +36,20 @@ APR_DECLARE_OPTIONAL_FN(char *, ssl_var_lookup,
                         conn_rec *, request_rec *,
                         char *));

/** The ssl_ext_lookup() optional function retrieves the value of a SSL
 * certificate X.509 extension.  The client certificate is used if
 * peer is non-zero; the server certificate is used otherwise.  The
 * oidnum parameter specifies the numeric OID (e.g. "1.2.3.4") of the
 * desired extension.  The string value of the extension is returned,
 * or NULL on error. */
APR_DECLARE_OPTIONAL_FN(const char *, ssl_ext_lookup,
/** The ssl_ext_list() optional function attempts to build an array
 * of all the values contained in the named X.509 extension. The 
 * returned array will be created in the supplied pool.
 * The client certificate is used if peer is non-zero; the server 
 * certificate is used otherwise.
 * Extension specifies the extensions to use as a string. This can be
 * one of the "known" long or short names, or a numeric OID,
 * e.g. "1.2.3.4", 'nsComment' and 'DN' are all valid.
 * A pointer to an apr_array_header_t structure is returned if at
 * least one matching extension is found, NULL otherwise.
 */
APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_ext_list,
                        (apr_pool_t *p, conn_rec *c, int peer,
                         const char *oidnum));
                         const char *extension));

/** An optional function which returns non-zero if the given connection
 * is using SSL/TLS. */
@@ -58,7 +63,5 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *));

APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *));

APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr));

#endif /* __MOD_SSL_H__ */
/** @} */
+185 −0
Original line number Diff line number Diff line
@@ -882,6 +882,7 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f,
}

static const char ssl_io_filter[] = "SSL/TLS Filter";
static const char ssl_io_buffer[] = "SSL/TLS Buffer";

/*
 *  Close the SSL part of the socket connection
@@ -1446,6 +1447,187 @@ static apr_status_t ssl_io_filter_output(ap_filter_t *f,
    return status;
}

/* 128K maximum buffer size by default. */
#ifndef SSL_MAX_IO_BUFFER
#define SSL_MAX_IO_BUFFER (128 * 1024)
#endif

struct modssl_buffer_ctx {
    apr_bucket_brigade *bb;
    apr_pool_t *pool;
};

int ssl_io_buffer_fill(request_rec *r)
{
    conn_rec *c = r->connection;
    struct modssl_buffer_ctx *ctx;
    apr_bucket_brigade *tempb;
    apr_off_t total = 0; /* total length buffered */
    int eos = 0; /* non-zero once EOS is seen */
    
    /* Create the context which will be passed to the input filter;
     * containing a setaside pool and a brigade which constrain the
     * lifetime of the buffered data. */
    ctx = apr_palloc(r->pool, sizeof *ctx);
    apr_pool_create(&ctx->pool, r->pool);
    ctx->bb = apr_brigade_create(ctx->pool, c->bucket_alloc);

    /* ... and a temporary brigade. */
    tempb = apr_brigade_create(r->pool, c->bucket_alloc);

    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "filling buffer");

    do {
        apr_status_t rv;
        apr_bucket *e, *next;

        /* The request body is read from the protocol-level input
         * filters; the buffering filter will reinject it from that
         * level, allowing content/resource filters to run later, if
         * necessary. */

        rv = ap_get_brigade(r->proto_input_filters, tempb, AP_MODE_READBYTES,
                            APR_BLOCK_READ, 8192);
        if (rv) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "could not read request body for SSL buffer");
            return HTTP_INTERNAL_SERVER_ERROR;
        }
        
        /* Iterate through the returned brigade: setaside each bucket
         * into the context's pool and move it into the brigade. */
        for (e = APR_BRIGADE_FIRST(tempb); 
             e != APR_BRIGADE_SENTINEL(tempb) && !eos; e = next) {
            const char *data;
            apr_size_t len;

            next = APR_BUCKET_NEXT(e);

            if (APR_BUCKET_IS_EOS(e)) {
                eos = 1;
            } else if (!APR_BUCKET_IS_METADATA(e)) {
                rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
                if (rv != APR_SUCCESS) {
                    ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                                  "could not read bucket for SSL buffer");
                    return HTTP_INTERNAL_SERVER_ERROR;
                }
                total += len;
            }
                
            rv = apr_bucket_setaside(e, ctx->pool);
            if (rv != APR_SUCCESS) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                              "could not setaside bucket for SSL buffer");
                return HTTP_INTERNAL_SERVER_ERROR;
            }
            
            APR_BUCKET_REMOVE(e);
            APR_BRIGADE_INSERT_TAIL(ctx->bb, e);
        }

        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 
                      "total of %" APR_OFF_T_FMT " bytes in buffer, eos=%d",
                      total, eos);

        /* Fail if this exceeds the maximum buffer size. */
        if (total > SSL_MAX_IO_BUFFER) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "request body exceeds maximum size for SSL buffer");
            return HTTP_REQUEST_ENTITY_TOO_LARGE;
        }

    } while (!eos);

    apr_brigade_destroy(tempb);

    /* Insert the filter which will supply the buffered data. */
    ap_add_input_filter(ssl_io_buffer, ctx, r, c);

    return 0;
}

/* This input filter supplies the buffered request body to the caller
 * from the brigade stored in f->ctx. */
static apr_status_t ssl_io_filter_buffer(ap_filter_t *f,
                                         apr_bucket_brigade *bb,
                                         ap_input_mode_t mode,
                                         apr_read_type_e block,
                                         apr_off_t bytes)
{
    struct modssl_buffer_ctx *ctx = f->ctx;
    apr_status_t rv;

    ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
                  "read from buffered SSL brigade, mode %d, "
                  "%" APR_OFF_T_FMT " bytes",
                  mode, bytes);

    if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {
        return APR_ENOTIMPL;
    }

    if (mode == AP_MODE_READBYTES) {
        apr_bucket *e;

        /* Partition the buffered brigade. */
        rv = apr_brigade_partition(ctx->bb, bytes, &e);
        if (rv && rv != APR_INCOMPLETE) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c,
                          "could not partition buffered SSL brigade");
            ap_remove_input_filter(f);
            return rv;
        }

        /* If the buffered brigade contains less then the requested
         * length, just pass it all back. */
        if (rv == APR_INCOMPLETE) {
            APR_BRIGADE_CONCAT(bb, ctx->bb);
        } else {
            apr_bucket *d = APR_BRIGADE_FIRST(ctx->bb);

            e = APR_BUCKET_PREV(e);
            
            /* Unsplice the partitioned segment and move it into the
             * passed-in brigade; no convenient way to do this with
             * the APR_BRIGADE_* macros. */
            APR_RING_UNSPLICE(d, e, link);
            APR_RING_SPLICE_HEAD(&bb->list, d, e, apr_bucket, link);

            APR_BRIGADE_CHECK_CONSISTENCY(bb);
            APR_BRIGADE_CHECK_CONSISTENCY(ctx->bb);
        }
    }
    else {
        /* Split a line into the passed-in brigade. */
        rv = apr_brigade_split_line(bb, ctx->bb, mode, bytes);

        if (rv) {
            ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c,
                          "could not split line from buffered SSL brigade");
            ap_remove_input_filter(f);
            return rv;
        }
    }

    if (APR_BRIGADE_EMPTY(ctx->bb)) {
        apr_bucket *e = APR_BRIGADE_LAST(bb);
        
        /* Ensure that the brigade is terminated by an EOS if the
         * buffered request body has been entirely consumed. */
        if (e == APR_BRIGADE_SENTINEL(bb) || !APR_BUCKET_IS_EOS(e)) {
            e = apr_bucket_eos_create(f->c->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(bb, e);
        }

        ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, f->c,
                      "buffered SSL brigade now exhausted; removing filter");
        ap_remove_input_filter(f);
    }

    return APR_SUCCESS;
}

static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c,
                                    SSL *ssl)
{
@@ -1508,6 +1690,9 @@ void ssl_io_filter_register(apr_pool_t *p)

    ap_register_input_filter  (ssl_io_filter, ssl_io_filter_input,  NULL, AP_FTYPE_CONNECTION + 5);
    ap_register_output_filter (ssl_io_filter, ssl_io_filter_output, NULL, AP_FTYPE_CONNECTION + 5);
    
    ap_register_input_filter  (ssl_io_buffer, ssl_io_filter_buffer, NULL, AP_FTYPE_PROTOCOL - 1);

    return;
}

Loading