Blame apache2/apache2_io.c

Packit 284210
/*
Packit 284210
 * ModSecurity for Apache 2.x, http://www.modsecurity.org/
Packit 284210
 * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
Packit 284210
 *
Packit 284210
 * You may not use this file except in compliance with
Packit 284210
 * the License.  You may obtain a copy of the License at
Packit 284210
 *
Packit 284210
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 284210
 *
Packit 284210
 * If any of the files related to licensing are missing or if you have any
Packit 284210
 * other questions related to licensing please contact Trustwave Holdings, Inc.
Packit 284210
 * directly using the email address security@modsecurity.org.
Packit 284210
 */
Packit 284210
Packit 284210
#include <util_filter.h>
Packit 284210
Packit 284210
#include "modsecurity.h"
Packit 284210
#include "apache2.h"
Packit 284210
#include "msc_crypt.h"
Packit 284210
Packit 284210
/* -- Input filter -- */
Packit 284210
Packit 284210
#if 0
Packit 284210
static void dummy_free_func(void *data) {}
Packit 284210
#endif
Packit 284210
Packit 284210
/**
Packit 284210
 * This request filter will forward the previously stored
Packit 284210
 * request body further down the chain (most likely to the
Packit 284210
 * processing module).
Packit 284210
 */
Packit 284210
apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out,
Packit 284210
        ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes)
Packit 284210
{
Packit 284210
    modsec_rec *msr = (modsec_rec *)f->ctx;
Packit 284210
    msc_data_chunk *chunk = NULL;
Packit 284210
    apr_bucket *bucket;
Packit 284210
    apr_status_t rc;
Packit 284210
    char *my_error_msg = NULL;
Packit 284210
Packit 284210
    if (msr == NULL) {
Packit 284210
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
Packit 284210
                "ModSecurity: Internal error in input filter: msr is null.");
Packit 284210
        ap_remove_input_filter(f);
Packit 284210
        return APR_EGENERAL;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Make sure we are using the current request */
Packit 284210
    msr->r = f->r;
Packit 284210
Packit 284210
    if (msr->phase < PHASE_REQUEST_BODY) {
Packit 284210
        msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase);
Packit 284210
        return APR_EGENERAL;
Packit 284210
    }
Packit 284210
Packit 284210
    if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) {
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r);
Packit 284210
        }
Packit 284210
        ap_remove_input_filter(f);
Packit 284210
        return ap_get_brigade(f->next, bb_out, mode, block, nbytes);
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT
Packit 284210
                " (f %pp, r %pp).", mode, block, nbytes, f, f->r);
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->if_started_forwarding == 0) {
Packit 284210
        msr->if_started_forwarding = 1;
Packit 284210
        rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg);
Packit 284210
        if (rc == -1) {
Packit 284210
            if (my_error_msg != NULL) {
Packit 284210
                msr_log(msr, 1, "%s", my_error_msg);
Packit 284210
            }
Packit 284210
            return APR_EGENERAL;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg);
Packit 284210
    if (rc == -1) {
Packit 284210
        if (my_error_msg != NULL) {
Packit 284210
            msr_log(msr, 1, "%s", my_error_msg);
Packit 284210
        }
Packit 284210
        return APR_EGENERAL;
Packit 284210
    }
Packit 284210
Packit 284210
    if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) {
Packit 284210
        /* Copy the data we received in the chunk */
Packit 284210
        bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
Packit 284210
                f->r->connection->bucket_alloc);
Packit 284210
Packit 284210
#if 0
Packit 284210
Packit 284210
        It would seem that we cannot prevent other filters in the chain
Packit 284210
            from modifying data in-place. Hence we copy.
Packit 284210
Packit 284210
            if (chunk->is_permanent) {
Packit 284210
                /* Do not make a copy of the data we received in the chunk. */
Packit 284210
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func,
Packit 284210
                        f->r->connection->bucket_alloc);
Packit 284210
            } else {
Packit 284210
                /* Copy the data we received in the chunk. */
Packit 284210
                bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL,
Packit 284210
                        f->r->connection->bucket_alloc);
Packit 284210
            }
Packit 284210
Packit 284210
#endif
Packit 284210
Packit 284210
        if (bucket == NULL) return APR_EGENERAL;
Packit 284210
        APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length);
Packit 284210
        }
Packit 284210
    } else if (msr->stream_input_data != NULL) {
Packit 284210
Packit 284210
        msr->if_stream_changed = 0;
Packit 284210
Packit 284210
        bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL,
Packit 284210
                f->r->connection->bucket_alloc);
Packit 284210
Packit 284210
        if (msr->txcfg->stream_inbody_inspection)  {
Packit 284210
            if(msr->stream_input_data != NULL) {
Packit 284210
                free(msr->stream_input_data);
Packit 284210
                msr->stream_input_data = NULL;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        if (bucket == NULL) return APR_EGENERAL;
Packit 284210
        APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length);
Packit 284210
        }
