From accb1820e058dc97c666c384afa697a906d372ec Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Wed, 4 Dec 2013 23:38:24 -0800 Subject: [PATCH] Adds collection FILES_TMP_CONTENT The collection is filled with a key-value set where value is the content of the file which was uploaded. This collection can be used with all supported operators, however SecUploadKeepFiles should be set to 'On' in order to have this collection filled. --- apache2/apache2_config.c | 37 ++++++++++++-- apache2/re_variables.c | 102 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 1fa8669b..30ba91fe 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -912,11 +912,6 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, } } - /* Optimisation */ - if ((rule->op_name != NULL)&&(strcasecmp(rule->op_name, "inspectFile") == 0)) { - dcfg->upload_validates_files = 1; - } - /* Create skip table if one does not already exist. */ if (dcfg->tmp_rule_placeholders == NULL) { dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10); @@ -2449,6 +2444,30 @@ static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, return NULL; } +static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + { + dcfg->upload_validates_files = 1; + } + else if (strcasecmp(p1, "off") == 0) + { + dcfg->upload_validates_files = 0; + } + else + { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecTmpSaveUploadedFiles: %s", + p1); + } + + return NULL; +} + static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = (directory_config *)_dcfg; @@ -3685,6 +3704,14 @@ const command_rec module_directives[] = { "On or Off" ), + AP_INIT_TAKE1 ( + "SecTmpSaveUploadedFiles", + cmd_upload_save_tmp_files, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + AP_INIT_TAKE1 ( "SecWebAppId", cmd_web_app_id, diff --git a/apache2/re_variables.c b/apache2/re_variables.c index ebccf9eb..d728f5f4 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1113,6 +1113,97 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule return count; } +/* FILES_TMP_CONTENT */ + +static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, + msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for (i = 0; i < msr->mpd->parts->nelts; i++) + { + if ((parts[i]->type == MULTIPART_FILE) && + (parts[i]->tmp_file_name != NULL)) + { + int match = 0; + + /* Figure out if we want to include this variable. */ + if (var->param == NULL) + { + match = 1; + } + else + { + if (var->param_data != NULL) + { + /* Regex. */ + char *my_error_msg = NULL; + if (!(msc_regexec((msc_regex_t *)var->param_data, + parts[i]->name, strlen(parts[i]->name), + &my_error_msg) == PCRE_ERROR_NOMATCH)) + { + match = 1; + } + } + else + { + /* Simple comparison. */ + if (strcasecmp(parts[i]->name, var->param) == 0) + { + match = 1; + } + } + } + /* If we had a match add this argument to the collection. */ + if (match) { + static int buf_size = 1024; + char buf[buf_size]; + FILE *file; + size_t nread; + char *full_content = NULL; + size_t total_lenght = 0; + + file = fopen(parts[i]->tmp_file_name, "r"); + if (file == NULL) + { + continue; + } + + while ((nread = fread(buf, 1, buf_size-1, file)) > 0) + { + total_lenght += nread; + buf[nread] = '\0'; + if (full_content == NULL) + { + full_content = apr_psprintf(mptmp, "%s", buf); + } + else + { + full_content = apr_psprintf(mptmp, "%s%s", full_content, buf); + } + } + fclose(file); + + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + rvar->value = full_content; + rvar->value_len = total_lenght; + rvar->name = apr_psprintf(mptmp, "FILES_TMP_CONTENT:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + } + + return count; +} + + /* FILES_TMPNAMES */ static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, @@ -2854,6 +2945,17 @@ void msre_engine_register_default_variables(msre_engine *engine) { PHASE_REQUEST_BODY ); + /* FILES_TMP_CONTENT */ + msre_engine_variable_register(engine, + "FILES_TMP_CONTENT", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_files_tmp_contents_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + /* GEO */ msre_engine_variable_register(engine, "GEO",