Packit 284210
Packit 284210
    }
Packit 284210
Packit 284210
    if (rc == 0) {
Packit 284210
        modsecurity_request_body_retrieve_end(msr);
Packit 284210
Packit 284210
        if (msr->if_seen_eos) {
Packit 284210
            bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc);
Packit 284210
            if (bucket == NULL) return APR_EGENERAL;
Packit 284210
            APR_BRIGADE_INSERT_TAIL(bb_out, bucket);
Packit 284210
Packit 284210
            if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                msr_log(msr, 4, "Input filter: Sent EOS.");
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* We're done */
Packit 284210
        msr->if_status = IF_STATUS_COMPLETE;
Packit 284210
        ap_remove_input_filter(f);
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input filter: Input forwarding complete.");
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return APR_SUCCESS;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Reads request body from a client.
Packit 284210
 */
Packit 284210
apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
Packit 284210
    request_rec *r = msr->r;
Packit 284210
    unsigned int finished_reading;
Packit 284210
    apr_bucket_brigade *bb_in;
Packit 284210
    apr_bucket *bucket;
Packit 284210
Packit 284210
    if (error_msg == NULL) return -1;
Packit 284210
    *error_msg = NULL;
Packit 284210
Packit 284210
    if (msr->reqbody_should_exist != 1) {
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input filter: This request does not have a body.");
Packit 284210
        }
Packit 284210
        return 0;
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->txcfg->reqbody_access != 1) {
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Input filter: Request body access not enabled.");
Packit 284210
        }
Packit 284210
        return 0;
Packit 284210
    }
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        msr_log(msr, 4, "Input filter: Reading request body.");
Packit 284210
    }
Packit 284210
Packit 284210
    if (modsecurity_request_body_start(msr, error_msg) < 0) {
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    finished_reading = 0;
Packit 284210
    msr->if_seen_eos = 0;
Packit 284210
    bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc);
Packit 284210
    if (bb_in == NULL) return -1;
Packit 284210
    do {
Packit 284210
        apr_status_t rc;
Packit 284210
Packit 284210
        rc = ap_get_brigade(r->input_filters, bb_in, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN);
Packit 284210
        if (rc != APR_SUCCESS) {
Packit 284210
            /* NOTE Apache returns AP_FILTER_ERROR here when the request is
Packit 284210
             *      too large and APR_EGENERAL when the client disconnects.
Packit 284210
             */
Packit 284210
            switch(rc) {
Packit 284210
                case APR_INCOMPLETE :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
Packit 284210
                    return -7;
Packit 284210
                case APR_EOF :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
Packit 284210
                    return -6;
Packit 284210
                case APR_TIMEUP :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
Packit 284210
                    return -4;
Packit 284210
                case AP_FILTER_ERROR :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)");
Packit 284210
                    return -3;
Packit 284210
                case APR_EGENERAL :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away.");
Packit 284210
                    return -2;
Packit 284210
                default :
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc));
Packit 284210
                    return -1;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* Loop through the buckets in the brigade in order
Packit 284210
         * to extract the size of the data available.
Packit 284210
         */
Packit 284210
        for(bucket = APR_BRIGADE_FIRST(bb_in);
Packit 284210
                bucket != APR_BRIGADE_SENTINEL(bb_in);
Packit 284210
                bucket = APR_BUCKET_NEXT(bucket))
Packit 284210
        {
Packit 284210
            const char *buf;
Packit 284210
            apr_size_t buflen;
Packit 284210
Packit 284210
            rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
Packit 284210
            if (rc != APR_SUCCESS) {
Packit 284210
                *error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc));
Packit 284210
                return -1;
Packit 284210
            }
Packit 284210
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
Packit 284210
                        bucket->type->name, buflen);
Packit 284210
            }
Packit 284210
Packit 284210
            /* Check request body limit (should only trigger on chunked requests). */
Packit 284210
            if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) {
Packit 284210
                if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) {
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
Packit 284210
                            "configured limit (%ld).", msr->txcfg->reqbody_limit);
Packit 284210
                    return -5;
Packit 284210
                } else if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) {
Packit 284210
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
Packit 284210
                            "configured limit (%ld).", msr->txcfg->reqbody_limit);
Packit 284210
Packit 284210
                } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)){
Packit 284210
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
Packit 284210
                            "configured limit (%ld).", msr->txcfg->reqbody_limit);
Packit 284210
Packit 284210
                } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)){
Packit 284210
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
Packit 284210
                            "configured limit (%ld).", msr->txcfg->reqbody_limit);
Packit 284210
Packit 284210
                } else  {
Packit 284210
Packit 284210
                    *error_msg = apr_psprintf(msr->mp, "Request body is larger than the "
Packit 284210
                            "configured limit (%ld).", msr->txcfg->reqbody_limit);
Packit 284210
Packit 284210
                    return -5;
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            if (msr->txcfg->stream_inbody_inspection == 1)   {
Packit 284210
                msr->stream_input_length+=buflen;
Packit 284210
                modsecurity_request_body_to_stream(msr, buf, buflen, error_msg);
Packit 284210
            }
Packit 284210
Packit 284210
            msr->reqbody_length += buflen;
Packit 284210
Packit 284210
            if (buflen != 0) {
Packit 284210
                int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg);
Packit 284210
Packit 284210
                if (msr->reqbody_length > (apr_size_t)msr->txcfg->reqbody_limit && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) {
Packit 284210
                    finished_reading = 1;
Packit 284210
                }
Packit 284210
Packit 284210
                if (rcbs < 0) {
Packit 284210
                    if (rcbs == -5) {
Packit 284210
                        if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) {
Packit 284210
                            *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
Packit 284210
                                    "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
Packit 284210
                            return -5;
Packit 284210
                        } else if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) {
Packit 284210
                            *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
Packit 284210
                                    "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
Packit 284210
                        } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) {
Packit 284210
                            *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
Packit 284210
                                    "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
Packit 284210
                        } else {
Packit 284210
                            *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
Packit 284210
                                    "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
Packit 284210
                            return -5;
Packit 284210
                        }
Packit 284210
                    }
Packit 284210
Packit 284210
                    if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT))
Packit 284210
                        return -1;
Packit 284210
                }
Packit 284210
Packit 284210
            }
Packit 284210
Packit 284210
            if (APR_BUCKET_IS_EOS(bucket)) {
Packit 284210
                finished_reading = 1;
Packit 284210
                msr->if_seen_eos = 1;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        apr_brigade_cleanup(bb_in);
Packit 284210
    } while(!finished_reading);
Packit 284210
Packit 284210
    // TODO: Why ignore the return code here?
Packit 284210
    modsecurity_request_body_end(msr, error_msg);
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").",
Packit 284210
                msr->reqbody_length);
Packit 284210
    }
Packit 284210
Packit 284210
    msr->if_status = IF_STATUS_WANTS_TO_RUN;
Packit 284210
Packit 284210
    return 1;
Packit 284210
}
Packit 284210
Packit 284210
Packit 284210
/* -- Output filter -- */
Packit 284210
Packit 284210
/**
Packit 284210
 * Examines the configuration and the response MIME type
Packit 284210
 * in order to determine whether output buffering should
Packit 284210
 * run or not.
Packit 284210
 */
Packit 284210
static int output_filter_should_run(modsec_rec *msr, request_rec *r) {
Packit 284210
    char *content_type = NULL;
Packit 284210
Packit 284210
    /* Check configuration. */
Packit 284210
    if (msr->txcfg->resbody_access != 1) {
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Output filter: Response body buffering is not enabled.");
Packit 284210
        }
Packit 284210
Packit 284210
        return 0;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Check MIME type. */
Packit 284210
Packit 284210
    if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) {
Packit 284210
        msr_log(msr, 1, "Output filter: MIME type structures corrupted (internal error).");
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    if (r->content_type != NULL) {
Packit 284210
        char *p = NULL;
Packit 284210
Packit 284210
        content_type = apr_pstrdup(msr->mp, r->content_type);
Packit 284210
        if (content_type == NULL) {
Packit 284210
            msr_log(msr, 1, "Output filter: Failed to allocate memory for content type.");
Packit 284210
            return -1;
Packit 284210
        }
Packit 284210
Packit 284210
        /* Hide the character encoding information
Packit 284210
         * if present. Sometimes the content type header
Packit 284210
         * looks like this "text/html; charset=xyz" ...
Packit 284210
         */
Packit 284210
        p = strstr(content_type, ";");
Packit 284210
        if (p != NULL) {
Packit 284210
            *p = '\0';
Packit 284210
        }
Packit 284210
Packit 284210
        strtolower_inplace((unsigned char *)content_type);
Packit 284210
Packit 284210
        if (strcmp(content_type, "text/html") == 0) {
Packit 284210
            /* Useful information to have should we later
Packit 284210
             * decide to do something with the HTML output.
Packit 284210
             */
Packit 284210
            msr->resbody_contains_html = 1;
Packit 284210
        }
Packit 284210
    } else {
Packit 284210
        content_type = "null";
Packit 284210
    }
Packit 284210
Packit 284210
    if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1;
Packit 284210
Packit 284210
    msr_log(msr, 4, "Output filter: Not buffering response body for unconfigured MIME type \"%s\".", content_type);
Packit 284210
Packit 284210
    return 0;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Initialises the output filter.
Packit 284210
 */
Packit 284210
static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f,
Packit 284210
        apr_bucket_brigade *bb_in)
Packit 284210
{
Packit 284210
    request_rec *r = f->r;
Packit 284210
    const char *s_content_length = NULL;
Packit 284210
    apr_status_t rc;
Packit 284210
Packit 284210
    msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc);
Packit 284210
    if (msr->of_brigade == NULL) {
Packit 284210
        msr_log(msr, 1, "Output filter: Failed to create brigade.");
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
    msr->of_status = OF_STATUS_IN_PROGRESS;
Packit 284210
Packit 284210
    rc = output_filter_should_run(msr, r);
Packit 284210
    if (rc < 0) return -1; /* output_filter_should_run() generates error msg */
Packit 284210
    if (rc == 0) return 0;
Packit 284210
Packit 284210
    /* Do not check the output limit if we are willing to
Packit 284210
     * process partial response bodies.
Packit 284210
     */
Packit 284210
Packit 284210
    if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_PARTIAL) {
Packit 284210
        return 1;
Packit 284210
    }
Packit 284210
Packit 284210
    /* Look up the Content-Length header to see if we know
Packit 284210
     * the amount of data coming our way. If we do and if
Packit 284210
     * it's too much we might want to stop processing right here.
Packit 284210
     */
Packit 284210
    s_content_length = apr_table_get(r->headers_out, "Content-Length");
Packit 284210
    if (s_content_length == NULL) {
Packit 284210
        /* Try this too, mod_cgi seems to put headers there. */
Packit 284210
        s_content_length = apr_table_get(r->err_headers_out, "Content-Length");
Packit 284210
    }
Packit 284210
Packit 284210
    if (s_content_length != NULL) {
Packit 284210
        long int len;
Packit 284210
Packit 284210
        len = strtol(s_content_length, NULL, 10);
Packit 284210
        if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) {
Packit 284210
            msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool,
Packit 284210
                        (char *)s_content_length));
Packit 284210
            return -1; /* Invalid. */
Packit 284210
        }
Packit 284210
Packit 284210
        if (len == 0) {
Packit 284210
            if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero.");
Packit 284210
            }
Packit 284210
Packit 284210
            return 0;
Packit 284210
        }
Packit 284210
Packit 284210
        if (len > msr->txcfg->of_limit) {
Packit 284210
            msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).",
Packit 284210
                    log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit);
Packit 284210
            msr->outbound_error = 1;
Packit 284210
            return -2; /* Over the limit. */
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return 1;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Send the accumulated content down the filter stream
Packit 284210
 * and to the client.
Packit 284210
 */
Packit 284210
static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) {
Packit 284210
    apr_status_t rc;
Packit 284210
Packit 284210
    rc = ap_pass_brigade(f->next, msr->of_brigade);
Packit 284210
    if (rc != APR_SUCCESS) {
Packit 284210
        /* TODO: These need to move to flags in 2.6.  For now log them
Packit 284210
         * at level 4 so that they are not confusing users.
Packit 284210
         */
Packit 284210
        int log_level = 4;
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= log_level) {
Packit 284210
            switch(rc) {
Packit 284210
                case AP_NOBODY_WROTE :
Packit 284210
                    msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): No data", rc);
Packit 284210
                    break;
Packit 284210
                case AP_FILTER_ERROR :
Packit 284210
                    /* Look like this is caused by the error
Packit 284210
                     * already being handled, so we should ignore it
Packit 284210
                     *
Packit 284210
                     msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc);
Packit 284210
                     */
Packit 284210
                    break;
Packit 284210
                default :
Packit 284210
                    msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s",
Packit 284210
                            rc, get_apr_error(msr->mp, rc));
Packit 284210
                    break;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        return rc;
Packit 284210
    }
Packit 284210
Packit 284210
    return APR_SUCCESS;
Packit 284210
}
Packit 284210
Packit 284210
/** \brief Inject data into brigade
Packit 284210
 *
Packit 284210
 * \param msr ModSecurity transation resource
Packit 284210
 * \param ap_filter_t Apache filter
Packit 284210
 *
Packit 284210
 */
Packit 284210
static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
Packit 284210
    apr_bucket *b;
Packit 284210
Packit 284210
    if (msr->txcfg->content_injection_enabled && msr->stream_output_data != NULL) {
Packit 284210
        apr_bucket *bucket_ci = NULL;
Packit 284210
Packit 284210
        bucket_ci = apr_bucket_heap_create(msr->stream_output_data,
Packit 284210
                msr->stream_output_length, NULL, f->r->connection->bucket_alloc);
Packit 284210
Packit 284210
        for (b = APR_BRIGADE_FIRST(msr->of_brigade); b != APR_BRIGADE_SENTINEL(msr->of_brigade); b = APR_BUCKET_NEXT(b))  {
Packit 284210
            if(!APR_BUCKET_IS_METADATA(b))
Packit 284210
                apr_bucket_delete(b);
Packit 284210
        }
Packit 284210
Packit 284210
        APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
            msr_log(msr, 9, "Content Injection: Data reinjected bytes [%"APR_SIZE_T_FMT"]",msr->stream_output_length);
Packit 284210
        }
Packit 284210
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 *
Packit 284210
 */
Packit 284210
static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) {
Packit 284210
    if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) {
Packit 284210
        apr_bucket *bucket_ci = NULL;
Packit 284210
Packit 284210
        bucket_ci = apr_bucket_heap_create(msr->content_prepend,
Packit 284210
                msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
Packit 284210
        APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci);
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
            msr_log(msr, 9, "Content Injection (b): Added content to top: %s",
Packit 284210
                    log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
Packit 284210
        }
Packit 284210
    }
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 *
Packit 284210
 */
Packit 284210
static int flatten_response_body(modsec_rec *msr) {
Packit 284210
    apr_status_t rc;
Packit 284210
Packit 284210
    msr->resbody_status = RESBODY_STATUS_READ_BRIGADE;
Packit 284210
Packit 284210
    if (msr->resbody_length + 1 <= 0) {
Packit 284210
        msr_log(msr, 1, "Output filter: Invalid response length: %" APR_SIZE_T_FMT, msr->resbody_length);
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1);
Packit 284210
    if (msr->resbody_data == NULL) {
Packit 284210
        msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
Packit 284210
                msr->resbody_length + 1);
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length);
Packit 284210
    if (rc != APR_SUCCESS) {
Packit 284210
        msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc,
Packit 284210
                get_apr_error(msr->mp, rc));
Packit 284210
        return -1;
Packit 284210
    }
Packit 284210
Packit 284210
    msr->resbody_data[msr->resbody_length] = '\0';
Packit 284210
    msr->resbody_status = RESBODY_STATUS_READ;
Packit 284210
Packit 284210
    if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_DISABLED)  {
Packit 284210
Packit 284210
        msr->stream_output_length = msr->resbody_length;
Packit 284210
Packit 284210
        if (msr->stream_output_data == NULL) {
Packit 284210
            msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
Packit 284210
                    msr->stream_output_length + 1);
Packit 284210
            return -1;
Packit 284210
        }
Packit 284210
Packit 284210
        memset(msr->stream_output_data, 0, msr->stream_output_length+1);
Packit 284210
        memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length);
Packit 284210
        msr->stream_output_data[msr->stream_output_length] = '\0';
Packit 284210
    } else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_ENABLED)    {
Packit 284210
        int retval = 0;
Packit 284210
        apr_time_t time1 = apr_time_now();
Packit 284210
Packit 284210
        retval = init_response_body_html_parser(msr);
Packit 284210
Packit 284210
        if(retval == 1) {
Packit 284210
            retval = hash_response_body_links(msr);
Packit 284210
            if(retval > 0) {
Packit 284210
                retval = inject_hashed_response_body(msr, retval);
Packit 284210
                if(retval < 0){
Packit 284210
                    msr_log(msr, 1, "inject_hashed_response_body: Unable to inject hash into response body. Returning response without changes." );
Packit 284210
                }else{
Packit 284210
                    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                        msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1));
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        if(msr->of_stream_changed == 0) {
Packit 284210
            msr->stream_output_length = msr->resbody_length;
Packit 284210
Packit 284210
            if (msr->stream_output_data == NULL) {
Packit 284210
                msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT,
Packit 284210
                        msr->stream_output_length + 1);
Packit 284210
                return -1;
Packit 284210
            }
Packit 284210
Packit 284210
            memset(msr->stream_output_data, 0, msr->stream_output_length+1);
Packit 284210
            memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length);
Packit 284210
            msr->stream_output_data[msr->stream_output_length] = '\0';
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    return 1;
Packit 284210
}
Packit 284210
Packit 284210
/**
Packit 284210
 * Output filter.
Packit 284210
 */
Packit 284210
apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
Packit 284210
    request_rec *r = f->r;
Packit 284210
    modsec_rec *msr = (modsec_rec *)f->ctx;
Packit 284210
    apr_bucket *bucket = NULL, *eos_bucket = NULL;
Packit 284210
    apr_status_t rc;
Packit 284210
    int start_skipping = 0;
Packit 284210
Packit 284210
    /* Do we have the context? */
Packit 284210
    if (msr == NULL) {
Packit 284210
        ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
Packit 284210
                "ModSecurity: Internal Error: msr is null in output filter.");
Packit 284210
        ap_remove_output_filter(f);
Packit 284210
        return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
    }
Packit 284210
Packit 284210
    msr->r = r;
Packit 284210
Packit 284210
    if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
        msr_log(msr, 9, "Output filter: Receiving output (f %pp, r %pp).", f, f->r);
Packit 284210
    }
Packit 284210
Packit 284210
    /* Put back the Accept-Encoding and TE request headers
Packit 284210
     * if they were removed from the request.
Packit 284210
     */
Packit 284210
    if (msr->txcfg->disable_backend_compression) {
Packit 284210
        char *ae = (char *)apr_table_get(msr->request_headers, "Accept-Encoding");
Packit 284210
        char *te = (char *)apr_table_get(msr->request_headers, "TE");
Packit 284210
Packit 284210
        if ((ae != NULL)&&(apr_table_get(f->r->headers_in, "Accept-Encoding") == NULL)) {
Packit 284210
            apr_table_add(f->r->headers_in, "Accept-Encoding", ae);
Packit 284210
        }
Packit 284210
Packit 284210
        if ((te != NULL)&&(apr_table_get(f->r->headers_in, "TE") == NULL)) {
Packit 284210
            apr_table_add(f->r->headers_in, "TE", te);
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Initialise on first invocation */
Packit 284210
    if (msr->of_status == OF_STATUS_NOT_STARTED) {
Packit 284210
        /* Update our context from the request structure. */
Packit 284210
        msr->r = r;
Packit 284210
        msr->response_status = r->status;
Packit 284210
        msr->status_line = ((r->status_line != NULL)
Packit 284210
                ? r->status_line : ap_get_status_line(r->status));
Packit 284210
        msr->response_protocol = get_response_protocol(r);
Packit 284210
Packit 284210
        if(msr->txcfg->crypto_hash_location_rx == 1 || msr->txcfg->crypto_hash_location_pm == 1)
Packit 284210
            rc = modify_response_header(msr);
Packit 284210
Packit 284210
        msr->response_headers = apr_table_overlay(msr->mp, r->err_headers_out, r->headers_out);
Packit 284210
Packit 284210
        /* Process phase RESPONSE_HEADERS */
Packit 284210
        rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS);
Packit 284210
        if (rc < 0) { /* error */
Packit 284210
            ap_remove_output_filter(f);
Packit 284210
            return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
        }
Packit 284210
Packit 284210
        if (rc > 0) { /* transaction needs to be interrupted */
Packit 284210
            int status = perform_interception(msr);
Packit 284210
            if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                msr->of_status = OF_STATUS_COMPLETE;
Packit 284210
                msr->resbody_status = RESBODY_STATUS_ERROR;
Packit 284210
                return send_error_bucket(msr, f, status);
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        msr->outbound_error = 0;
Packit 284210
        /* Decide whether to observe the response body. */
Packit 284210
        rc = output_filter_init(msr, f, bb_in);
Packit 284210
        switch(rc) {
Packit 284210
            case -2 : /* response too large */
Packit 284210
            case -1 : /* error */
Packit 284210
                /* there's something wrong with this response */
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                msr->of_status = OF_STATUS_COMPLETE;
Packit 284210
                msr->resbody_status = RESBODY_STATUS_ERROR;
Packit 284210
                return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
            case 0 :
Packit 284210
                /* We do not want to observe this response body
Packit 284210
                 * but we need to remain attached to observe
Packit 284210
                 * when it is completed so that we can run
Packit 284210
                 * the RESPONSE_BODY phase.
Packit 284210
                 */
Packit 284210
                msr->of_skipping = 1;
Packit 284210
                msr->resbody_status = RESBODY_STATUS_NOT_READ;
Packit 284210
                break;
Packit 284210
            default :
Packit 284210
                /* Continue (observe the response body). */
Packit 284210
                break;
Packit 284210
        }
Packit 284210
Packit 284210
        /* If injecting content unset headers now. */
Packit 284210
        if (msr->txcfg->content_injection_enabled == 0) {
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Content Injection: Not enabled.");
Packit 284210
            }
Packit 284210
        } else {
Packit 284210
            if ((msr->content_prepend) || (msr->content_append)) {
Packit 284210
                apr_table_unset(msr->r->headers_out, "Content-Length");
Packit 284210
                apr_table_unset(msr->r->headers_out, "Last-Modified");
Packit 284210
                apr_table_unset(msr->r->headers_out, "ETag");
Packit 284210
                apr_table_unset(msr->r->headers_out, "Expires");
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Content Injection: Removing headers (C-L, L-M, Etag, Expires).");
Packit 284210
                }
Packit 284210
            } else {
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Content Injection: Nothing to inject.");
Packit 284210
                }
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* Content injection (prepend & non-buffering). */
Packit 284210
        if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) {
Packit 284210
            apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend,
Packit 284210
                    msr->content_prepend_len, NULL, f->r->connection->bucket_alloc);
Packit 284210
            APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci);
Packit 284210
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Content Injection (nb): Added content to top: %s",
Packit 284210
                        log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len));
Packit 284210
            }
Packit 284210
        }
Packit 284210
    } else
Packit 284210
        if (msr->of_status == OF_STATUS_COMPLETE) {
Packit 284210
            msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked.");
Packit 284210
            ap_remove_output_filter(f);
Packit 284210
            return APR_EGENERAL;
Packit 284210
        }
Packit 284210
Packit 284210
Packit 284210
    /* Loop through the buckets in the brigade in order
Packit 284210
     * to extract the size of the data available.
Packit 284210
     */
Packit 284210
    for(bucket = APR_BRIGADE_FIRST(bb_in);
Packit 284210
            bucket != APR_BRIGADE_SENTINEL(bb_in);
Packit 284210
            bucket = APR_BUCKET_NEXT(bucket)) {
Packit 284210
        const char *buf;
Packit 284210
        apr_size_t buflen;
Packit 284210
Packit 284210
        /* Look into response data if configured to do so,
Packit 284210
         * unless we've already processed a partial response.
Packit 284210
         */
Packit 284210
        if ((msr->of_skipping == 0)&&(!msr->of_partial)) { /* Observe the response data. */
Packit 284210
            /* Retrieve data from the bucket. */
Packit 284210
            rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ);
Packit 284210
            if (rc != APR_SUCCESS) {
Packit 284210
                msr->of_status = OF_STATUS_COMPLETE;
Packit 284210
                msr->resbody_status = RESBODY_STATUS_ERROR;
Packit 284210
Packit 284210
                msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s",
Packit 284210
                        rc, get_apr_error(r->pool, rc));
Packit 284210
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
            }
Packit 284210
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.",
Packit 284210
                        bucket->type->name, buflen);
Packit 284210
            }
Packit 284210
Packit 284210
            /* Check the response size. */
Packit 284210
            if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) {
Packit 284210
                /* The size of the response is larger than what we're
Packit 284210
                 * ready to accept. We need to decide what we want to do
Packit 284210
                 * about it.
Packit 284210
                 */
Packit 284210
                msr->outbound_error = 1;
Packit 284210
                if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) {
Packit 284210
                    /* Reject response. */
Packit 284210
                    msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, "
Packit 284210
                            "total not specified).", msr->txcfg->of_limit);
Packit 284210
Packit 284210
                    msr->of_status = OF_STATUS_COMPLETE;
Packit 284210
                    msr->resbody_status = RESBODY_STATUS_PARTIAL;
Packit 284210
Packit 284210
                    ap_remove_output_filter(f);
Packit 284210
                    return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
                } else {
Packit 284210
                    /* Process partial response. */
Packit 284210
                    start_skipping = 1;
Packit 284210
                    msr->resbody_length = msr->txcfg->of_limit;
Packit 284210
Packit 284210
                    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
                        msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)",
Packit 284210
                                msr->txcfg->of_limit);
Packit 284210
                    }
Packit 284210
                }
Packit 284210
            } else {
Packit 284210
                msr->resbody_length += buflen;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* Have we reached the end of the response? */
Packit 284210
        if (APR_BUCKET_IS_EOS(bucket)) {
Packit 284210
            eos_bucket = bucket;
Packit 284210
Packit 284210
            /* Inject content (append & non-buffering). */
Packit 284210
            if ((msr->txcfg->content_injection_enabled) && (msr->content_append)
Packit 284210
                    && (msr->of_skipping || msr->of_partial || start_skipping))
Packit 284210
            {
Packit 284210
                apr_bucket *bucket_ci = NULL;
Packit 284210
Packit 284210
                bucket_ci = apr_bucket_heap_create(msr->content_append,
Packit 284210
                        msr->content_append_len, NULL, f->r->connection->bucket_alloc);
Packit 284210
                APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci);
Packit 284210
Packit 284210
                if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                    msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s",
Packit 284210
                            log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            msr->of_done_reading = 1;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Add buckets in this brigade to the brigade
Packit 284210
     * we have in the context, but only if we actually
Packit 284210
     * want to keep the response body.
Packit 284210
     */
Packit 284210
    if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
Packit 284210
        ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp);
Packit 284210
Packit 284210
        /* Do we need to process a partial response? */
Packit 284210
        if (start_skipping) {
Packit 284210
Packit 284210
            if (msr->txcfg->stream_outbody_inspection)  {
Packit 284210
                if(msr->stream_output_data != NULL) {
Packit 284210
                    free(msr->stream_output_data);
Packit 284210
                    msr->stream_output_data = NULL;
Packit 284210
                }
Packit 284210
Packit 284210
                msr->stream_output_data = (char *)malloc(msr->resbody_length+1);
Packit 284210
            }
Packit 284210
Packit 284210
            if (flatten_response_body(msr) < 0) {
Packit 284210
                if (msr->txcfg->stream_outbody_inspection)  {
Packit 284210
                    if(msr->stream_output_data != NULL) {
Packit 284210
                        free(msr->stream_output_data);
Packit 284210
                        msr->stream_output_data = NULL;
Packit 284210
                    }
Packit 284210
                }
Packit 284210
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
            }
Packit 284210
Packit 284210
            /* Process phase RESPONSE_BODY */
Packit 284210
            rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
Packit 284210
            if (rc < 0) {
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
            }
Packit 284210
            if (rc > 0) {
Packit 284210
                int status = perform_interception(msr);
Packit 284210
                if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
Packit 284210
                    ap_remove_output_filter(f);
Packit 284210
                    return send_error_bucket(msr, f, status);
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            /* Prepend content as necessary. */
Packit 284210
            prepend_content_to_of_brigade(msr, f);
Packit 284210
Packit 284210
            if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
Packit 284210
                return rc;
Packit 284210
            }
Packit 284210
Packit 284210
            msr->of_partial = 1;
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->of_done_reading == 0) {
Packit 284210
            /* We are done for now. We will be called again with more data. */
Packit 284210
            return APR_SUCCESS;
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).",
Packit 284210
                    (msr->of_partial ? "partial" : "full"), msr->resbody_length);
Packit 284210
        }
Packit 284210
    } else { /* Not looking at response data. */
Packit 284210
        if (msr->of_done_reading == 0) {
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Output filter: Sending input brigade directly.");
Packit 284210
            }
Packit 284210
Packit 284210
            return ap_pass_brigade(f->next, bb_in);
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
            msr_log(msr, 4, "Output filter: Completed receiving response body (non-buffering).");
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* We've done our thing; remove us from the filter list. */
Packit 284210
    msr->of_status = OF_STATUS_COMPLETE;
Packit 284210
    ap_remove_output_filter(f);
Packit 284210
Packit 284210
    /* Process phase RESPONSE_BODY, but
Packit 284210
     * only if it hasn't been processed already.
Packit 284210
     */
Packit 284210
    if (msr->phase < PHASE_RESPONSE_BODY) {
Packit 284210
Packit 284210
        if (msr->txcfg->stream_outbody_inspection)  {
Packit 284210
            if(msr->stream_output_data != NULL) {
Packit 284210
                free(msr->stream_output_data);
Packit 284210
                msr->stream_output_data = NULL;
Packit 284210
            }
Packit 284210
Packit 284210
            msr->stream_output_data = (char *)malloc(msr->resbody_length+1);
Packit 284210
        }
Packit 284210
Packit 284210
        if (flatten_response_body(msr) < 0) {
Packit 284210
            if (msr->txcfg->stream_outbody_inspection)  {
Packit 284210
                if(msr->stream_output_data != NULL) {
Packit 284210
                    free(msr->stream_output_data);
Packit 284210
                    msr->stream_output_data = NULL;
Packit 284210
                }
Packit 284210
            }
Packit 284210
Packit 284210
            ap_remove_output_filter(f);
Packit 284210
            return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
        }
Packit 284210
Packit 284210
        rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY);
Packit 284210
        if (rc < 0) {
Packit 284210
            ap_remove_output_filter(f);
Packit 284210
            return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR);
Packit 284210
        }
Packit 284210
        if (rc > 0) {
Packit 284210
            int status = perform_interception(msr);
Packit 284210
            if (status != DECLINED) { /* DECLINED means we allow-ed the request. */
Packit 284210
                ap_remove_output_filter(f);
Packit 284210
                return send_error_bucket(msr, f, status);
Packit 284210
            }
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Now send data down the filter stream
Packit 284210
     * (full-buffering only).
Packit 284210
     */
Packit 284210
    if ((msr->of_skipping == 0)&&(!msr->of_partial)) {
Packit 284210
        if(msr->of_stream_changed == 1) {
Packit 284210
            inject_content_to_of_brigade(msr,f);
Packit 284210
            msr->of_stream_changed = 0;
Packit 284210
        }
Packit 284210
Packit 284210
        if (msr->txcfg->stream_outbody_inspection)  {
Packit 284210
            if(msr->stream_output_data != NULL) {
Packit 284210
                free(msr->stream_output_data);
Packit 284210
                msr->stream_output_data = NULL;
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        prepend_content_to_of_brigade(msr, f);
Packit 284210
Packit 284210
        /* Inject content into response (append & buffering). */
Packit 284210
        if ((msr->txcfg->content_injection_enabled) && (msr->content_append)) {
Packit 284210
            apr_bucket *bucket_ci = NULL;
Packit 284210
Packit 284210
            bucket_ci = apr_bucket_heap_create(msr->content_append,
Packit 284210
                    msr->content_append_len, NULL, f->r->connection->bucket_alloc);
Packit 284210
            APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci);
Packit 284210
Packit 284210
            if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
                msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s",
Packit 284210
                        log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len));
Packit 284210
            }
Packit 284210
        }
Packit 284210
Packit 284210
        /* Send data down the filter stream. */
Packit 284210
        if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) {
Packit 284210
            return rc;
Packit 284210
        }
Packit 284210
    }
Packit 284210
Packit 284210
    /* Another job well done! */
Packit 284210
    if (msr->txcfg->debuglog_level >= 4) {
Packit 284210
        msr_log(msr, 4, "Output filter: Output forwarding complete.");
Packit 284210
    }
Packit 284210
Packit 284210
    if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) {
Packit 284210
        return APR_SUCCESS;
Packit 284210
    } else {
Packit 284210
        if (msr->txcfg->debuglog_level >= 9) {
Packit 284210
            msr_log(msr, 9, "Output filter: Sending input brigade directly.");
Packit 284210
        }
Packit 284210
Packit 284210
        return ap_pass_brigade(f->next, bb_in);
Packit 284210
    }
Packit 284210
}