From f0112604a6b9f4af393389bda50bb3f504e68cfa Mon Sep 17 00:00:00 2001 From: Michael Bunk <bunk@iat.uni-leipzig.de> Date: Mon, 9 Feb 2015 12:05:48 +0100 Subject: [PATCH 001/477] Remove misguided call to srand() A random number generator needs to be initialized once per process after a fork, but not after each request, more so with an argument that changes only once per second. This fixes SpiderLabs#778 This is a copy of my commit deec149ca363dd14213afd1f9d7f71a71959ef31. --- apache2/modsecurity.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index da89faa7a2..5bda4cff82 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -237,8 +237,6 @@ static void modsecurity_persist_data(modsec_rec *msr) { } /* Remove stale collections. */ - srand(time(NULL)); - if (rand() < RAND_MAX/100) { arr = apr_table_elts(msr->collections); te = (apr_table_entry_t *)arr->elts; From fdcab3a60d4175f3a66792e84a4b2e0b3b7507de Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 16 Oct 2015 11:13:56 -0300 Subject: [PATCH 002/477] Adds information about the issue #836 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 031648e4d5..b67b413f64 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Remove misguided call to srand() + [Issues #778, #781 and #836 - Michael Bunk, @gilperon] * Fix compilation problem while ssdeep is installed in non-standard location. [Issude #872 - Kurt Newman] From 7ba07bd5476bd90d63079df9015ec7d9772a4f60 Mon Sep 17 00:00:00 2001 From: Eugene Alekseev <ealekseev@hostcomm.ru> Date: Mon, 14 Sep 2015 16:47:19 +0300 Subject: [PATCH 003/477] Fix buffer overflow on empty strings in key. Sometimes apache segfalult on memory copying when key.dptr is some kind of empty string and key.dsize seems to be 0. --- apache2/persist_dbm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index b698e7913f..42123f8c18 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -626,7 +626,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { */ rc = apr_sdbm_firstkey(dbm, &key); while(rc == APR_SUCCESS) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + char *s = apr_pstrmemdup(msr->mp, key.dptr, strlen(key.dptr)); *(char **)apr_array_push(keys_arr) = s; rc = apr_sdbm_nextkey(dbm, &key); } From 198032208a2e6ca6f0520fcc021b787f0fef37b8 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 26 Oct 2015 13:49:05 -0300 Subject: [PATCH 004/477] Improves #927 by checking earlier if the string is empty or not --- apache2/persist_dbm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 42123f8c18..76c3820baf 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -626,8 +626,10 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { */ rc = apr_sdbm_firstkey(dbm, &key); while(rc == APR_SUCCESS) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, strlen(key.dptr)); - *(char **)apr_array_push(keys_arr) = s; + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } rc = apr_sdbm_nextkey(dbm, &key); } apr_sdbm_unlock(dbm); From 18d79b62211cb65987beb5c35abe929dca724ca1 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 26 Oct 2015 13:55:17 -0300 Subject: [PATCH 005/477] Adds information about the issue #927 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index b67b413f64..470a9fc6db 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Fix crash while adding empty keys to persistent collections. + [Issues #927 - Eugene Alekseev, Marc Stern and ModSecurity team] * Remove misguided call to srand() [Issues #778, #781 and #836 - Michael Bunk, @gilperon] * Fix compilation problem while ssdeep is installed in non-standard From 6d458be8ca8b528db23e09ef8a0247448c80fc7d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 27 Oct 2015 14:03:45 -0300 Subject: [PATCH 006/477] Fix typo in CHANGES file --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 470a9fc6db..0564f80f45 100644 --- a/CHANGES +++ b/CHANGES @@ -2,12 +2,12 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ * Fix crash while adding empty keys to persistent collections. - [Issues #927 - Eugene Alekseev, Marc Stern and ModSecurity team] + [Issue #927 - Eugene Alekseev, Marc Stern and ModSecurity team] * Remove misguided call to srand() [Issues #778, #781 and #836 - Michael Bunk, @gilperon] * Fix compilation problem while ssdeep is installed in non-standard location. - [Issude #872 - Kurt Newman] + [Issue #872 - Kurt Newman] * Fix invalid storage reference by apr_psprintf at msc_crypt.c [Issue #609 - Jeff Trawick] From 3044ad012b7fe0b417374bd032dc183b50ab4fbc Mon Sep 17 00:00:00 2001 From: Andrew Elble <aweits@rit.edu> Date: Thu, 30 Apr 2015 12:03:42 -0400 Subject: [PATCH 007/477] Fix the variable resolution duration (Issue #662) apr_time_usec is apparently defined as follows: Which leads DURATION to not behave as expected when duration exceeds one second. --- apache2/re_variables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index b83af1c605..c69085feef 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1828,7 +1828,7 @@ static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); rvar->value = apr_psprintf(mptmp, "%" APR_TIME_T_FMT, - (apr_time_usec(apr_time_now() - msr->r->request_time))); + (apr_time_now() - msr->r->request_time)); rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); From 2e7ae24b16ec84723ee556d238047e7dd671cf30 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 27 Oct 2015 14:39:20 -0300 Subject: [PATCH 008/477] Adds information about the issue #662 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 0564f80f45..03e4a283af 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Fix variable resolution duration (Content of the DURATION variable). + [Issue #662 - Andrew Elble] * Fix crash while adding empty keys to persistent collections. [Issue #927 - Eugene Alekseev, Marc Stern and ModSecurity team] * Remove misguided call to srand() From 9dbb31b6ce1a96c9da50bb1e9c8b56b9c5c54d43 Mon Sep 17 00:00:00 2001 From: Kurt Newman <kurt.newman@cpanel.net> Date: Tue, 5 May 2015 16:04:23 -0500 Subject: [PATCH 009/477] Fix WITH_APU_CRYPTO check on 32-bit Linux platform All of the apr flags needed to compile APU_HAVE_CRYPTO check in configure.ac aren't passed. While this works fine for 64-bit machines (because _LARGEFILE64_SOURCE is already defined), this does not work on 32-bit. This in-turn breaks the apr_off_t definition in apr.h. By passing along the apr --cflags and --cppflags to compile, 32-bit machines will allow WITH_APU_CRYPTO to be set if there's support for it. --- CHANGES | 2 ++ configure.ac | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 03e4a283af..becf7acb14 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Fix apr_crypto.h check on 32-bit Linux platform + [Issue #882 - Kurt Newman] * Fix variable resolution duration (Content of the DURATION variable). [Issue #662 - Andrew Elble] * Fix crash while adding empty keys to persistent collections. diff --git a/configure.ac b/configure.ac index f00172a771..7517885893 100644 --- a/configure.ac +++ b/configure.ac @@ -712,7 +712,12 @@ CHECK_YAJL() CHECK_SSDEEP() #AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy]) -CFLAGS="$CFLAGS $APU_CFLAGS" +# Temporarily set cflags for apr_crypto check, then restore +# since it's already used correctly to compile modsecurity module. +ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" +ORIG_CPPFLAGS="$CPPFLAGS" +CFLAGS="$CFLAGS $APR_CFLAGS" +CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" AC_TRY_COMPILE( [#include <apr_crypto.h>], [ @@ -725,6 +730,10 @@ AC_TRY_COMPILE( ], [ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ] ) +# Restore env vars so that we don't clutter with duplicates that +# are eventually appended later on +CFLAGS="$ORIG_CFLAGS" +CPPFLAGS="$ORIG_CPPFLAGS" # Current our unique download backend is curl, furhter we can support more. if test ! -z "${CURL_VERSION}"; then From fecefbe8b4fc628dfef9ebff0317bfb9fd871078 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 30 Oct 2015 14:03:19 -0300 Subject: [PATCH 010/477] Adds information about the issue #883 on the CHANGES file --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index becf7acb14..7b042994c2 100644 --- a/CHANGES +++ b/CHANGES @@ -2,7 +2,7 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ * Fix apr_crypto.h check on 32-bit Linux platform - [Issue #882 - Kurt Newman] + [Issue #882, #883 - Kurt Newman] * Fix variable resolution duration (Content of the DURATION variable). [Issue #662 - Andrew Elble] * Fix crash while adding empty keys to persistent collections. From 76dfc1a90b2b191426171a0953f7424331106880 Mon Sep 17 00:00:00 2001 From: vfolin <email_github.com@tikon.ch> Date: Mon, 16 Feb 2015 12:52:52 +0100 Subject: [PATCH 011/477] Fix apache logging limitation by using correct apache call. Apache 2.4 brought the option to change the ErrorLogFormat. However, many fields remain empty, as ModSecurity uses the wrong apache logging function. This fixes this behaviour with the use of ap_log_rerror. --- apache2/apache2_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index 0960dc8e63..ed5b0ba216 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -268,7 +268,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * else hostname = ""; #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, + ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1, hostname, log_escape(msr->mp, r->uri), unique_id); #else From 8f3bc3cbac6222c6fec6d905c6023999fe0a5a92 Mon Sep 17 00:00:00 2001 From: Christian Folini <email_github.com@tikon.ch> Date: Mon, 30 Nov 2015 14:40:06 +0100 Subject: [PATCH 012/477] Introduced ap_log_rerror declaration to standalone/server.c --- standalone/server.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/standalone/server.c b/standalone/server.c index 53beccf9bf..05b3bf3ac4 100644 --- a/standalone/server.c +++ b/standalone/server.c @@ -285,6 +285,31 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index, modsecLogHook(modsecLogObj, level, errstr); } +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 +AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level, + apr_status_t status, const request_rec *r, + const char *fmt, ...) +// __attribute__((format(printf,6,7))) +#else +AP_DECLARE(void) ap_log_rerror_(const char *file, int line, int module_index, + int level, apr_status_t status, + const request_rec *r, const char *fmt, ...) +// __attribute__((format(printf,7,8))) +#endif +{ + va_list args; + char errstr[MAX_STRING_LEN]; + + va_start(args, fmt); + + apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args); + + va_end(args); + + if(modsecLogHook != NULL) + modsecLogHook(modsecLogObj, level, errstr); +} + #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 AP_DECLARE(void) ap_log_perror(const char *file, int line, int level, apr_status_t status, apr_pool_t *p, From 8defe8ac3d720dcfbb23b2f0fae41ede872a14f3 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 22 Oct 2015 18:09:32 -0300 Subject: [PATCH 013/477] Adds information about the pull request #840 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 7b042994c2..6690f6cfa6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Fix apache logging limitation by using correct apache call. + [Issue #840 - Christian Folini] * Fix apr_crypto.h check on 32-bit Linux platform [Issue #882, #883 - Kurt Newman] * Fix variable resolution duration (Content of the DURATION variable). From 51f1ff6ebf20c5f40d39baddb574993cefa13a46 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 28 Sep 2015 13:03:32 -0300 Subject: [PATCH 014/477] iis-installer: Adds IIS 10 on the suported list As reported on issue #931 the installer was marking ModSecurity as incompatible with IIS 10. --- CHANGES | 2 ++ iis/installer.wxs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 6690f6cfa6..aa3f1a041a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Understands IIS 10 as compatible on Windows installer. + [Issue #931 - Anton Serbulov, Pavel Vasilevich and ModSecurity team] * Fix apache logging limitation by using correct apache call. [Issue #840 - Christian Folini] * Fix apr_crypto.h check on 32-bit Linux platform diff --git a/iis/installer.wxs b/iis/installer.wxs index 51f4878b14..49d2e5e42a 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -91,7 +91,7 @@ <RegistrySearch Id="FindInetPubFolder" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="PathWWWRoot" Type="directory" /> </Property> <Property Id="MSIUSEREALADMINDETECTION" Value="1" /> - <Condition Message="This setup requires IIS 7.0 or 8.0."><![CDATA[(IIS="#7") OR (IIS="#8")]]></Condition> + <Condition Message="This setup requires IIS 7.0 or 8.0."><![CDATA[(IIS="#7") OR (IIS="#8") OR (IIS="#10")]]></Condition> <!-- Version 2.7.5 had an uninstall issue that leaves some files behind. Asking the user to manually hash this out. --> <Condition Message="A older version of ModSecurityIIS was found in your computer. Please complete uninstall by removing the following file: [FILEEXISTS]. You may have to remove ModSecurity module from IIS, use the IIS Manager to do so."><![CDATA[(NOT FILEEXISTS) OR (Installed)]]></Condition> <Condition Message="64-bit operating system was detected, please use the 64-bit installer."> From b3ce3da2fc1c19e998ba850751d4deb2d8e23d8a Mon Sep 17 00:00:00 2001 From: Elia Pinto <elia.pinto@gmail.com> Date: Fri, 26 Sep 2014 06:52:45 -0700 Subject: [PATCH 015/477] mlogc-batch-load.pl.in: fix searching SecAuditLogStorageDir files with Apache 2.4 Setting SecAuditLogType concurrent the files created by modsecurity in the directory SecAuditLogStorageDir are of the type %Y%m%d-%H%M%S-UNIQUE_ID where UNIQUE_ID is produced by the module mod_unique_id. In apache 2.2 UNIQUE_ID was 24 characters long while in apache 2.4 is 27 characters long, as a result of the new version of mod_unique_id. This patch extends the regular expression for searching these log files for apache 2.4 and apache 2.2, and also with future releases, at least with regard to the length of UNIQUE_ID Signed-off-by: Elia Pinto <elia.pinto@gmail.com> --- mlogc/mlogc-batch-load.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlogc/mlogc-batch-load.pl.in b/mlogc/mlogc-batch-load.pl.in index 53da8786a7..60030771db 100755 --- a/mlogc/mlogc-batch-load.pl.in +++ b/mlogc/mlogc-batch-load.pl.in @@ -38,7 +38,7 @@ find( (($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size) = stat($_)) && -f _ && #### MODSEC-204 /^\d{8}-\d+-\w{24}$/s - /^\d{8}-\d+-.{24}$/s + /^\d{8}-\d+-.{24,}$/s && (($fn = $File::Find::name) =~ s/^\Q$ROOTDIR\E//) && push(@AUDIT, [$fn, $size]); }, From c373256d467ef48f0a7d83f243ec53d492018e49 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 4 Jan 2016 15:02:31 -0300 Subject: [PATCH 016/477] Adds information about the pull request #775 on the CHANGES file --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index aa3f1a041a..de1448f8dd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * mlogc-batch-load.pl.in: fix searching SecAuditLogStorageDir + files with Apache 2.4 + [Issue #775 - Elia Pinto] * Understands IIS 10 as compatible on Windows installer. [Issue #931 - Anton Serbulov, Pavel Vasilevich and ModSecurity team] * Fix apache logging limitation by using correct apache call. From 3a7fdf8fc037f6ebfe5fd20d70432a9af1a38250 Mon Sep 17 00:00:00 2001 From: Wesley M <wesleymr.27@gmail.com> Date: Tue, 8 Dec 2015 23:26:26 -0300 Subject: [PATCH 017/477] Refactoring conditional directives for if wrappers, alternative if statements and incomplete if conditions. --- apache2/apache2_config.c | 25 ++++++++++++++----------- apache2/mod_security2.c | 13 +++++++------ standalone/config.c | 11 ++++++----- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index bfbcb83468..bad5c5dc79 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -755,6 +755,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, char *rid = NULL; msre_rule *rule = NULL; extern msc_engine *modsecurity; + int type_with_lua = 1; + int type_rule; + int rule_actionset; int offset = 0; #ifdef DEBUG_CONF @@ -787,25 +790,25 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, } /* Rules must have uniq ID */ - if ( + type_rule = (dcfg->tmp_chain_starter == NULL); #if defined(WITH_LUA) - type != RULE_TYPE_LUA && + type_rule = (type != RULE_TYPE_LUA && type_rule); #endif - (dcfg->tmp_chain_starter == NULL)) + if (type_rule) if(rule->actionset == NULL) return "ModSecurity: Rules must have at least id action"; if(rule->actionset != NULL && (dcfg->tmp_chain_starter == NULL)) { - if(rule->actionset->id == NOT_SET_P + rule_actionset = (rule->actionset->id == NOT_SET_P); #if defined(WITH_LUA) - && (type != RULE_TYPE_LUA) + rule_actionset = (rule_actionset && (type != RULE_TYPE_LUA)); #endif - ) - return "ModSecurity: No action id present within the rule"; + if (rule_actionset) + return "ModSecurity: No action id present within the rule"; #if defined(WITH_LUA) - if(type != RULE_TYPE_LUA) + type_with_lua = (type != RULE_TYPE_LUA); #endif - { + if (type_with_lua){ rid = apr_hash_get(dcfg->rule_id_htab, rule->actionset->id, APR_HASH_KEY_STRING); if(rid != NULL) { return "ModSecurity: Found another rule with the same id"; @@ -1666,7 +1669,7 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, } char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, - TreeRoot **whitelist, TreeRoot **suspicious_list, + TreeRoot **whitelist, TreeRoot **suspicious_list, const char *filename) { int res = 0; @@ -1753,7 +1756,7 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, if (param) return param; } - + conn_read_state_limit = limit; return NULL; diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 519f2cc8db..5404fd8744 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1086,6 +1086,7 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s { modsec_rec *msr = NULL; error_message_t *em = NULL; + int msr_ap_server; #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 if (info == NULL) return; @@ -1102,15 +1103,15 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s /* Create a context for requests we never had the chance to process */ #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - if ((msr == NULL) + msr_ap_server = ((msr == NULL) && ((info->level & APLOG_LEVELMASK) < APLOG_DEBUG) - && apr_table_get(info->r->subprocess_env, "UNIQUE_ID")) + && apr_table_get(info->r->subprocess_env, "UNIQUE_ID")); #else - if ((msr == NULL) + msr_ap_server = ((msr == NULL) && ((level & APLOG_LEVELMASK) < APLOG_DEBUG) - && apr_table_get(r->subprocess_env, "UNIQUE_ID")) + && apr_table_get(r->subprocess_env, "UNIQUE_ID")); #endif - { + if (msr_ap_server) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 msr = create_tx_context((request_rec *)info->r); #else @@ -1484,7 +1485,7 @@ static int hook_connection_early(conn_rec *conn) conn_read_state_suspicious_list, client_ip, NULL, &error_msg) <= 0)) { if (conn_limits_filter_state == MODSEC_DETECTION_ONLY) - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Too many threads [%ld] of %ld allowed " \ "in READ state from %s - There is a suspission list " \ "but that IP is not part of it, access granted", diff --git a/standalone/config.c b/standalone/config.c index 1552c6fabf..800d5b4344 100644 --- a/standalone/config.c +++ b/standalone/config.c @@ -432,6 +432,7 @@ AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, apr_file_t *file = NULL; apr_finfo_t finfo; apr_status_t status; + int exist_type; #ifdef DEBUG char buf[120]; #endif @@ -457,13 +458,13 @@ AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, if (status != APR_SUCCESS) return status; - if (finfo.filetype != APR_REG && + exist_type = (finfo.filetype != APR_REG); #if defined(WIN32) || defined(OS2) || defined(NETWARE) - strcasecmp(apr_filepath_name_get(name), "nul") != 0) { + exist_type = (exist_type && strcasecmp(apr_filepath_name_get(name), "nul") != 0); #else - strcmp(name, "/dev/null") != 0) { + exist_type = (exist_type && strcmp(name, "/dev/null") != 0); #endif /* WIN32 || OS2 */ - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, + if (exist_type){ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Access to file %s denied by server: not a regular file", name); apr_file_close(file); @@ -503,7 +504,7 @@ AP_DECLARE(apr_status_t) ap_pcfg_openfile(ap_configfile_t **ret_cfg, #else new_cfg->getch = cfg_getch; new_cfg->getstr = cfg_getstr; - new_cfg->close = cfg_close; + new_cfg->close = cfg_close; #endif new_cfg->line_number = 0; *ret_cfg = new_cfg; From 59851fff2b98abece45b63aee10d0680e13486f4 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 9 Dec 2015 10:06:00 -0300 Subject: [PATCH 018/477] Adds information about the issue #996 on the CHANGES file --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index de1448f8dd..21d6fc5c57 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Refactoring conditional directives for if wrappers, alternative if + statements and incomplete if conditions. + [Issue #996 - Wesley M and ModSecurity team] * mlogc-batch-load.pl.in: fix searching SecAuditLogStorageDir files with Apache 2.4 [Issue #775 - Elia Pinto] From 258e5545a2ba4a064004ccfedba015c1904cbdaa Mon Sep 17 00:00:00 2001 From: "Mario D. Santana" <mds@mariosantana.net> Date: Tue, 15 Dec 2015 16:03:45 -0700 Subject: [PATCH 019/477] Perform the intercept_action as well as the disruptive actions. --- apache2/re.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apache2/re.c b/apache2/re.c index 1d843e21c1..7e0a238c63 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2513,6 +2513,11 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, } } } + if (actionset->intercept_action_rec->metadata->type == ACTION_DISRUPTIVE) { + if (actionset->intercept_action_rec->metadata->execute != NULL) { + actionset->intercept_action_rec->metadata->execute(msr, mptmp, rule, actionset->intercept_action_rec); + } + } /* If "noauditlog" was used do not mark the transaction relevant. */ if (actionset->auditlog != 0) { From e3b3721ee379dd8251cec97f5e588456cf5ee420 Mon Sep 17 00:00:00 2001 From: "Mario D. Santana" <mds@mariosantana.net> Date: Tue, 15 Dec 2015 16:04:20 -0700 Subject: [PATCH 020/477] Allow mod_proxy's "nocanon" behavior to be specified in proxy actions. --- apache2/re_actions.c | 7 ++++- .../regression/action/00-disruptive-actions.t | 31 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index e06ebe65c2..aaf33817e2 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -664,7 +664,12 @@ static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp var = apr_pcalloc(mptmp, sizeof(msc_string)); if (var == NULL) return -1; - var->value = (char *)action->param; + if (!strncmp(action->param,"[nocanon]",9)) { + apr_table_setn(msr->r->notes,"proxy-nocanon",1); + var->value = (char *)action->param+9; + } else { + var->value = (char *)action->param; + } var->value_len = strlen(var->value); expand_macros(msr, var, rule, mptmp); diff --git a/tests/regression/action/00-disruptive-actions.t b/tests/regression/action/00-disruptive-actions.t index 15c9836d88..f682396ee9 100644 --- a/tests/regression/action/00-disruptive-actions.t +++ b/tests/regression/action/00-disruptive-actions.t @@ -474,6 +474,37 @@ GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", ), }, +{ + type => "action", + comment => "nocanon proxy in phase:1 (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecRule REQUEST_URI "\@streq /test2.txt" "phase:1,proxy:'[nocanon]http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt',id:500005" + ), + match_log => { + error => { + apache => [qr/ModSecurity: Access denied using proxy to \(phase 1\)/, 1], + nginx => [qr/ModSecurity: Access denied with code 500 \(phase 1\) \(Configuration Error: Proxy action to .* requested but proxy is only available in Apache version\)./, 1], + }, + }, + match_response => { + status => { + apache => qr/^200$/, + nginx => qr/^500$/, + }, + content => { + apache => qr/^TEST$/, + nginx => qr/^*$/, + }, + }, + + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test2.txt", + ), +}, { type => "action", comment => "proxy in phase:2 (get)", From c711808ef73a16df830cebf3e381846510942ed3 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 6 Jan 2016 08:24:48 -0300 Subject: [PATCH 021/477] Cosmetic changes on #1031 to avoid compilation warning --- apache2/re_actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index aaf33817e2..504cc24053 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -665,7 +665,7 @@ static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp var = apr_pcalloc(mptmp, sizeof(msc_string)); if (var == NULL) return -1; if (!strncmp(action->param,"[nocanon]",9)) { - apr_table_setn(msr->r->notes,"proxy-nocanon",1); + apr_table_setn(msr->r->notes,"proxy-nocanon", "1"); var->value = (char *)action->param+9; } else { var->value = (char *)action->param; From 831282ee2c4107c4823063b25f28b4e1d648ffaf Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 6 Jan 2016 08:27:40 -0300 Subject: [PATCH 022/477] Adds information about the pull request #1031 on the CHANGES file --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 21d6fc5c57..675989b0d5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Allow mod_proxy's "nocanon" behavior to be specified in proxy actions + and Perform the intercept_action as well as the disruptive actions. + [Issue #1031, #961, #763 - Mario D. Santana and ModSecurity team] * Refactoring conditional directives for if wrappers, alternative if statements and incomplete if conditions. [Issue #996 - Wesley M and ModSecurity team] From bd7ee39d2eb614bdec75cec5ca5569ca52ca3609 Mon Sep 17 00:00:00 2001 From: Ishwor Gurung <isg@email.badbug.id.au> Date: Sun, 3 May 2015 16:59:59 +1000 Subject: [PATCH 023/477] Allow user to choose between TLS versions(TLSProtocol option introduced). --- mlogc/mlogc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c index e67da10850..e650452dc4 100644 --- a/mlogc/mlogc.c +++ b/mlogc/mlogc.c @@ -158,6 +158,8 @@ static apr_pool_t *recv_pool = NULL; static apr_array_header_t *queue = NULL; static const char *queue_path = NULL; static int ssl_validation = 0; +static int tlsprotocol = 1; +static curl_version_info_data* curlversion = NULL; /* static apr_time_t queue_time = 0; */ static void *requestline_regex = NULL; static int running = 0; @@ -810,6 +812,26 @@ static void init_configuration(void) startup_delay = atoi(s); } + /* TLS Protocol - TLSv1(0) TLSv1.1(1) TLSv1.2(2) (SSLv3 not supported) */ + s = apr_table_get(conf, "TLSProtocol"); + if (s != NULL) { + int num = atoi(s); + switch (num) { + case 0: + tlsprotocol = 0; + break; + case 1: + tlsprotocol = 1; + break; + case 2: + tlsprotocol = 2; + break; + default: + tlsprotocol = 2; /* Default is TLSv1.2 */ + } + } + curlversion = curl_version_info(CURLVERSION_NOW); + if ( startup_delay > 0 ) { error_log(LOG_NOTICE, NULL, "Delaying execution for %dms.", startup_delay); @@ -824,6 +846,8 @@ static void init_configuration(void) error_log(LOG_DEBUG2, NULL, "ErrorLog=%s", error_log_path); error_log(LOG_DEBUG2, NULL, "ErrorLogLevel=%d", error_log_level); error_log(LOG_DEBUG2, NULL, "StartupDelay=%d", startup_delay); + error_log(LOG_DEBUG2, NULL, "TLSProtocol=%d", tlsprotocol); + error_log(LOG_DEBUG2, NULL, "cURL version=%s", curlversion->version); s = apr_table_get(conf, "CheckpointInterval"); if (s != NULL) { @@ -1182,6 +1206,8 @@ static void logc_init(void) apr_status_t rc = 0; const char *errptr = NULL; int i, erroffset; + /* cURL major, minor and patch version */ + short cmaj, cmin, cpat = 0; queue = apr_array_make(pool, 64, sizeof(entry_t *)); if (queue == NULL) { @@ -1246,8 +1272,31 @@ static void logc_init(void) /* Seems like CURL_SSLVERSION_TLSv1_2 is not supported on libcurl * < v7.34.0 + * + * version_num is a 24 bit number created like this: + * <8 bits major number> | <8 bits minor number> | <8 bits patch number>. */ - curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + switch (tlsprotocol) { + case 0: + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); + break; + case 1: + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); + break; + case 2: + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + break; + default: + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + break; + } + cmaj = curlversion->version_num >> 16; + cmin = (curlversion->version_num & 0x00ff00) >> 8; + cpat = (curlversion->version_num & 0x0000ff); + /* If cURL version < v7.34.0, use TLS v1.x */ + if (cmaj <= 7 && cmin < 34) { + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + } curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 15); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE); @@ -1258,6 +1307,10 @@ static void logc_init(void) *(CURL **)apr_array_push(curl_handles) = curl; } + if (cmaj <= 7 && cmin < 34) { + error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d", cmaj, cmin, cpat); + } + logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS, &errptr, &erroffset, NULL); if (logline_regex == NULL) { From cb91850bcd331a7a56a2a4f27706b3c9e396a059 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 6 Jan 2016 15:02:41 -0300 Subject: [PATCH 024/477] Adds information about the pull request #881 on the CHANGES file --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 675989b0d5..ff2e8c2779 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * mlogc: Allow user to choose between TLS versions (TLSProtocol option + introduced). + [Issue #881 - Ishwor Gurung] * Allow mod_proxy's "nocanon" behavior to be specified in proxy actions and Perform the intercept_action as well as the disruptive actions. [Issue #1031, #961, #763 - Mario D. Santana and ModSecurity team] From 74558b42e416a8193ec2726f0cfa7ca5ec99ac63 Mon Sep 17 00:00:00 2001 From: Athmane Madjoudj <athmane@fedoraproject.org> Date: Fri, 13 Feb 2015 13:24:50 +0100 Subject: [PATCH 025/477] Fix build issue with Lua >= 5.3 --- apache2/msc_lua.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index f4482ae7e5..58206a7584 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -111,8 +111,11 @@ char *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool) { dump.pool = pool; dump.parts = apr_array_make(pool, 128, sizeof(msc_script_part *)); +#if LUA_VERSION_NUM >= 503 + lua_dump(L, dump_writer, &dump, 1); +#else lua_dump(L, dump_writer, &dump); - +#endif (*script) = apr_pcalloc(pool, sizeof(msc_script)); (*script)->name = filename; (*script)->parts = dump.parts; From 05bcafd4fc6337fd0a06e0df4399d98aed00f4fc Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 8 Jan 2016 09:24:12 -0300 Subject: [PATCH 026/477] Extends Lua implementation to support Lua 5.3 --- CHANGES | 2 ++ apache2/msc_lua.c | 26 +++++++++++++++++++------- build/find_lua.m4 | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index ff2e8c2779..837a32feed 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Extanded Lua support to include version 5.3 + [Issue #837, #762, #814 - Athmane Madjoudj and ModSecurity team] * mlogc: Allow user to choose between TLS versions (TLSProtocol option introduced). [Issue #881 - Ishwor Gurung] diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index 58206a7584..51be1745b2 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -112,7 +112,7 @@ char *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool) { dump.parts = apr_array_make(pool, 128, sizeof(msc_script_part *)); #if LUA_VERSION_NUM >= 503 - lua_dump(L, dump_writer, &dump, 1); + lua_dump(L, dump_writer, &dump, 0); #else lua_dump(L, dump_writer, &dump); #endif @@ -420,23 +420,32 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul time_before = apr_time_now(); #ifdef CACHE_LUA + L = msr->L; rc = lua_gettop(L); if(rc) lua_pop(L, rc); + #else + /* Create new state. */ -#if LUA_VERSION_NUM > 501 +#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 501 L = luaL_newstate(); -#else +#elif LUA_VERSION_NUM == 500 L = lua_open(); +#else +#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. #endif luaL_openlibs(L); + #endif if(L == NULL) return -1; + luaL_newmetatable(L, "luaL_msc"); + lua_newtable(L); + /* Associate msr with the state. */ lua_pushlightuserdata(L, (void *)msr); lua_setglobal(L, "__msr"); @@ -448,13 +457,16 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul } /* Register functions. */ -#if LUA_VERSION_NUM > 501 - luaL_setfuncs(L,mylib,0); - lua_setglobal(L,"m"); -#else +#if LUA_VERSION_NUM == 500 || LUA_VERSION_NUM == 501 luaL_register(L, "m", mylib); +#elif LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 + luaL_setfuncs(L, mylib, 0); +#else +#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. #endif + lua_setglobal(L, "m"); + rc = lua_restore(L, script); if (rc) { *error_msg = apr_psprintf(msr->mp, "Lua: Failed to restore script with %i.", rc); diff --git a/build/find_lua.m4 b/build/find_lua.m4 index b86280112b..acb903e5fa 100644 --- a/build/find_lua.m4 +++ b/build/find_lua.m4 @@ -16,7 +16,7 @@ LUA_CPPFLAGS="" LUA_LDADD="" LUA_LDFLAGS="" LUA_CONFIG=${PKG_CONFIG} -LUA_PKGNAMES="lua5.1 lua-5.1 lua_5.1 lua-51 lua_51 lua51 lua5 lua" +LUA_PKGNAMES="lua5.1 lua-5.1 lua_5.1 lua-51 lua_51 lua51 lua5 lua lua5.2 lua-5.2 lua_5.2 lua-52 lua_52 lua52 lua5.3 lua-5.3 lua_5.3 lua-53 lua_53 lua53 " LUA_SONAMES="so la sl dll dylib a" AC_ARG_WITH( From 880b2764a31c2c3db77b81d139a0aa3149ce50db Mon Sep 17 00:00:00 2001 From: Chaim Sanders <csanders@sparsa.org> Date: Mon, 11 Jan 2016 10:09:41 -0500 Subject: [PATCH 027/477] Updated Licensing information to reflect year --- LICENSE | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index 261eeb9e9f..9135230d95 100644 --- a/LICENSE +++ b/LICENSE @@ -175,18 +175,7 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] + Copyright 2016 ModSecurity Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 1068da464c4fd7a91e7cf25adb8e028cfd650d53 Mon Sep 17 00:00:00 2001 From: Chaim Sanders <csanders@sparsa.org> Date: Mon, 11 Jan 2016 10:43:05 -0500 Subject: [PATCH 028/477] Updated recommended conf to enter XML processor when content-type is application/xml --- modsecurity.conf-recommended | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 9ee17f2f82..42a6f6c889 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -19,7 +19,7 @@ SecRequestBodyAccess On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type # -SecRule REQUEST_HEADERS:Content-Type "text/xml" \ +SecRule REQUEST_HEADERS:Content-Type "(?:text|application)/xml" \ "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" # Enable JSON request body parser. From 3f9e2ccc7cce33e8410c761f935cd5939ca4af63 Mon Sep 17 00:00:00 2001 From: Justin Gerace <jgrace103@gmail.com> Date: Thu, 24 Apr 2014 16:06:00 -0700 Subject: [PATCH 029/477] Stop buffering when the request is larger than SecRequestBodyLimit and in ProcessPartial mode --- apache2/apache2_io.c | 27 ++++++++++++++++++--------- apache2/modsecurity.h | 1 + 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 88f1903183..af6555fde7 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -139,12 +139,14 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, if (rc == 0) { modsecurity_request_body_retrieve_end(msr); - bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); - if (bucket == NULL) return APR_EGENERAL; - APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + if (msr->if_seen_eos) { + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Input filter: Sent EOS."); + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Sent EOS."); + } } /* We're done */ @@ -164,7 +166,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, */ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { request_rec *r = msr->r; - unsigned int seen_eos; + unsigned int finished_reading; apr_bucket_brigade *bb_in; apr_bucket *bucket; @@ -193,7 +195,8 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { return -1; } - seen_eos = 0; + finished_reading = 0; + msr->if_seen_eos = 0; bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc); if (bb_in == NULL) return -1; do { @@ -283,6 +286,11 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if (buflen != 0) { int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg); + + if (msr->reqbody_length > (apr_size_t)msr->txcfg->reqbody_limit && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) { + finished_reading = 1; + } + if (rcbs < 0) { if (rcbs == -5) { if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { @@ -309,12 +317,13 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (APR_BUCKET_IS_EOS(bucket)) { - seen_eos = 1; + finished_reading = 1; + msr->if_seen_eos = 1; } } apr_brigade_cleanup(bb_in); - } while(!seen_eos); + } while(!finished_reading); // TODO: Why ignore the return code here? modsecurity_request_body_end(msr, error_msg); diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index bbec3faa4d..04b96a8c1c 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -268,6 +268,7 @@ struct modsec_rec { unsigned int phase_request_body_complete; apr_bucket_brigade *if_brigade; + unsigned int if_seen_eos; unsigned int if_status; unsigned int if_started_forwarding; From b3f197dd1f5afbea585067c3d8c61c9e0a1afe8c Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 25 Jan 2016 13:40:46 -0300 Subject: [PATCH 030/477] Adds information about the pull request #709 on the CHANGES file --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 837a32feed..5c29f11022 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Stop buffering when the request is larger than SecRequestBodyLimit + in ProcessPartial mode + [Issue #709, #705, #728 - Justin Gerace and ModSecurity team] * Extanded Lua support to include version 5.3 [Issue #837, #762, #814 - Athmane Madjoudj and ModSecurity team] * mlogc: Allow user to choose between TLS versions (TLSProtocol option From d434a6c0430a1ff960e5a79720f08f12c8a34f8c Mon Sep 17 00:00:00 2001 From: Chaim Sanders <csanders@trustwave.com> Date: Thu, 7 Jan 2016 11:36:50 -0500 Subject: [PATCH 031/477] Fixing missing return value check for hashing response injection failure --- apache2/apache2_io.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index af6555fde7..0d59613e4d 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -609,8 +609,12 @@ static int flatten_response_body(modsec_rec *msr) { retval = hash_response_body_links(msr); if(retval > 0) { retval = inject_hashed_response_body(msr, retval); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); + if(retval < 0){ + msr_log(msr, 1, "inject_hashed_response_body: Unable to inject hash into response body. Returning response without changes." ); + }else{ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); + } } } From 35fbc76ecca9457f59f15cae01a0da9ebfd3b0f7 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 25 Jan 2016 14:58:24 -0300 Subject: [PATCH 032/477] Adds information about the pull request #1041 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 5c29f11022..574343ec28 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Checking for hashing injection response to report in case of failure. + [Issue #1041 - ModSecurity team] * Stop buffering when the request is larger than SecRequestBodyLimit in ProcessPartial mode [Issue #709, #705, #728 - Justin Gerace and ModSecurity team] From b175c5cf60b022721990a3e6bd7ca253145805be Mon Sep 17 00:00:00 2001 From: littlecho <littlecho@users.noreply.github.com> Date: Thu, 26 Mar 2015 15:22:45 +0800 Subject: [PATCH 033/477] Update apache2_config.c Change third parameter(which is the apr file permission flag) from CREATEMODE to dcfg->auditlog_fileperms. Due to the user can specify the desired file permission setting for the audit log files with setting the value of SecAuditLogFileMode, we should follow the file permission setting from the config file. Therefore, as the dcfg->auditlog_fileperms will be modified in cmd_audit_log_dirmode function, we can use the value while calling apr_file_open to meet the file permission that specified in modsecurity.conf. --- apache2/apache2_config.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index bad5c5dc79..4cab8983f8 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1192,10 +1192,13 @@ static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) else { const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name); apr_status_t rc; - + + if (dcfg->auditlog_fileperms == NOT_SET) { + dcfg->auditlog_fileperms = CREATEMODE; + } rc = apr_file_open(&dcfg->auditlog_fd, file_name, APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, - CREATEMODE, cmd->pool); + dcfg->auditlog_fileperms, cmd->pool); if (rc != APR_SUCCESS) { return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s", From 0db247f0e9ca43dba7e4720ae48283ae3b26832e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 26 Jan 2016 09:20:25 -0300 Subject: [PATCH 034/477] Replicates CREATEMODE patch to the secondary auditlog file At patch 45805be, @littlecho changed the behaviour to set the audit log index/serial file permission. Before, it was using the default permission now it is respecting the permission configured via SecAuditLogFileMode. This patch replicates @littlecho's work to the secundary auditlog file. --- apache2/apache2_config.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 4cab8983f8..3e33fa0453 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1234,9 +1234,12 @@ static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name); apr_status_t rc; + if (dcfg->auditlog_fileperms == NOT_SET) { + dcfg->auditlog_fileperms = CREATEMODE; + } rc = apr_file_open(&dcfg->auditlog2_fd, file_name, APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, - CREATEMODE, cmd->pool); + dcfg->auditlog_fileperms, cmd->pool); if (rc != APR_SUCCESS) { return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s", From 4eb095ad2566f6055fcbf89be2cbab08d4b73a9e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 26 Jan 2016 09:28:20 -0300 Subject: [PATCH 035/477] Adds information about the pull request #852 on the CHANGES file --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 574343ec28..fc30e44b3f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Creating AuditLog serial file (or paralel index) respecting the + permission configured with SecAuditLogFileMode, before, it was used + only to save the transactions while in paralel mode. + [Issue #852 - @littlecho and ModSecurity team] * Checking for hashing injection response to report in case of failure. [Issue #1041 - ModSecurity team] * Stop buffering when the request is larger than SecRequestBodyLimit From 7b2ca1617e9bff088369cf2fd5807a09cb4ac6e8 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 15 Jul 2015 13:57:02 -0700 Subject: [PATCH 036/477] first pass at JSON logging implementation --- apache2/msc_logging.c | 475 ++++++++++++++++++++++++++++++++++++- apache2/msc_logging_json.h | 13 + configure.ac | 18 +- 3 files changed, 494 insertions(+), 12 deletions(-) create mode 100644 apache2/msc_logging_json.h diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 3323fac925..61e21ad773 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -25,6 +25,11 @@ #include "apr_version.h" #include <libxml/xmlversion.h> +#ifdef WITH_JSON_LOGGING +#include <yajl/yajl_gen.h> +#include "msc_logging_json.h" +#endif + /** * Write the supplied data to the audit log (if the FD is ready), update * the size counters, update the hash context. @@ -381,6 +386,40 @@ static void sec_auditlog_write_producer_header(modsec_rec *msr) { sec_auditlog_write(msr, ".\n", 2); } +#ifdef WITH_JSON_LOGGING +/** + * Ouput the Producer header into a JSON generator + */ +static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) { + char **signatures = NULL; + int i; + + // this is written no matter what + yajl_string(g, "producer"); + + /* Try to write verything in one go. */ + if (msr->txcfg->component_signatures->nelts == 0) { + yajl_string(g, MODSEC_MODULE_NAME_FULL); + + return; + } + + // we'll need an array if there are component signatures + yajl_gen_array_open(g); + + /* Start with the ModSecurity signature. */ + yajl_string(g, MODSEC_MODULE_NAME_FULL); + + /* Then loop through the components and output individual signatures. */ + signatures = (char **)msr->txcfg->component_signatures->elts; + for(i = 0; i < msr->txcfg->component_signatures->nelts; i++) { + yajl_string(g, (char *)signatures[i]); + } + + yajl_gen_array_close(g); // array for producers is finished +} +#endif + /* * \brief This function will returns the next chain node * @@ -480,6 +519,66 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { return 0; } +#ifdef WITH_JSON_LOGGING +/** + * Write detailed information about a rule and its actionset into a JSON generator + */ +static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) { + int present = 0; + + yajl_gen_map_open(g); + + yajl_string(g, "actionset"); + yajl_gen_map_open(g); + if (rule->actionset->id) { + yajl_kv_string(g, "id", rule->actionset->id); + } + if (rule->actionset->rev) { + yajl_kv_string(g, "rev", rule->actionset->rev); + } + if (rule->actionset->msg) { + yajl_kv_string(g, "msg", rule->actionset->msg); + } + if (rule->actionset->version) { + yajl_kv_string(g, "version", rule->actionset->version); + } + if (rule->actionset->logdata) { + yajl_kv_string(g, "logdata", rule->actionset->logdata); + } + if (rule->actionset->severity != NOT_SET) { + yajl_kv_int(g, "severity", rule->actionset->severity); + } + if (rule->actionset->accuracy != NOT_SET) { + yajl_kv_int(g, "accuracy", rule->actionset->accuracy); + } + if (rule->actionset->maturity != NOT_SET) { + yajl_kv_int(g, "maturity", rule->actionset->maturity); + } + if (rule->actionset->phase != NOT_SET) { + yajl_kv_int(g, "phase", rule->actionset->phase); + } + yajl_kv_bool(g, "is_chained", rule->actionset->is_chained); + yajl_gen_map_close(g); + + yajl_string(g, "operator"); + yajl_gen_map_open(g); + yajl_kv_string(g, "operator", rule->op_name); + yajl_kv_string(g, "operator_param", rule->op_param); + yajl_kv_string(g, "target", rule->p1); + yajl_gen_map_close(g); + + yajl_string(g, "config"); + yajl_gen_map_open(g); + yajl_kv_string(g, "filename", rule->filename); + yajl_kv_int(g, "line_num", rule->line_num); + yajl_gen_map_close(g); + + yajl_kv_bool(g, "is_matched", chained_is_matched(msr, rule)); + + yajl_gen_map_close(g); +} +#endif + /** * Produce an audit log entry. */ @@ -501,9 +600,14 @@ void sec_audit_logger(modsec_rec *msr) { char *buf = NULL, *pat = NULL; msc_parm *mparm = NULL; int arg_min, arg_max, sanitize_matched; +#ifdef WITH_JSON_LOGGING + yajl_gen g; +#endif +#ifndef WITH_JSON_LOGGING /* the boundary is used by both audit log types */ msr->new_auditlog_boundary = create_auditlog_boundary(msr->r); +#endif /* Return silently if we don't have a request line. This * means we will not be logging request timeouts. @@ -591,29 +695,72 @@ void sec_audit_logger(modsec_rec *msr) { } } - /* AUDITLOG_PART_HEADER */ +#ifdef WITH_JSON_LOGGING + /** + * allocate the buffer for the JSON generator + * passing null will force yajl to use malloc/realloc/free + * need to perf test using APR routines + */ + g = yajl_gen_alloc(NULL); + + /** + * don't pretty print JSON by default + * this is harder to eyeball but much easier to parse programmatically + */ + yajl_gen_config(g, yajl_gen_beautify, 0); + + yajl_gen_map_open(g); // IT BEGINS +#endif + + /* AUDITLOG_PART_HEADER */ +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER); sec_auditlog_write(msr, text, strlen(text)); - /* Format: time transaction_id remote_addr remote_port local_addr local_port */ text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u", current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port, msr->local_addr, msr->local_port); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "transaction"); + yajl_gen_map_open(g); // transaction top-level key + yajl_kv_string(g, "time", current_logtime(msr->mp)); + yajl_kv_string(g, "transaction_id", msr->txid); + yajl_kv_string(g, "remote_address", msr->remote_addr); + yajl_kv_int(g, "remote_port", (int)msr->remote_port); // msr->remote_port is unsigned, yajl wants signed + yajl_kv_string(g, "local_address", msr->local_addr); + yajl_kv_int(g, "local_port", (int)msr->local_port); + + yajl_gen_map_close(g); // transaction top-level key is finished + + yajl_string(g, "request"); + yajl_gen_map_open(g); // request top-level key +#endif /* AUDITLOG_PART_REQUEST_HEADERS */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS); sec_auditlog_write(msr, text, strlen(text)); +#endif sanitize_request_line(msr); - +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, msr->request_line, strlen(msr->request_line)); sec_auditlog_write(msr, "\n", 1); +#else + // Request Line doesn't get its own map for now. should it? + yajl_kv_string(g, "request_line", msr->request_line); +#endif + +#ifdef WITH_JSON_LOGGING + yajl_string(g, "headers"); + yajl_gen_map_open(g); // separate map for request headers +#endif arr = apr_table_elts(msr->request_headers); te = (apr_table_entry_t *)arr->elts; @@ -624,7 +771,13 @@ void sec_audit_logger(modsec_rec *msr) { for (i = 0; i < arr->nelts; i++) { sanitized_partial = 0; sanitize_matched = 0; +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); +#else + // write the key no matter what + // since sanitization only occurs on the value + yajl_string(g, te[i].key); +#endif if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) { buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); @@ -656,13 +809,30 @@ void sec_audit_logger(modsec_rec *msr) { } if(sanitized_partial == 1 && sanitize_matched == 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); +#else + yajl_string(g, buf); +#endif } else { +#ifndef WITH_JSON_LOGGING memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); +#else + yajl_string(g, "****"); // fix this later +#endif } } +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + // we diverge from the original logic a bit because we always print the key + // at this no point sanitization had occured, so we just print the value + yajl_string(g, te[i].val); +#endif } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // request headers map is finished +#endif } /* AUDITLOG_PART_REQUEST_BODY */ @@ -749,9 +919,13 @@ void sec_audit_logger(modsec_rec *msr) { unsigned int chunk_offset = 0; unsigned int sanitize_offset = 0; unsigned int sanitize_length = 0; - +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "body"); + yajl_gen_array_open(g); // use an array here because we're writing in chunks +#endif for(;;) { rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg); @@ -810,7 +984,11 @@ void sec_audit_logger(modsec_rec *msr) { /* Write the sanitized chunk to the log * and advance to the next chunk. */ +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, chunk->data, chunk->length); +#else + yajl_string(g, chunk->data); +#endif chunk_offset += chunk->length; } @@ -819,6 +997,10 @@ void sec_audit_logger(modsec_rec *msr) { } } +#ifdef WITH_JSON_LOGGING + yajl_gen_array_close(g); // request body chunks array is finished +#endif + if (rc < 0) { msr_log(msr, 1, "Audit log: %s", my_error_msg); } @@ -838,29 +1020,58 @@ void sec_audit_logger(modsec_rec *msr) { if (buffer == NULL) { msr_log(msr, 1, "Audit log: Failed to reconstruct request body."); } else { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY); sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, buffer, strlen(buffer)); +#else + // this is a key instead 'request', doesn't need an array or map since it's one value + yajl_kv_string(g, "fake_body", buffer); +#endif } } } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // request top-level key is finished + + yajl_string(g, "response"); + yajl_gen_map_open(g); // response top-level key +#endif + /* AUDITLOG_PART_A_RESPONSE_HEADERS */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS); sec_auditlog_write(msr, text, strlen(text)); +#endif /* There are no response headers (or the status line) in HTTP 0.9 */ if (msr->response_headers_sent) { if (msr->status_line != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, msr->status_line); +#else + yajl_kv_string(g, "protocol", msr->response_protocol); + yajl_kv_string(g, "status", msr->status_line); +#endif } else { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol, msr->response_status); +#else + yajl_kv_string(g, "protocol", msr->response_protocol); + yajl_kv_int(g, "status", (int)msr->response_status); +#endif } +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "headers"); + yajl_gen_map_open(g); // separate map for response headers +#endif /* Output headers */ @@ -873,7 +1084,13 @@ void sec_audit_logger(modsec_rec *msr) { for (i = 0; i < arr->nelts; i++) { sanitized_partial = 0; sanitize_matched = 0; +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); +#else + // write the key no matter what + // since sanitization only occurs on the value + yajl_string(g, te[i].key); +#endif if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) { buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); @@ -905,13 +1122,30 @@ void sec_audit_logger(modsec_rec *msr) { } if(sanitized_partial == 1 && sanitize_matched == 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); +#else + yajl_string(g, buf); +#endif } else { +#ifndef WITH_JSON_LOGGING memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); +#else + yajl_string(g, "****"); // fix this later +#endif } } +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + // we diverge from the original logic a bit because we always print the key + // at this point no sanitization had occured, so we just print the value + yajl_string(g, te[i].val); +#endif } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // response headers map is finised +#endif } } @@ -921,51 +1155,101 @@ void sec_audit_logger(modsec_rec *msr) { if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) { if (msr->resbody_data != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY); sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length); +#else + yajl_kv_string(g, "body", msr->resbody_data); +#endif wrote_response_body = 1; } } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // response top-level key is finished + + yajl_string(g, "data"); + yajl_gen_map_open(g); // data top-level key +#endif + /* AUDITLOG_PART_TRAILER */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) { apr_time_t now = apr_time_now(); - +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER); sec_auditlog_write(msr, text, strlen(text)); +#endif /* Messages */ +#ifdef WITH_JSON_LOGGING + yajl_string(g, "messages"); + yajl_gen_array_open(g); +#endif for(i = 0; i < msr->alerts->nelts; i++) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Message: %s\n", ((char **)msr->alerts->elts)[i]); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, ((char **)msr->alerts->elts)[i]); +#endif } +#ifdef WITH_JSON_LOGGING + yajl_gen_array_close(g); +#endif /* Apache error messages */ +#ifdef WITH_JSON_LOGGING + yajl_string(g, "error_messages"); + yajl_gen_array_open(g); +#endif for(i = 0; i < msr->error_messages->nelts; i++) { error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]); +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Apache-Error: %s\n", format_error_log_message(msr->mp, em)); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, format_error_log_message(msr->mp, em)); +#endif } +#ifdef WITH_JSON_LOGGING + yajl_gen_array_close(g); +#endif /* Action */ if (msr->was_intercepted) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "action"); + yajl_gen_map_open(g); + yajl_kv_bool(g, "intercepted", 1); + yajl_kv_int(g, "phase", msr->intercept_phase); + yajl_gen_map_close(g); +#endif } /* Apache-Handler */ if (msr->r->handler != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, "handler", msr->r->handler); +#endif } /* Stopwatch; left in for compatibility reasons */ text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", msr->request_time, (now - msr->request_time)); +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, "stopwatch", text); +#endif /* Stopwatch2 */ { @@ -973,26 +1257,46 @@ void sec_audit_logger(modsec_rec *msr) { text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT "; %s\n", msr->request_time, (now - msr->request_time), perf_all); - +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, "stopwatch2", text); +#endif } /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ /* ENH Add info when request body was decompressed, dechunked too. */ if (wrote_response_body) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n"); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_bool(g, "response_body_dechunked", 1); +#endif } +#ifndef WITH_JSON_LOGGING sec_auditlog_write_producer_header(msr); +#else + sec_auditlog_write_producer_header_json(msr, g); +#endif /* Server */ if (msr->server_software != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, "server", msr->server_software); +#endif } +#ifdef WITH_JSON_LOGGING + yajl_string(g, "sanitized"); + yajl_gen_map_open(g); // open a separate map for sanitized values +#endif + /* Sanitised arguments */ { const apr_array_header_t *tarr; @@ -1002,16 +1306,31 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Sanitised-Args: "); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "args"); + yajl_gen_array_open(g); +#endif } for(i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), log_escape(msr->mp, arg->name), ((i == (tarr->nelts - 1)) ? ".\n" : "")); sec_auditlog_write(msr, text, strlen(text)); +#else + // yay arrays actually make it easier here + yajl_string(g, log_escape(msr->mp, arg->name)); +#endif } +#ifdef WITH_JSON_LOGGING + if (tarr->nelts > 0) { + yajl_gen_array_close(g); + } +#endif } /* Sanitised request headers */ @@ -1023,15 +1342,29 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: "); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "request_headers"); + yajl_gen_array_open(g); +#endif } for(i = 0; i < tarr->nelts; i++) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, log_escape(msr->mp, telts[i].key)); +#endif + } +#ifdef WITH_JSON_LOGGING + if (tarr->nelts > 0) { + yajl_gen_array_close(g); } +#endif } /* Sanitised response headers */ @@ -1043,40 +1376,85 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: "); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "response_headers"); + yajl_gen_array_open(g); +#endif } for(i = 0; i < tarr->nelts; i++) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, log_escape(msr->mp, telts[i].key)); +#endif + } +#ifdef WITH_JSON_LOGGING + if (tarr->nelts > 0) { + yajl_gen_array_close(g); } +#endif } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // sanitized args map is finished +#endif + /* Web application info. */ if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) || (msr->sessionid != NULL) || (msr->userid != NULL)) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "WebApp-Info: \"%s\" \"%s\" \"%s\"\n", msr->txcfg->webappid == NULL ? "-" : log_escape(msr->mp, msr->txcfg->webappid), msr->sessionid == NULL ? "-" : log_escape(msr->mp, msr->sessionid), msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid)); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "webapp_info"); + yajl_gen_map_open(g); + + if (msr->txcfg->webappid != NULL) { + yajl_kv_string(g, "id", log_escape(msr->mp, msr->txcfg->webappid)); + } + if (msr->sessionid != NULL) { + yajl_kv_string(g, "session", log_escape(msr->mp, msr->sessionid)); + } + if (msr->userid != NULL) { + yajl_kv_string(g, "user_id", log_escape(msr->mp, msr->userid)); + } + + yajl_gen_map_close(g); +#endif } if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0))) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Sensor-Id: \"%s\"\n", msr->txcfg->sensor_id == NULL ? "-" : log_escape(msr->mp, msr->txcfg->sensor_id)), sec_auditlog_write(msr, text, strlen(text)); +#else + if(msr->txcfg->sensor_id != NULL) { + yajl_kv_string(g, "sensor_id", log_escape(msr->mp, msr->txcfg->sensor_id)); + } +#endif } if (msr->txcfg->is_enabled > 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Engine-Mode: \"%s\"\n", msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"), sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, "engine_mode", (msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED")); +#endif } /* Rule performance time */ @@ -1088,54 +1466,104 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Rules-Performance-Info: "); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "rules_performance_info"); + yajl_gen_map_open(g); // separate map for rule perf info +#endif } for(i = 0; i < tarr->nelts; i++) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\"%s=%s\"%s", ((i == 0) ? "" : ", "), log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val), ((i == (tarr->nelts - 1)) ? ".\n" : "")); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_string(g, log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val)); +#endif } +#ifdef WITH_JSON_LOGGING + if (tarr->nelts > 0) { + yajl_gen_map_close(g); // map for rule perf info is finished + } +#endif } - } +#ifdef WITH_JSON_LOGGING + yajl_gen_map_close(g); // data top-level key is finished +#endif + /* AUDITLOG_PART_UPLOADS */ if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) { multipart_part **parts = NULL; unsigned int total_size = 0; int cfiles = 0; +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_UPLOADS); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "uploads"); + yajl_gen_map_open(g); +#endif parts = (multipart_part **)msr->mpd->parts->elts; +#ifdef WITH_JSON_LOGGING + yajl_string(g, "info"); + yajl_gen_array_open(g); // separate array for upload info +#endif for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) { if (parts[cfiles]->type == MULTIPART_FILE) { if(parts[cfiles]->filename != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%d,%u,\"%s\",\"%s\"\n", cfiles+1, parts[cfiles]->tmp_file_size, log_escape(msr->mp, parts[cfiles]->filename), log_escape(msr->mp, parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown ContentType>")); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_kv_int(g, "file_size", parts[cfiles]->tmp_file_size); + yajl_kv_string(g, "file_name", log_escape(msr->mp, parts[cfiles]->filename)); + yajl_kv_string(g, "content_type", parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown Content-Type>"); +#endif total_size += parts[cfiles]->tmp_file_size; } } } +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "Total,%u\n", total_size); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_gen_array_close(g); // array for upload info is finished + yajl_kv_int(g, "total", total_size); + + yajl_gen_map_close(g); // uploads top-level key is finished +#endif } /* AUDITLOG_PART_MATCHEDRULES */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_string(g, "matched_rules"); + yajl_gen_array_open(g); // matched_rules top-level key +#endif + /* Matched Rules */ + for(i = 0; i < msr->matched_rules->nelts; i++) { rule = ((msre_rule **)msr->matched_rules->elts)[i]; if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\n", rule->unparsed); sec_auditlog_write(msr, text, strlen(text)); +#else + write_rule_json(msr, rule, g); +#endif do { if (rule->ruleset != NULL) { @@ -1146,32 +1574,59 @@ void sec_audit_logger(modsec_rec *msr) { present = chained_is_matched(msr,next_rule); if (present == 0) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "#%s\n",next_rule->unparsed); +#endif } else { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\n",next_rule->unparsed); +#endif i++; } - +#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); +#else + write_rule_json(msr, next_rule, g); +#endif } } rule = next_rule; } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained); +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n"); sec_auditlog_write(msr, text, strlen(text)); +#endif } else { if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) { +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s\n\n", rule->unparsed); sec_auditlog_write(msr, text, strlen(text)); +#else + write_rule_json(msr, rule, g); +#endif } } } - } +#ifdef WITH_JSON_LOGGING + yajl_gen_array_close(g); // matched_rules top-level key is finished +#endif + } /* AUDITLOG_PART_ENDMARKER */ - +#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER); sec_auditlog_write(msr, text, strlen(text)); +#else + yajl_gen_map_close(g); // box it up! + + const unsigned char *final_buf; + size_t len; + yajl_gen_get_buf(g, &final_buf, &len); + sec_auditlog_write(msr, final_buf, len); + + yajl_gen_clear(g); + yajl_gen_free(g); +#endif /* Return here if we were writing to a serial log * as it does not need an index file. diff --git a/apache2/msc_logging_json.h b/apache2/msc_logging_json.h new file mode 100644 index 0000000000..e49b98c29d --- /dev/null +++ b/apache2/msc_logging_json.h @@ -0,0 +1,13 @@ +#include <string.h> + +#include <yajl/yajl_gen.h> + +#define yajl_string(g, s) yajl_gen_string(g, (const unsigned char *)s, strlen(s)) + +#define yajl_kv_null(g, k) yajl_string(g, k); yajl_gen_null(g) + +#define yajl_kv_int(g, k, v) yajl_string(g, k); yajl_gen_integer(g, v) + +#define yajl_kv_string(g, k, v) yajl_string(g, k); yajl_string(g, v) + +#define yajl_kv_bool(g, k, v) yajl_string(g, k); yajl_gen_bool(g, v) diff --git a/configure.ac b/configure.ac index 7517885893..bb2e42e34a 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,21 @@ if test "$build_docs" -eq 1; then TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS docs" fi +# Add JSON audit logging +AC_ARG_ENABLE(json-logging, + AS_HELP_STRING([--enabled-json-logging], + [Enable JSON audit logging.]), +[ + if test "$enableval" != "no"; then + json_logging='-DWITH_JSON_LOGGING' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $json_logging" + else + json_logging='' + fi +], +[ + json_logging='' +]) # Add PCRE Studying @@ -659,8 +674,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" - +MODSEC_EXTRA_CFLAGS="$json_logging $pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" for f in $EXTRA_CFLAGS; do From dd79bea0b49df2e90683e47077f4d6e592f512ba Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Thu, 16 Jul 2015 15:33:52 -0700 Subject: [PATCH 037/477] Additional updates for JSON logging * Write Stopwatch2 values into a separate map * Remove legacy Stopwatch * Proper sanitization of request/response headers * Lazily open maps for keys that may not have content --- apache2/msc_logging.c | 120 +++++++++++++++++++++++++++++++----------- 1 file changed, 88 insertions(+), 32 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 61e21ad773..2fe63142ee 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -520,6 +520,26 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { } #ifdef WITH_JSON_LOGGING +/** + * Write detailed information about performance metrics into a JSON generator + */ +static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { + yajl_string(g, "stopwatch"); + yajl_gen_map_open(g); + + yajl_kv_int(g, "p1", msr->time_phase1); + yajl_kv_int(g, "p2", msr->time_phase2); + yajl_kv_int(g, "p3", msr->time_phase3); + yajl_kv_int(g, "p4", msr->time_phase4); + yajl_kv_int(g, "p5", msr->time_phase5); + yajl_kv_int(g, "sr", msr->time_storage_read); + yajl_kv_int(g, "sw", msr->time_storage_write); + yajl_kv_int(g, "l", msr->time_logging); + yajl_kv_int(g, "gc", msr->time_gc); + + yajl_gen_map_close(g); +} + /** * Write detailed information about a rule and its actionset into a JSON generator */ @@ -558,6 +578,9 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) yajl_kv_int(g, "phase", rule->actionset->phase); } yajl_kv_bool(g, "is_chained", rule->actionset->is_chained); + if (rule->actionset->is_chained && (rule->chain_starter == NULL)) { + yajl_kv_bool(g, "chain_starter", 1); + } yajl_gen_map_close(g); yajl_string(g, "operator"); @@ -602,6 +625,7 @@ void sec_audit_logger(modsec_rec *msr) { int arg_min, arg_max, sanitize_matched; #ifdef WITH_JSON_LOGGING yajl_gen g; + int been_opened = 0; // helper flag for conditionally opening maps #endif #ifndef WITH_JSON_LOGGING @@ -704,7 +728,7 @@ void sec_audit_logger(modsec_rec *msr) { g = yajl_gen_alloc(NULL); /** - * don't pretty print JSON by default + * don't pretty print JSON * this is harder to eyeball but much easier to parse programmatically */ yajl_gen_config(g, yajl_gen_beautify, 0); @@ -771,16 +795,14 @@ void sec_audit_logger(modsec_rec *msr) { for (i = 0; i < arr->nelts; i++) { sanitized_partial = 0; sanitize_matched = 0; -#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); -#else +#ifdef WITH_JSON_LOGGING // write the key no matter what // since sanitization only occurs on the value yajl_string(g, te[i].key); #endif if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) { buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); - for ( k = 0; k < tarr_pattern->nelts; k++) { if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) { mparm = (msc_parm *)telts_pattern[k].val; @@ -818,7 +840,8 @@ void sec_audit_logger(modsec_rec *msr) { #ifndef WITH_JSON_LOGGING memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); #else - yajl_string(g, "****"); // fix this later + memset(buf, '*', strlen(buf)); // strlen also includes the appended newline on the header + yajl_string(g, buf); #endif } } @@ -827,7 +850,9 @@ void sec_audit_logger(modsec_rec *msr) { #else // we diverge from the original logic a bit because we always print the key // at this no point sanitization had occured, so we just print the value - yajl_string(g, te[i].val); + else { + yajl_string(g, te[i].val); + } #endif } #ifdef WITH_JSON_LOGGING @@ -1025,7 +1050,6 @@ void sec_audit_logger(modsec_rec *msr) { sec_auditlog_write(msr, text, strlen(text)); sec_auditlog_write(msr, buffer, strlen(buffer)); #else - // this is a key instead 'request', doesn't need an array or map since it's one value yajl_kv_string(g, "fake_body", buffer); #endif } @@ -1055,7 +1079,8 @@ void sec_audit_logger(modsec_rec *msr) { msr->status_line); #else yajl_kv_string(g, "protocol", msr->response_protocol); - yajl_kv_string(g, "status", msr->status_line); + // as an integer, response status is easier to parse than status_line + yajl_kv_int(g, "status", (int)msr->response_status); #endif } else { #ifndef WITH_JSON_LOGGING @@ -1084,9 +1109,8 @@ void sec_audit_logger(modsec_rec *msr) { for (i = 0; i < arr->nelts; i++) { sanitized_partial = 0; sanitize_matched = 0; -#ifndef WITH_JSON_LOGGING text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); -#else +#ifdef WITH_JSON_LOGGING // write the key no matter what // since sanitization only occurs on the value yajl_string(g, te[i].key); @@ -1131,7 +1155,8 @@ void sec_audit_logger(modsec_rec *msr) { #ifndef WITH_JSON_LOGGING memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); #else - yajl_string(g, "****"); // fix this later + memset(buf, '*', strlen(buf)); + yajl_string(g, buf); #endif } } @@ -1140,7 +1165,9 @@ void sec_audit_logger(modsec_rec *msr) { #else // we diverge from the original logic a bit because we always print the key // at this point no sanitization had occured, so we just print the value - yajl_string(g, te[i].val); + else { + yajl_string(g, te[i].val); + } #endif } #ifdef WITH_JSON_LOGGING @@ -1169,8 +1196,8 @@ void sec_audit_logger(modsec_rec *msr) { #ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // response top-level key is finished - yajl_string(g, "data"); - yajl_gen_map_open(g); // data top-level key + yajl_string(g, "audit_data"); + yajl_gen_map_open(g); // audit_data top-level key #endif /* AUDITLOG_PART_TRAILER */ @@ -1184,8 +1211,12 @@ void sec_audit_logger(modsec_rec *msr) { /* Messages */ #ifdef WITH_JSON_LOGGING - yajl_string(g, "messages"); - yajl_gen_array_open(g); + been_opened = 0; + if (msr->alerts->nelts > 0) { + yajl_string(g, "messages"); + yajl_gen_array_open(g); + been_opened = 1; + } #endif for(i = 0; i < msr->alerts->nelts; i++) { #ifndef WITH_JSON_LOGGING @@ -1196,13 +1227,19 @@ void sec_audit_logger(modsec_rec *msr) { #endif } #ifdef WITH_JSON_LOGGING - yajl_gen_array_close(g); + if (been_opened == 1) { + yajl_gen_array_close(g); + } #endif /* Apache error messages */ #ifdef WITH_JSON_LOGGING - yajl_string(g, "error_messages"); - yajl_gen_array_open(g); + been_opened = 0; + if (msr->error_messages->nelts > 0) { + yajl_string(g, "error_messages"); + yajl_gen_array_open(g); + been_opened = 1; + } #endif for(i = 0; i < msr->error_messages->nelts; i++) { error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]); @@ -1215,7 +1252,9 @@ void sec_audit_logger(modsec_rec *msr) { #endif } #ifdef WITH_JSON_LOGGING - yajl_gen_array_close(g); + if (been_opened == 1) { + yajl_gen_array_close(g); + } #endif /* Action */ @@ -1228,6 +1267,7 @@ void sec_audit_logger(modsec_rec *msr) { yajl_gen_map_open(g); yajl_kv_bool(g, "intercepted", 1); yajl_kv_int(g, "phase", msr->intercept_phase); + yajl_kv_string(g, "message", msr->intercept_message); yajl_gen_map_close(g); #endif } @@ -1242,27 +1282,25 @@ void sec_audit_logger(modsec_rec *msr) { #endif } +#ifndef WITH_JSON_LOGGING /* Stopwatch; left in for compatibility reasons */ text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", msr->request_time, (now - msr->request_time)); -#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); -#else - yajl_kv_string(g, "stopwatch", text); #endif /* Stopwatch2 */ +#ifndef WITH_JSON_LOGGING { char *perf_all = format_all_performance_variables(msr, msr->mp); text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT "; %s\n", msr->request_time, (now - msr->request_time), perf_all); -#ifndef WITH_JSON_LOGGING sec_auditlog_write(msr, text, strlen(text)); + } #else - yajl_kv_string(g, "stopwatch2", text); + format_performance_variables_json(msr, g); #endif - } /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ @@ -1293,8 +1331,7 @@ void sec_audit_logger(modsec_rec *msr) { } #ifdef WITH_JSON_LOGGING - yajl_string(g, "sanitized"); - yajl_gen_map_open(g); // open a separate map for sanitized values + been_opened = 0; #endif /* Sanitised arguments */ @@ -1310,6 +1347,12 @@ void sec_audit_logger(modsec_rec *msr) { text = apr_psprintf(msr->mp, "Sanitised-Args: "); sec_auditlog_write(msr, text, strlen(text)); #else + if (been_opened == 0) { + yajl_string(g, "sanitized"); + yajl_gen_map_open(g); + been_opened = 1; + } + yajl_string(g, "args"); yajl_gen_array_open(g); #endif @@ -1346,6 +1389,12 @@ void sec_audit_logger(modsec_rec *msr) { text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: "); sec_auditlog_write(msr, text, strlen(text)); #else + if (been_opened == 0) { + yajl_string(g, "sanitized"); + yajl_gen_map_open(g); + been_opened = 1; + } + yajl_string(g, "request_headers"); yajl_gen_array_open(g); #endif @@ -1380,6 +1429,12 @@ void sec_audit_logger(modsec_rec *msr) { text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: "); sec_auditlog_write(msr, text, strlen(text)); #else + if (been_opened == 0) { + yajl_string(g, "sanitized"); + yajl_gen_map_open(g); + been_opened = 1; + } + yajl_string(g, "response_headers"); yajl_gen_array_open(g); #endif @@ -1402,7 +1457,9 @@ void sec_audit_logger(modsec_rec *msr) { } #ifdef WITH_JSON_LOGGING - yajl_gen_map_close(g); // sanitized args map is finished + if (been_opened == 1) { + yajl_gen_map_close(g); // sanitized args map is finished + } #endif /* Web application info. */ @@ -1493,7 +1550,7 @@ void sec_audit_logger(modsec_rec *msr) { } #ifdef WITH_JSON_LOGGING - yajl_gen_map_close(g); // data top-level key is finished + yajl_gen_map_close(g); // audit_data top-level key is finished #endif /* AUDITLOG_PART_UPLOADS */ @@ -1552,7 +1609,6 @@ void sec_audit_logger(modsec_rec *msr) { yajl_gen_array_open(g); // matched_rules top-level key #endif - /* Matched Rules */ for(i = 0; i < msr->matched_rules->nelts; i++) { @@ -1608,7 +1664,7 @@ void sec_audit_logger(modsec_rec *msr) { } } #ifdef WITH_JSON_LOGGING - yajl_gen_array_close(g); // matched_rules top-level key is finished + yajl_gen_array_close(g); // matched_rules top-level key is finished #endif } From 7a39b4b5b9fb51054445e3a8ca66a5f5bdde75fb Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Sat, 18 Jul 2015 22:43:10 -0700 Subject: [PATCH 038/477] Make JSON audit logging a configurable option Remove compile-time setting for generating audit logs as JSON, creating a new config option (SecAuditLogFormat). sec_audit_logger is now a wrapper for sec_audit_logger_json or sec_audit_logger_native. This has the disadvantage of making the audit log generation code harder to maintain, but the logger function itself now is no longer pepper with binary branches. --- apache2/apache2_config.c | 27 + apache2/modsecurity.h | 3 + apache2/msc_logging.c | 1116 +++++++++++++++++++++++++++----------- apache2/msc_logging.h | 3 + configure.ac | 18 +- 5 files changed, 819 insertions(+), 348 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 3e33fa0453..e38cf4e97a 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -73,6 +73,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) /* audit log variables */ dcfg->auditlog_flag = NOT_SET; dcfg->auditlog_type = NOT_SET; + dcfg->auditlog_format = NOT_SET; dcfg->max_rule_time = NOT_SET; dcfg->auditlog_dirperms = NOT_SET; dcfg->auditlog_fileperms = NOT_SET; @@ -503,6 +504,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->auditlog2_fd = parent->auditlog2_fd; merged->auditlog2_name = parent->auditlog2_name; } + merged->auditlog_format = (child->auditlog_format == NOT_SET + ? parent->auditlog_format : child->auditlog_format); merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P ? parent->auditlog_storage_dir : child->auditlog_storage_dir); merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P @@ -667,6 +670,7 @@ void init_directory_config(directory_config *dcfg) /* audit log variables */ if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + if (dcfg->auditlog_format == NOT_SET) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0; if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; @@ -1291,6 +1295,21 @@ static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, return NULL; } +static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "JSON") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_JSON; + else + if (strcasecmp(p1, "Native") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditLogFormat: %s", p1); + + return NULL; +} + static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) { @@ -3232,6 +3251,14 @@ const command_rec module_directives[] = { "whether to use the old audit log format (Serial) or new (Concurrent)" ), + AP_INIT_TAKE1 ( + "SecAuditLogFormat", + cmd_audit_log_mode, + NULL, + CMD_SCOPE_ANY, + "whether to emit audit log data in native format or JSON" + ), + AP_INIT_TAKE1 ( "SecAuditLogStorageDir", cmd_audit_log_storage_dir, diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 04b96a8c1c..bc015f9345 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -519,6 +519,9 @@ struct directory_config { /* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */ int auditlog_type; + /* AUDITLOGFORMAT_NATIVE or AUDITLOGFORMAT_JSON */ + int auditlog_format; + /* Mode for audit log directories and files */ apr_fileperms_t auditlog_dirperms; apr_fileperms_t auditlog_fileperms; diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 2fe63142ee..a1911f65ea 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -25,10 +25,8 @@ #include "apr_version.h" #include <libxml/xmlversion.h> -#ifdef WITH_JSON_LOGGING #include <yajl/yajl_gen.h> #include "msc_logging_json.h" -#endif /** * Write the supplied data to the audit log (if the FD is ready), update @@ -386,7 +384,6 @@ static void sec_auditlog_write_producer_header(modsec_rec *msr) { sec_auditlog_write(msr, ".\n", 2); } -#ifdef WITH_JSON_LOGGING /** * Ouput the Producer header into a JSON generator */ @@ -418,7 +415,6 @@ static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) yajl_gen_array_close(g); // array for producers is finished } -#endif /* * \brief This function will returns the next chain node @@ -519,7 +515,6 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { return 0; } -#ifdef WITH_JSON_LOGGING /** * Write detailed information about performance metrics into a JSON generator */ @@ -600,12 +595,11 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) yajl_gen_map_close(g); } -#endif -/** - * Produce an audit log entry. +/* + * Produce an audit log entry in JSON format. */ -void sec_audit_logger(modsec_rec *msr) { +void sec_audit_logger_json(modsec_rec *msr) { const apr_array_header_t *arr = NULL; apr_table_entry_t *te = NULL; const apr_array_header_t *tarr_pattern = NULL; @@ -623,15 +617,8 @@ void sec_audit_logger(modsec_rec *msr) { char *buf = NULL, *pat = NULL; msc_parm *mparm = NULL; int arg_min, arg_max, sanitize_matched; -#ifdef WITH_JSON_LOGGING yajl_gen g; int been_opened = 0; // helper flag for conditionally opening maps -#endif - -#ifndef WITH_JSON_LOGGING - /* the boundary is used by both audit log types */ - msr->new_auditlog_boundary = create_auditlog_boundary(msr->r); -#endif /* Return silently if we don't have a request line. This * means we will not be logging request timeouts. @@ -719,7 +706,6 @@ void sec_audit_logger(modsec_rec *msr) { } } -#ifdef WITH_JSON_LOGGING /** * allocate the buffer for the JSON generator * passing null will force yajl to use malloc/realloc/free @@ -734,20 +720,8 @@ void sec_audit_logger(modsec_rec *msr) { yajl_gen_config(g, yajl_gen_beautify, 0); yajl_gen_map_open(g); // IT BEGINS -#endif - /* AUDITLOG_PART_HEADER */ -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER); - sec_auditlog_write(msr, text, strlen(text)); - /* Format: time transaction_id remote_addr remote_port local_addr local_port */ - - text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u", - current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port, - msr->local_addr, msr->local_port); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "transaction"); yajl_gen_map_open(g); // transaction top-level key @@ -762,29 +736,15 @@ void sec_audit_logger(modsec_rec *msr) { yajl_string(g, "request"); yajl_gen_map_open(g); // request top-level key -#endif /* AUDITLOG_PART_REQUEST_HEADERS */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS); - sec_auditlog_write(msr, text, strlen(text)); -#endif - sanitize_request_line(msr); -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, msr->request_line, strlen(msr->request_line)); - sec_auditlog_write(msr, "\n", 1); -#else - // Request Line doesn't get its own map for now. should it? yajl_kv_string(g, "request_line", msr->request_line); -#endif -#ifdef WITH_JSON_LOGGING yajl_string(g, "headers"); yajl_gen_map_open(g); // separate map for request headers -#endif arr = apr_table_elts(msr->request_headers); te = (apr_table_entry_t *)arr->elts; @@ -796,11 +756,9 @@ void sec_audit_logger(modsec_rec *msr) { sanitized_partial = 0; sanitize_matched = 0; text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); -#ifdef WITH_JSON_LOGGING // write the key no matter what // since sanitization only occurs on the value yajl_string(g, te[i].key); -#endif if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) { buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); for ( k = 0; k < tarr_pattern->nelts; k++) { @@ -831,33 +789,18 @@ void sec_audit_logger(modsec_rec *msr) { } if(sanitized_partial == 1 && sanitize_matched == 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); -#else yajl_string(g, buf); -#endif } else { -#ifndef WITH_JSON_LOGGING - memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); -#else memset(buf, '*', strlen(buf)); // strlen also includes the appended newline on the header yajl_string(g, buf); -#endif } - } -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, text, strlen(text)); -#else + } else { // we diverge from the original logic a bit because we always print the key // at this no point sanitization had occured, so we just print the value - else { yajl_string(g, te[i].val); } -#endif } -#ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // request headers map is finished -#endif } /* AUDITLOG_PART_REQUEST_BODY */ @@ -944,13 +887,8 @@ void sec_audit_logger(modsec_rec *msr) { unsigned int chunk_offset = 0; unsigned int sanitize_offset = 0; unsigned int sanitize_length = 0; -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "body"); yajl_gen_array_open(g); // use an array here because we're writing in chunks -#endif for(;;) { rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg); @@ -1009,11 +947,7 @@ void sec_audit_logger(modsec_rec *msr) { /* Write the sanitized chunk to the log * and advance to the next chunk. */ -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, chunk->data, chunk->length); -#else yajl_string(g, chunk->data); -#endif chunk_offset += chunk->length; } @@ -1022,9 +956,7 @@ void sec_audit_logger(modsec_rec *msr) { } } -#ifdef WITH_JSON_LOGGING yajl_gen_array_close(g); // request body chunks array is finished -#endif if (rc < 0) { msr_log(msr, 1, "Audit log: %s", my_error_msg); @@ -1045,58 +977,27 @@ void sec_audit_logger(modsec_rec *msr) { if (buffer == NULL) { msr_log(msr, 1, "Audit log: Failed to reconstruct request body."); } else { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY); - sec_auditlog_write(msr, text, strlen(text)); - sec_auditlog_write(msr, buffer, strlen(buffer)); -#else yajl_kv_string(g, "fake_body", buffer); -#endif } } } -#ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // request top-level key is finished yajl_string(g, "response"); yajl_gen_map_open(g); // response top-level key -#endif /* AUDITLOG_PART_A_RESPONSE_HEADERS */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS); - sec_auditlog_write(msr, text, strlen(text)); -#endif /* There are no response headers (or the status line) in HTTP 0.9 */ if (msr->response_headers_sent) { - if (msr->status_line != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, - msr->status_line); -#else - yajl_kv_string(g, "protocol", msr->response_protocol); - // as an integer, response status is easier to parse than status_line - yajl_kv_int(g, "status", (int)msr->response_status); -#endif - } else { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol, - msr->response_status); -#else - yajl_kv_string(g, "protocol", msr->response_protocol); - yajl_kv_int(g, "status", (int)msr->response_status); -#endif - } -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, text, strlen(text)); -#else + yajl_kv_string(g, "protocol", msr->response_protocol); + // as an integer, response status is easier to parse than status_line + yajl_kv_int(g, "status", (int)msr->response_status); yajl_string(g, "headers"); yajl_gen_map_open(g); // separate map for response headers -#endif /* Output headers */ @@ -1110,11 +1011,9 @@ void sec_audit_logger(modsec_rec *msr) { sanitized_partial = 0; sanitize_matched = 0; text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); -#ifdef WITH_JSON_LOGGING // write the key no matter what // since sanitization only occurs on the value yajl_string(g, te[i].key); -#endif if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) { buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); @@ -1146,33 +1045,18 @@ void sec_audit_logger(modsec_rec *msr) { } if(sanitized_partial == 1 && sanitize_matched == 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); -#else yajl_string(g, buf); -#endif } else { -#ifndef WITH_JSON_LOGGING - memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); -#else memset(buf, '*', strlen(buf)); yajl_string(g, buf); -#endif } - } -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, text, strlen(text)); -#else - // we diverge from the original logic a bit because we always print the key - // at this point no sanitization had occured, so we just print the value - else { + } else { + // we diverge from the original logic a bit because we always print the key + // at this point no sanitization had occured, so we just print the value yajl_string(g, te[i].val); } -#endif } -#ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // response headers map is finised -#endif } } @@ -1182,158 +1066,84 @@ void sec_audit_logger(modsec_rec *msr) { if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) { if (msr->resbody_data != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY); - sec_auditlog_write(msr, text, strlen(text)); - sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length); -#else yajl_kv_string(g, "body", msr->resbody_data); -#endif wrote_response_body = 1; } } -#ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // response top-level key is finished yajl_string(g, "audit_data"); yajl_gen_map_open(g); // audit_data top-level key -#endif /* AUDITLOG_PART_TRAILER */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) { apr_time_t now = apr_time_now(); -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER); - sec_auditlog_write(msr, text, strlen(text)); -#endif /* Messages */ -#ifdef WITH_JSON_LOGGING been_opened = 0; if (msr->alerts->nelts > 0) { yajl_string(g, "messages"); yajl_gen_array_open(g); been_opened = 1; } -#endif for(i = 0; i < msr->alerts->nelts; i++) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Message: %s\n", ((char **)msr->alerts->elts)[i]); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, ((char **)msr->alerts->elts)[i]); -#endif } -#ifdef WITH_JSON_LOGGING if (been_opened == 1) { yajl_gen_array_close(g); } -#endif /* Apache error messages */ -#ifdef WITH_JSON_LOGGING been_opened = 0; if (msr->error_messages->nelts > 0) { yajl_string(g, "error_messages"); yajl_gen_array_open(g); been_opened = 1; } -#endif for(i = 0; i < msr->error_messages->nelts; i++) { error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]); -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Apache-Error: %s\n", - format_error_log_message(msr->mp, em)); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, format_error_log_message(msr->mp, em)); -#endif } -#ifdef WITH_JSON_LOGGING if (been_opened == 1) { yajl_gen_array_close(g); } -#endif /* Action */ if (msr->was_intercepted) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "action"); yajl_gen_map_open(g); yajl_kv_bool(g, "intercepted", 1); yajl_kv_int(g, "phase", msr->intercept_phase); yajl_kv_string(g, "message", msr->intercept_message); yajl_gen_map_close(g); -#endif } /* Apache-Handler */ if (msr->r->handler != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_string(g, "handler", msr->r->handler); -#endif } -#ifndef WITH_JSON_LOGGING - /* Stopwatch; left in for compatibility reasons */ - text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", - msr->request_time, (now - msr->request_time)); - sec_auditlog_write(msr, text, strlen(text)); -#endif /* Stopwatch2 */ -#ifndef WITH_JSON_LOGGING - { - char *perf_all = format_all_performance_variables(msr, msr->mp); - - text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT - "; %s\n", msr->request_time, (now - msr->request_time), perf_all); - sec_auditlog_write(msr, text, strlen(text)); - } -#else format_performance_variables_json(msr, g); -#endif /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ /* ENH Add info when request body was decompressed, dechunked too. */ if (wrote_response_body) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n"); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_bool(g, "response_body_dechunked", 1); -#endif } -#ifndef WITH_JSON_LOGGING - sec_auditlog_write_producer_header(msr); -#else sec_auditlog_write_producer_header_json(msr, g); -#endif /* Server */ if (msr->server_software != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_string(g, "server", msr->server_software); -#endif } -#ifdef WITH_JSON_LOGGING been_opened = 0; -#endif - /* Sanitised arguments */ { const apr_array_header_t *tarr; @@ -1343,10 +1153,6 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Sanitised-Args: "); - sec_auditlog_write(msr, text, strlen(text)); -#else if (been_opened == 0) { yajl_string(g, "sanitized"); yajl_gen_map_open(g); @@ -1355,25 +1161,16 @@ void sec_audit_logger(modsec_rec *msr) { yajl_string(g, "args"); yajl_gen_array_open(g); -#endif } for(i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), - log_escape(msr->mp, arg->name), ((i == (tarr->nelts - 1)) ? ".\n" : "")); - sec_auditlog_write(msr, text, strlen(text)); -#else // yay arrays actually make it easier here yajl_string(g, log_escape(msr->mp, arg->name)); -#endif } -#ifdef WITH_JSON_LOGGING if (tarr->nelts > 0) { yajl_gen_array_close(g); } -#endif } /* Sanitised request headers */ @@ -1385,10 +1182,6 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: "); - sec_auditlog_write(msr, text, strlen(text)); -#else if (been_opened == 0) { yajl_string(g, "sanitized"); yajl_gen_map_open(g); @@ -1397,23 +1190,14 @@ void sec_audit_logger(modsec_rec *msr) { yajl_string(g, "request_headers"); yajl_gen_array_open(g); -#endif } for(i = 0; i < tarr->nelts; i++) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), - log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, log_escape(msr->mp, telts[i].key)); -#endif } -#ifdef WITH_JSON_LOGGING if (tarr->nelts > 0) { yajl_gen_array_close(g); } -#endif } /* Sanitised response headers */ @@ -1425,10 +1209,6 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: "); - sec_auditlog_write(msr, text, strlen(text)); -#else if (been_opened == 0) { yajl_string(g, "sanitized"); yajl_gen_map_open(g); @@ -1437,42 +1217,24 @@ void sec_audit_logger(modsec_rec *msr) { yajl_string(g, "response_headers"); yajl_gen_array_open(g); -#endif } for(i = 0; i < tarr->nelts; i++) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), - log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, log_escape(msr->mp, telts[i].key)); -#endif } -#ifdef WITH_JSON_LOGGING if (tarr->nelts > 0) { yajl_gen_array_close(g); } -#endif } -#ifdef WITH_JSON_LOGGING if (been_opened == 1) { yajl_gen_map_close(g); // sanitized args map is finished } -#endif /* Web application info. */ if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) || (msr->sessionid != NULL) || (msr->userid != NULL)) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "WebApp-Info: \"%s\" \"%s\" \"%s\"\n", - msr->txcfg->webappid == NULL ? "-" : log_escape(msr->mp, msr->txcfg->webappid), - msr->sessionid == NULL ? "-" : log_escape(msr->mp, msr->sessionid), - msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid)); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "webapp_info"); yajl_gen_map_open(g); @@ -1487,31 +1249,18 @@ void sec_audit_logger(modsec_rec *msr) { } yajl_gen_map_close(g); -#endif } if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0))) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Sensor-Id: \"%s\"\n", - msr->txcfg->sensor_id == NULL ? "-" : log_escape(msr->mp, msr->txcfg->sensor_id)), - sec_auditlog_write(msr, text, strlen(text)); -#else if(msr->txcfg->sensor_id != NULL) { yajl_kv_string(g, "sensor_id", log_escape(msr->mp, msr->txcfg->sensor_id)); } -#endif } if (msr->txcfg->is_enabled > 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Engine-Mode: \"%s\"\n", - msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"), - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_string(g, "engine_mode", (msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED")); -#endif } /* Rule performance time */ @@ -1523,35 +1272,20 @@ void sec_audit_logger(modsec_rec *msr) { telts = (const apr_table_entry_t*)tarr->elts; if (tarr->nelts > 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Rules-Performance-Info: "); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "rules_performance_info"); yajl_gen_map_open(g); // separate map for rule perf info -#endif } for(i = 0; i < tarr->nelts; i++) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\"%s=%s\"%s", ((i == 0) ? "" : ", "), - log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val), ((i == (tarr->nelts - 1)) ? ".\n" : "")); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_string(g, log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val)); -#endif } -#ifdef WITH_JSON_LOGGING if (tarr->nelts > 0) { yajl_gen_map_close(g); // map for rule perf info is finished } -#endif } } -#ifdef WITH_JSON_LOGGING yajl_gen_map_close(g); // audit_data top-level key is finished -#endif /* AUDITLOG_PART_UPLOADS */ if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) { @@ -1559,67 +1293,40 @@ void sec_audit_logger(modsec_rec *msr) { unsigned int total_size = 0; int cfiles = 0; -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_UPLOADS); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "uploads"); yajl_gen_map_open(g); -#endif parts = (multipart_part **)msr->mpd->parts->elts; -#ifdef WITH_JSON_LOGGING yajl_string(g, "info"); yajl_gen_array_open(g); // separate array for upload info -#endif for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) { if (parts[cfiles]->type == MULTIPART_FILE) { if(parts[cfiles]->filename != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%d,%u,\"%s\",\"%s\"\n", cfiles+1, parts[cfiles]->tmp_file_size, log_escape(msr->mp, parts[cfiles]->filename), log_escape(msr->mp, parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown ContentType>")); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_kv_int(g, "file_size", parts[cfiles]->tmp_file_size); yajl_kv_string(g, "file_name", log_escape(msr->mp, parts[cfiles]->filename)); yajl_kv_string(g, "content_type", parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown Content-Type>"); -#endif total_size += parts[cfiles]->tmp_file_size; } } } -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "Total,%u\n", total_size); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_gen_array_close(g); // array for upload info is finished yajl_kv_int(g, "total", total_size); yajl_gen_map_close(g); // uploads top-level key is finished -#endif } /* AUDITLOG_PART_MATCHEDRULES */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES); - sec_auditlog_write(msr, text, strlen(text)); -#else yajl_string(g, "matched_rules"); yajl_gen_array_open(g); // matched_rules top-level key -#endif /* Matched Rules */ for(i = 0; i < msr->matched_rules->nelts; i++) { rule = ((msre_rule **)msr->matched_rules->elts)[i]; if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\n", rule->unparsed); - sec_auditlog_write(msr, text, strlen(text)); -#else write_rule_json(msr, rule, g); -#endif do { if (rule->ruleset != NULL) { @@ -1629,50 +1336,26 @@ void sec_audit_logger(modsec_rec *msr) { present = chained_is_matched(msr,next_rule); - if (present == 0) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "#%s\n",next_rule->unparsed); -#endif - } else { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\n",next_rule->unparsed); -#endif + if (present == 1) { i++; } -#ifndef WITH_JSON_LOGGING - sec_auditlog_write(msr, text, strlen(text)); -#else write_rule_json(msr, next_rule, g); -#endif } } rule = next_rule; } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained); -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n"); - sec_auditlog_write(msr, text, strlen(text)); -#endif } else { if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) { -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "%s\n\n", rule->unparsed); - sec_auditlog_write(msr, text, strlen(text)); -#else write_rule_json(msr, rule, g); -#endif } } } -#ifdef WITH_JSON_LOGGING yajl_gen_array_close(g); // matched_rules top-level key is finished -#endif } /* AUDITLOG_PART_ENDMARKER */ -#ifndef WITH_JSON_LOGGING - text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER); - sec_auditlog_write(msr, text, strlen(text)); -#else + + /* finished building JSON */ yajl_gen_map_close(g); // box it up! const unsigned char *final_buf; @@ -1682,7 +1365,6 @@ void sec_audit_logger(modsec_rec *msr) { yajl_gen_clear(g); yajl_gen_free(g); -#endif /* Return here if we were writing to a serial log * as it does not need an index file. @@ -1760,3 +1442,775 @@ void sec_audit_logger(modsec_rec *msr) { apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written); } } + +/* + * Produce an audit log entry in native format. + */ +void sec_audit_logger_native(modsec_rec *msr) { + const apr_array_header_t *arr = NULL; + apr_table_entry_t *te = NULL; + const apr_array_header_t *tarr_pattern = NULL; + const apr_table_entry_t *telts_pattern = NULL; + char *str1 = NULL, *str2 = NULL, *text = NULL; + const msre_rule *rule = NULL, *next_rule = NULL; + apr_size_t nbytes, nbytes_written; + unsigned char md5hash[APR_MD5_DIGESTSIZE]; + int was_limited = 0; + int present = 0; + int wrote_response_body = 0; + char *entry_filename, *entry_basename; + apr_status_t rc; + int i, limit, k, sanitized_partial, j; + char *buf = NULL, *pat = NULL; + msc_parm *mparm = NULL; + int arg_min, arg_max, sanitize_matched; + + /* the boundary is used by both audit log types */ + msr->new_auditlog_boundary = create_auditlog_boundary(msr->r); + + /* Return silently if we don't have a request line. This + * means we will not be logging request timeouts. + */ + if (msr->request_line == NULL) { + msr_log(msr, 4, "Audit log: Skipping request whose request_line is null."); + return; + } + + /* Also return silently if we don't have a file descriptor. */ + if (msr->txcfg->auditlog_fd == NULL) { + msr_log(msr, 4, "Audit log: Skipping request since there is nowhere to write to."); + return; + } + + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + /* Serial logging - we already have an open file + * descriptor to write to. + */ + msr->new_auditlog_fd = msr->txcfg->auditlog_fd; + } else { + /* Concurrent logging - we need to create a brand + * new file for this request. + */ + apr_md5_init(&msr->new_auditlog_md5ctx); + + msr->new_auditlog_filename = construct_auditlog_filename(msr->mp, msr->txid); + if (msr->new_auditlog_filename == NULL) return; + + /* The audit log storage directory should be explicitly + * defined. But if it isn't try to write to the same + * directory where the index file is placed. Of course, + * it is *very* bad practice to allow the Apache user + * to write to the same directory where a root user is + * writing to but it's not us that's causing the problem + * and there isn't anything we can do about that. + * + * ENH Actually there is something we can do! We will make + * SecAuditStorageDir mandatory, ask the user to explicitly + * define the storage location *and* refuse to work if the + * index and the storage location are in the same folder. + */ + if (msr->txcfg->auditlog_storage_dir == NULL) { + entry_filename = file_dirname(msr->mp, msr->txcfg->auditlog_name); + } + else { + entry_filename = msr->txcfg->auditlog_storage_dir; + } + if (entry_filename == NULL) return; + + entry_filename = apr_psprintf(msr->mp, "%s%s", entry_filename, msr->new_auditlog_filename); + if (entry_filename == NULL) return; + entry_basename = file_dirname(msr->mp, entry_filename); + if (entry_basename == NULL) return; + + /* IMP1 Surely it would be more efficient to check the folders for + * the audit log repository base path in the configuration phase, to reduce + * the work we do on every request. Also, since our path depends on time, + * we could cache the time we last checked and don't check if we know + * the folder is there. + */ + rc = apr_dir_make_recursive(entry_basename, msr->txcfg->auditlog_dirperms, msr->mp); + if ((rc != APR_SUCCESS) && (rc != APR_EEXIST)) { + msr_log(msr, 1, "Audit log: Failed to create subdirectories: %s (%s)", + entry_basename, get_apr_error(msr->mp, rc)); + return; + } + + rc = apr_file_open(&msr->new_auditlog_fd, entry_filename, + APR_WRITE | APR_TRUNCATE | APR_CREATE | APR_BINARY | APR_FILE_NOCLEANUP, + msr->txcfg->auditlog_fileperms, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to create file: %s (%s)", + entry_filename, get_apr_error(msr->mp, rc)); + return; + } + } + + /* Lock the mutex, but only if we are using serial format. */ + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", + get_apr_error(msr->mp, rc)); + } + } + + + /* AUDITLOG_PART_HEADER */ + text = apr_psprintf(msr->mp, "--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_HEADER); + sec_auditlog_write(msr, text, strlen(text)); + /* Format: time transaction_id remote_addr remote_port local_addr local_port */ + + text = apr_psprintf(msr->mp, "[%s] %s %s %u %s %u", + current_logtime(msr->mp), msr->txid, msr->remote_addr, msr->remote_port, + msr->local_addr, msr->local_port); + sec_auditlog_write(msr, text, strlen(text)); + + /* AUDITLOG_PART_REQUEST_HEADERS */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_HEADERS) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_HEADERS); + sec_auditlog_write(msr, text, strlen(text)); + + sanitize_request_line(msr); + sec_auditlog_write(msr, msr->request_line, strlen(msr->request_line)); + sec_auditlog_write(msr, "\n", 1); + + + arr = apr_table_elts(msr->request_headers); + te = (apr_table_entry_t *)arr->elts; + + tarr_pattern = apr_table_elts(msr->pattern_to_sanitize); + telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts; + + for (i = 0; i < arr->nelts; i++) { + sanitized_partial = 0; + sanitize_matched = 0; + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); + if (apr_table_get(msr->request_headers_to_sanitize, te[i].key) != NULL) { + buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); + for ( k = 0; k < tarr_pattern->nelts; k++) { + if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) { + mparm = (msc_parm *)telts_pattern[k].val; + if(mparm->pad_1 == -1) + sanitize_matched = 1; + pat = strstr(buf,mparm->value); + if (pat != NULL) { + j = strlen(mparm->value); + arg_min = j; + arg_max = 1; + while((*pat != '\0')&&(j--)) { + if(arg_max > mparm->pad_2) { + int off = strlen(mparm->value) - arg_max; + int pos = mparm->pad_1-1; + if(off > pos) { + *pat = '*'; + } + } + arg_max++; + arg_min--; + pat++; + } + sanitized_partial = 1; + } + } + } + + if(sanitized_partial == 1 && sanitize_matched == 0) { + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); + } else { + memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); + } + } + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* AUDITLOG_PART_REQUEST_BODY */ + + /* Output this part of it was explicitly requested (C) or if it was the faked + * request body that was requested (I) but we have no reason to fake it (it's + * already in the correct format). + */ + if ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_REQUEST_BODY) != NULL) + || ( (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) + && (msr->mpd == NULL) ) ) + { + if (msr->msc_reqbody_read) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + apr_array_header_t *sorted_args; + unsigned int offset = 0, last_offset = 0; + msc_arg *nextarg = NULL; + int sanitize = 0; /* IMP1 Use constants for "sanitize" values. */ + char *my_error_msg = NULL; + + sorted_args = apr_array_make(msr->mp, 25, sizeof(const msc_arg *)); + + /* First we need to sort the arguments that need to be + * sanitized in descending order (we are using a stack structure + * to store then so the order will be ascending when we start + * popping them out). This is because we will + * be reading the request body sequentially and must + * sanitize it as we go. + */ + + for(;;) { + nextarg = NULL; + + /* Find the next largest offset (excluding + * the ones we've used up already). + */ + tarr = apr_table_elts(msr->arguments_to_sanitize); + telts = (const apr_table_entry_t*)tarr->elts; + for(i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + if (arg->origin != NULL && + strcmp(arg->origin, "BODY") != 0) + continue; + + if (last_offset == 0) { /* The first time we're here. */ + if (arg->value_origin_offset > offset) { + offset = arg->value_origin_offset; + nextarg = arg; + } + } else { /* Not the first time. */ + if ((arg->value_origin_offset > offset) + &&(arg->value_origin_offset < last_offset)) + { + offset = arg->value_origin_offset; + nextarg = arg; + } + } + } + + /* If we don't have the next argument that means + * we're done here. + */ + if (nextarg == NULL) break; + + sanitize = 2; /* Means time to pop the next argument out. */ + last_offset = offset; + offset = 0; + { /* IMP1 Fix this ugly bit here. */ + msc_arg **x = apr_array_push(sorted_args); + *x = nextarg; + } + } + + /* Now start retrieving the body chunk by chunk and + * sanitize data in pieces. + */ + + rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg); + if (rc < 0) { + msr_log(msr, 1, "Audit log: %s", my_error_msg); + } else { + msc_data_chunk *chunk = NULL; + unsigned int chunk_offset = 0; + unsigned int sanitize_offset = 0; + unsigned int sanitize_length = 0; + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_REQUEST_BODY); + sec_auditlog_write(msr, text, strlen(text)); + + for(;;) { + rc = modsecurity_request_body_retrieve(msr, &chunk, -1, &my_error_msg); + if (chunk != NULL) { + /* Anything greater than 1 means we have more data to sanitize. */ + while (sanitize > 1) { + msc_arg **arg = NULL; + + if (sanitize == 2) { + /* Get the next argument from the stack. */ + arg = (msc_arg **)apr_array_pop(sorted_args); + if (arg == NULL) sanitize = 0; /* We're done sanitising. */ + else { + /* Continue with sanitation to process the + * retrieved argument. + */ + sanitize = 1; + sanitize_offset = (*arg)->value_origin_offset; + sanitize_length = (*arg)->value_origin_len; + } + } + + if (sanitize) { + /* Check if the data we want to sanitize is + * stored in the current chunk. + */ + if (chunk_offset + chunk->length > sanitize_offset) { + unsigned int soff; /* data offset within chunk */ + unsigned int len; /* amount in this chunk to sanitize */ + + soff = sanitize_offset - chunk_offset; + + if (soff + sanitize_length <= chunk->length) { + /* The entire argument resides in the current chunk. */ + len = sanitize_length; + sanitize = 2; /* Get another parameter to sanitize. */ + } else { + /* Some work to do here but we'll need to seek + * another chunk. + */ + len = chunk->length - soff; + sanitize_offset += len; + sanitize_length -= len; + sanitize = 1; /* It's OK to go to the next chunk. */ + } + + /* Yes, we actually write over the original data. + * We shouldn't be needing it any more. + */ + if (soff + len <= chunk->length) { /* double check */ + memset((char *)chunk->data + soff, '*', len); + } + } + } + } + + /* Write the sanitized chunk to the log + * and advance to the next chunk. */ + sec_auditlog_write(msr, chunk->data, chunk->length); + chunk_offset += chunk->length; + } + + if (rc <= 0) { + break; + } + } + + if (rc < 0) { + msr_log(msr, 1, "Audit log: %s", my_error_msg); + } + + modsecurity_request_body_retrieve_end(msr); + } + } + } + + /* AUDITLOG_PART_FAKE_REQUEST_BODY */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_FAKE_REQUEST_BODY) != NULL) { + if ((msr->msc_reqbody_read)&&(msr->mpd != NULL)) { + char *buffer = NULL; + + buffer = multipart_reconstruct_urlencoded_body_sanitize(msr); + if (buffer == NULL) { + msr_log(msr, 1, "Audit log: Failed to reconstruct request body."); + } else { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_FAKE_REQUEST_BODY); + sec_auditlog_write(msr, text, strlen(text)); + sec_auditlog_write(msr, buffer, strlen(buffer)); + } + } + } + + /* AUDITLOG_PART_A_RESPONSE_HEADERS */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_A_RESPONSE_HEADERS) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_A_RESPONSE_HEADERS); + sec_auditlog_write(msr, text, strlen(text)); + + /* There are no response headers (or the status line) in HTTP 0.9 */ + if (msr->response_headers_sent) { + if (msr->status_line != NULL) { + text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, + msr->status_line); + } else { + text = apr_psprintf(msr->mp, "%s %u\n", msr->response_protocol, + msr->response_status); + } + sec_auditlog_write(msr, text, strlen(text)); + + /* Output headers */ + + arr = apr_table_elts(msr->response_headers); + te = (apr_table_entry_t *)arr->elts; + + tarr_pattern = apr_table_elts(msr->pattern_to_sanitize); + telts_pattern = (const apr_table_entry_t*)tarr_pattern->elts; + + for (i = 0; i < arr->nelts; i++) { + sanitized_partial = 0; + sanitize_matched = 0; + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, te[i].val); + if (apr_table_get(msr->response_headers_to_sanitize, te[i].key) != NULL) { + buf = apr_psprintf(msr->mp, "%s",text+strlen(te[i].key)+2); + + for ( k = 0; k < tarr_pattern->nelts; k++) { + if(strncmp(telts_pattern[k].key,te[i].key,strlen(te[i].key)) ==0 ) { + mparm = (msc_parm *)telts_pattern[k].val; + if(mparm->pad_1 == -1) + sanitize_matched = 1; + pat = strstr(buf,mparm->value); + if (pat != NULL) { + j = strlen(mparm->value); + arg_min = j; + arg_max = 1; + while((*pat != '\0')&&(j--)) { + if(arg_max > mparm->pad_2) { + int off = strlen(mparm->value) - arg_max; + int pos = mparm->pad_1-1; + if(off > pos) { + *pat = '*'; + } + } + arg_max++; + arg_min--; + pat++; + } + sanitized_partial = 1; + } + } + } + + if(sanitized_partial == 1 && sanitize_matched == 0) { + text = apr_psprintf(msr->mp, "%s: %s\n", te[i].key, buf); + } else { + memset(text + strlen(te[i].key) + 2, '*', strlen(te[i].val)); + } + } + sec_auditlog_write(msr, text, strlen(text)); + } + } + } + + apr_table_clear(msr->pattern_to_sanitize); + + /* AUDITLOG_PART_RESPONSE_BODY */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_RESPONSE_BODY) != NULL) { + if (msr->resbody_data != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_RESPONSE_BODY); + sec_auditlog_write(msr, text, strlen(text)); + sec_auditlog_write(msr, msr->resbody_data, msr->resbody_length); + wrote_response_body = 1; + } + } + + /* AUDITLOG_PART_TRAILER */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) { + apr_time_t now = apr_time_now(); + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_TRAILER); + sec_auditlog_write(msr, text, strlen(text)); + + /* Messages */ + for(i = 0; i < msr->alerts->nelts; i++) { + text = apr_psprintf(msr->mp, "Message: %s\n", ((char **)msr->alerts->elts)[i]); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Apache error messages */ + for(i = 0; i < msr->error_messages->nelts; i++) { + error_message_t *em = (((error_message_t **)msr->error_messages->elts)[i]); + text = apr_psprintf(msr->mp, "Apache-Error: %s\n", + format_error_log_message(msr->mp, em)); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Action */ + if (msr->was_intercepted) { + text = apr_psprintf(msr->mp, "Action: Intercepted (phase %d)\n", msr->intercept_phase); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Apache-Handler */ + if (msr->r->handler != NULL) { + text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Stopwatch; left in for compatibility reasons */ + text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", + msr->request_time, (now - msr->request_time)); + sec_auditlog_write(msr, text, strlen(text)); + + /* Stopwatch2 */ + { + char *perf_all = format_all_performance_variables(msr, msr->mp); + + text = apr_psprintf(msr->mp, "Stopwatch2: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT + "; %s\n", msr->request_time, (now - msr->request_time), perf_all); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Our response body does not contain chunks */ + /* ENH Only write this when the output was chunked. */ + /* ENH Add info when request body was decompressed, dechunked too. */ + if (wrote_response_body) { + text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n"); + sec_auditlog_write(msr, text, strlen(text)); + } + + sec_auditlog_write_producer_header(msr); + + /* Server */ + if (msr->server_software != NULL) { + text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Sanitised arguments */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->arguments_to_sanitize); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Args: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + msc_arg *arg = (msc_arg *)telts[i].val; + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, arg->name), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Sanitised request headers */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->request_headers_to_sanitize); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Request-Headers: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Sanitised response headers */ + { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->response_headers_to_sanitize); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Sanitised-Response-Headers: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s\"%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, telts[i].key), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + + /* Web application info. */ + if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) + || (msr->sessionid != NULL) || (msr->userid != NULL)) + { + text = apr_psprintf(msr->mp, "WebApp-Info: \"%s\" \"%s\" \"%s\"\n", + msr->txcfg->webappid == NULL ? "-" : log_escape(msr->mp, msr->txcfg->webappid), + msr->sessionid == NULL ? "-" : log_escape(msr->mp, msr->sessionid), + msr->userid == NULL ? "-" : log_escape(msr->mp, msr->userid)); + sec_auditlog_write(msr, text, strlen(text)); + } + + if ( ((msr->txcfg->sensor_id != NULL)&&(strcmp(msr->txcfg->sensor_id, "default") != 0))) + { + text = apr_psprintf(msr->mp, "Sensor-Id: \"%s\"\n", + msr->txcfg->sensor_id == NULL ? "-" : log_escape(msr->mp, msr->txcfg->sensor_id)), + sec_auditlog_write(msr, text, strlen(text)); + } + + + if (msr->txcfg->is_enabled > 0) { + text = apr_psprintf(msr->mp, "Engine-Mode: \"%s\"\n", + msr->txcfg->is_enabled == 1 ? "DETECTION_ONLY" : "ENABLED"), + sec_auditlog_write(msr, text, strlen(text)); + } + + /* Rule performance time */ + if(msr->txcfg->max_rule_time > 0) { + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + + tarr = apr_table_elts(msr->perf_rules); + telts = (const apr_table_entry_t*)tarr->elts; + + if (tarr->nelts > 0) { + text = apr_psprintf(msr->mp, "Rules-Performance-Info: "); + sec_auditlog_write(msr, text, strlen(text)); + } + + for(i = 0; i < tarr->nelts; i++) { + text = apr_psprintf(msr->mp, "%s\"%s=%s\"%s", ((i == 0) ? "" : ", "), + log_escape(msr->mp, telts[i].key), log_escape(msr->mp, telts[i].val), ((i == (tarr->nelts - 1)) ? ".\n" : "")); + sec_auditlog_write(msr, text, strlen(text)); + } + } + } + + /* AUDITLOG_PART_UPLOADS */ + if ((strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_UPLOADS) != NULL) && (msr->mpd != NULL)) { + multipart_part **parts = NULL; + unsigned int total_size = 0; + int cfiles = 0; + + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_UPLOADS); + sec_auditlog_write(msr, text, strlen(text)); + + parts = (multipart_part **)msr->mpd->parts->elts; + for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) { + if (parts[cfiles]->type == MULTIPART_FILE) { + if(parts[cfiles]->filename != NULL) { + text = apr_psprintf(msr->mp, "%d,%u,\"%s\",\"%s\"\n", cfiles+1, parts[cfiles]->tmp_file_size, log_escape(msr->mp, parts[cfiles]->filename), log_escape(msr->mp, parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown ContentType>")); + sec_auditlog_write(msr, text, strlen(text)); + total_size += parts[cfiles]->tmp_file_size; + } + } + } + text = apr_psprintf(msr->mp, "Total,%u\n", total_size); + sec_auditlog_write(msr, text, strlen(text)); + } + + /* AUDITLOG_PART_MATCHEDRULES */ + + if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_MATCHEDRULES) != NULL) { + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_MATCHEDRULES); + sec_auditlog_write(msr, text, strlen(text)); + + /* Matched Rules */ + + for(i = 0; i < msr->matched_rules->nelts; i++) { + rule = ((msre_rule **)msr->matched_rules->elts)[i]; + if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) { + text = apr_psprintf(msr->mp, "%s\n", rule->unparsed); + sec_auditlog_write(msr, text, strlen(text)); + do { + if (rule->ruleset != NULL) { + + next_rule = return_chained_rule(rule,msr); + + if (next_rule != NULL) { + + present = chained_is_matched(msr,next_rule); + + if (present == 0) { + text = apr_psprintf(msr->mp, "#%s\n",next_rule->unparsed); + } else { + text = apr_psprintf(msr->mp, "%s\n",next_rule->unparsed); + i++; + } + sec_auditlog_write(msr, text, strlen(text)); + } + } + rule = next_rule; + } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained); + text = apr_psprintf(msr->mp, "\n"); + sec_auditlog_write(msr, text, strlen(text)); + } else { + if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) { + text = apr_psprintf(msr->mp, "%s\n\n", rule->unparsed); + sec_auditlog_write(msr, text, strlen(text)); + } + } + } + } + /* AUDITLOG_PART_ENDMARKER */ + text = apr_psprintf(msr->mp, "\n--%s-%c--\n", msr->new_auditlog_boundary, AUDITLOG_PART_ENDMARKER); + sec_auditlog_write(msr, text, strlen(text)); + + /* Return here if we were writing to a serial log + * as it does not need an index file. + */ + if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { + sec_auditlog_write(msr, "\n", 1); + + /* Unlock the mutex we used to serialise access to the audit log file. */ + rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", + get_apr_error(msr->mp, rc)); + } + + return; + } + + /* From here on only concurrent-style processing. */ + + /* File handle might already be closed after write failure. */ + if (msr->new_auditlog_fd) { + apr_file_close(msr->new_auditlog_fd); + } + + /* Write an entry to the index file */ + + /* Calculate hash of the entry. */ + apr_md5_final(md5hash, &msr->new_auditlog_md5ctx); + + str2 = apr_psprintf(msr->mp, "%s %d %d md5:%s", msr->new_auditlog_filename, 0, + msr->new_auditlog_size, bytes2hex(msr->mp, md5hash, 16)); + if (str2 == NULL) return; + + /* We do not want the index line to be longer than 3980 bytes. */ + limit = 3980; + was_limited = 0; + + /* If we are logging to a pipe we need to observe and + * obey the pipe atomic write limit - PIPE_BUF. For + * more details see the discussion in sec_guardian_logger code. + */ + if (msr->txcfg->auditlog_name[0] == '|') { + if (PIPE_BUF < limit) { + limit = PIPE_BUF; + } + } + + limit = limit - strlen(str2) - 5; + if (limit <= 0) { + msr_log(msr, 1, "Audit Log: Atomic PIPE write buffer too small: %d", PIPE_BUF); + return; + } + + str1 = construct_log_vcombinedus_limited(msr, limit, &was_limited); + if (str1 == NULL) return; + + if (was_limited == 0) { + text = apr_psprintf(msr->mp, "%s %s \n", str1, str2); + } else { + text = apr_psprintf(msr->mp, "%s %s L\n", str1, str2); + } + if (text == NULL) return; + + nbytes = strlen(text); + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to primary concurrent index", nbytes); + } + apr_file_write_full(msr->txcfg->auditlog_fd, text, nbytes, &nbytes_written); + + /* Write to the secondary audit log if we have one */ + if (msr->txcfg->auditlog2_fd != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Audit Log: Writing %" APR_SIZE_T_FMT " bytes to secondary concurrent index", nbytes); + } + apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written); + } +} + +/* + * Handler for audit log writers. + */ +void sec_audit_logger(modsec_rec *msr) { + if (msr->txcfg->auditlog_format == AUDITLOGFORMAT_JSON) { + sec_audit_logger_json(msr); + } else { + sec_audit_logger_native(msr); + } +} diff --git a/apache2/msc_logging.h b/apache2/msc_logging.h index 75af9da7ae..9b1b48853a 100644 --- a/apache2/msc_logging.h +++ b/apache2/msc_logging.h @@ -22,6 +22,9 @@ #define AUDITLOG_SERIAL 0 #define AUDITLOG_CONCURRENT 1 +#define AUDITLOGFORMAT_JSON 0 +#define AUDITLOGFORMAT_NATIVE 1 + #define AUDITLOG_PART_FIRST 'A' #define AUDITLOG_PART_HEADER 'A' #define AUDITLOG_PART_REQUEST_HEADERS 'B' diff --git a/configure.ac b/configure.ac index bb2e42e34a..b188cb11e4 100644 --- a/configure.ac +++ b/configure.ac @@ -275,22 +275,6 @@ if test "$build_docs" -eq 1; then TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS docs" fi -# Add JSON audit logging -AC_ARG_ENABLE(json-logging, - AS_HELP_STRING([--enabled-json-logging], - [Enable JSON audit logging.]), -[ - if test "$enableval" != "no"; then - json_logging='-DWITH_JSON_LOGGING' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $json_logging" - else - json_logging='' - fi -], -[ - json_logging='' -]) - # Add PCRE Studying AC_ARG_ENABLE(pcre-study, @@ -674,7 +658,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$json_logging $pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" for f in $EXTRA_CFLAGS; do From 8559399ebdf4364a9ec73e3c88f92de2f48c017c Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Sun, 19 Jul 2015 00:09:37 -0700 Subject: [PATCH 039/477] Update JSON structure for matched rules Create a separate map for each matched rule chain, making it easier to identify chains in which only a portion of rules actually matched. --- apache2/msc_logging.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index a1911f65ea..edc771be1a 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1326,6 +1326,15 @@ void sec_audit_logger_json(modsec_rec *msr) { for(i = 0; i < msr->matched_rules->nelts; i++) { rule = ((msre_rule **)msr->matched_rules->elts)[i]; if ((rule != NULL) && (rule->actionset != NULL) && rule->actionset->is_chained && (rule->chain_starter == NULL)) { + /* + * create a separate map for each rule chain + * this makes it a lot easier to search for partial chains + */ + yajl_gen_map_open(g); // map for this chain + yajl_kv_bool(g, "chain", 1); + yajl_string(g, "rules"); + yajl_gen_array_open(g); // array for the rules + write_rule_json(msr, rule, g); do { if (rule->ruleset != NULL) { @@ -1344,10 +1353,23 @@ void sec_audit_logger_json(modsec_rec *msr) { } rule = next_rule; } while (rule != NULL && rule->actionset != NULL && rule->actionset->is_chained); + yajl_gen_array_close(g); + + yajl_kv_bool(g, "full_chain_match", present); // if one of the rules didnt match, present is set to 0 + yajl_gen_map_close(g); // close the map for this chain } else { + yajl_gen_map_open(g); + + yajl_kv_bool(g, "chain", 0); + yajl_string(g, "rules"); // this really should be 'rule', but we're keeping in line with other chain maps + + yajl_gen_array_open(g); if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) { write_rule_json(msr, rule, g); } + yajl_gen_array_close(g); + + yajl_gen_map_close(g); } } yajl_gen_array_close(g); // matched_rules top-level key is finished From 0c95a7a2cde10e3cbe77c45f26b7a19b980f34c8 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 22 Jul 2015 13:14:00 -0700 Subject: [PATCH 040/477] Clean up JSON rule writer * Escape rule actionset metadata * Escape and truncate logdata * Lazily add actionset tags as an array * Add negated rule op_param * Add unparsed rule representation --- apache2/msc_logging.c | 64 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index edc771be1a..771b52b59e 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -539,26 +539,49 @@ static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { * Write detailed information about a rule and its actionset into a JSON generator */ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) { - int present = 0; + const apr_array_header_t *tarr; + const apr_table_entry_t *telts; + int been_opened = 0; + int k; yajl_gen_map_open(g); yajl_string(g, "actionset"); yajl_gen_map_open(g); if (rule->actionset->id) { - yajl_kv_string(g, "id", rule->actionset->id); + yajl_kv_string(g, "id", log_escape(msr->mp, rule->actionset->id)); } if (rule->actionset->rev) { - yajl_kv_string(g, "rev", rule->actionset->rev); + yajl_kv_string(g, "rev", log_escape(msr->mp, rule->actionset->rev)); } if (rule->actionset->msg) { - yajl_kv_string(g, "msg", rule->actionset->msg); + msc_string *var = (msc_string *)apr_palloc(msr->mp, sizeof(msc_string)); + var->value = (char *)rule->actionset->msg; + var->value_len = strlen(rule->actionset->msg); + expand_macros(msr, var, NULL, msr->mp); + + yajl_kv_string(g, "msg", log_escape_ex(msr->mp, var->value, var->value_len)); } if (rule->actionset->version) { - yajl_kv_string(g, "version", rule->actionset->version); + yajl_kv_string(g, "version", log_escape(msr->mp, rule->actionset->version)); } if (rule->actionset->logdata) { - yajl_kv_string(g, "logdata", rule->actionset->logdata); + msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->value = (char *)rule->actionset->logdata; + var->value_len = strlen(rule->actionset->logdata); + expand_macros(msr, var, NULL, msr->mp); + + char *logdata = apr_pstrdup(msr->mp, log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); + + // if it is > 512 bytes, then truncate at 512 with ellipsis. + if (strlen(logdata) > 515) { + logdata[512] = '.'; + logdata[513] = '.'; + logdata[514] = '.'; + logdata[515] = '\0'; + } + + yajl_kv_string(g, "logdata", logdata); } if (rule->actionset->severity != NOT_SET) { yajl_kv_int(g, "severity", rule->actionset->severity); @@ -576,6 +599,33 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) if (rule->actionset->is_chained && (rule->chain_starter == NULL)) { yajl_kv_bool(g, "chain_starter", 1); } + + // tags, lazily opened + tarr = apr_table_elts(rule->actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + for (k = 0; k < tarr->nelts; k++) { + msre_action *action = (msre_action *)telts[k].val; + if (strcmp(telts[k].key, "tag") == 0) { + if (been_opened == 0) { + yajl_string(g, "tags"); + yajl_gen_array_open(g); + been_opened = 1; + } + + // expand variables in the tag + msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->value = (char *)action->param; + var->value_len = strlen(action->param); + expand_macros(msr, var, NULL, msr->mp); + + yajl_string(g, log_escape(msr->mp, var->value)); + } + } + + if (been_opened == 1) { + yajl_gen_array_close(g); + } + yajl_gen_map_close(g); yajl_string(g, "operator"); @@ -583,6 +633,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) yajl_kv_string(g, "operator", rule->op_name); yajl_kv_string(g, "operator_param", rule->op_param); yajl_kv_string(g, "target", rule->p1); + yajl_kv_bool(g, "negated", rule->op_negated); yajl_gen_map_close(g); yajl_string(g, "config"); @@ -591,6 +642,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) yajl_kv_int(g, "line_num", rule->line_num); yajl_gen_map_close(g); + yajl_kv_string(g, "unparsed", rule->unparsed); yajl_kv_bool(g, "is_matched", chained_is_matched(msr, rule)); yajl_gen_map_close(g); From 5bc75ec871814d3963ed86c79e71fab88c5de228 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 10 Nov 2015 11:12:42 -0800 Subject: [PATCH 041/477] Do not compile in JSON logging support if yajl is not found --- apache2/apache2_config.c | 10 ++++++++++ apache2/modsecurity.h | 2 ++ apache2/msc_logging.c | 10 ++++++++++ apache2/msc_logging.h | 2 ++ 4 files changed, 24 insertions(+) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index e38cf4e97a..3ab618a9e2 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -73,7 +73,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) /* audit log variables */ dcfg->auditlog_flag = NOT_SET; dcfg->auditlog_type = NOT_SET; + #ifdef WITH_YAJL dcfg->auditlog_format = NOT_SET; + #endif dcfg->max_rule_time = NOT_SET; dcfg->auditlog_dirperms = NOT_SET; dcfg->auditlog_fileperms = NOT_SET; @@ -504,8 +506,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->auditlog2_fd = parent->auditlog2_fd; merged->auditlog2_name = parent->auditlog2_name; } + #ifdef WITH_YAJL merged->auditlog_format = (child->auditlog_format == NOT_SET ? parent->auditlog_format : child->auditlog_format); + #endif merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P ? parent->auditlog_storage_dir : child->auditlog_storage_dir); merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P @@ -670,7 +674,9 @@ void init_directory_config(directory_config *dcfg) /* audit log variables */ if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + #ifdef WITH_YAJL if (dcfg->auditlog_format == NOT_SET) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; + #endif if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0; if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; @@ -1295,6 +1301,7 @@ static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, return NULL; } +#ifdef WITH_YAJL static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, const char *p1) { @@ -1309,6 +1316,7 @@ static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, return NULL; } +#endif static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) @@ -3251,6 +3259,7 @@ const command_rec module_directives[] = { "whether to use the old audit log format (Serial) or new (Concurrent)" ), +#ifdef WITH_YAJL AP_INIT_TAKE1 ( "SecAuditLogFormat", cmd_audit_log_mode, @@ -3258,6 +3267,7 @@ const command_rec module_directives[] = { CMD_SCOPE_ANY, "whether to emit audit log data in native format or JSON" ), +#endif AP_INIT_TAKE1 ( "SecAuditLogStorageDir", diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index bc015f9345..228bea0b22 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -519,8 +519,10 @@ struct directory_config { /* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */ int auditlog_type; +#ifdef WITH_YAJL /* AUDITLOGFORMAT_NATIVE or AUDITLOGFORMAT_JSON */ int auditlog_format; +#endif /* Mode for audit log directories and files */ apr_fileperms_t auditlog_dirperms; diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 771b52b59e..6a03d8181e 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -25,8 +25,10 @@ #include "apr_version.h" #include <libxml/xmlversion.h> +#ifdef WITH_YAJL #include <yajl/yajl_gen.h> #include "msc_logging_json.h" +#endif /** * Write the supplied data to the audit log (if the FD is ready), update @@ -384,6 +386,7 @@ static void sec_auditlog_write_producer_header(modsec_rec *msr) { sec_auditlog_write(msr, ".\n", 2); } +#ifdef WITH_YAJL /** * Ouput the Producer header into a JSON generator */ @@ -415,6 +418,7 @@ static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) yajl_gen_array_close(g); // array for producers is finished } +#endif /* * \brief This function will returns the next chain node @@ -515,6 +519,7 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { return 0; } +#ifdef WITH_YAJL /** * Write detailed information about performance metrics into a JSON generator */ @@ -1516,6 +1521,7 @@ void sec_audit_logger_json(modsec_rec *msr) { apr_file_write_full(msr->txcfg->auditlog2_fd, text, nbytes, &nbytes_written); } } +#endif /* * Produce an audit log entry in native format. @@ -2282,9 +2288,13 @@ void sec_audit_logger_native(modsec_rec *msr) { * Handler for audit log writers. */ void sec_audit_logger(modsec_rec *msr) { + #ifdef WITH_YAJL if (msr->txcfg->auditlog_format == AUDITLOGFORMAT_JSON) { sec_audit_logger_json(msr); } else { + #endif sec_audit_logger_native(msr); + #ifdef WITH_YAJL } + #endif } diff --git a/apache2/msc_logging.h b/apache2/msc_logging.h index 9b1b48853a..5378ddc659 100644 --- a/apache2/msc_logging.h +++ b/apache2/msc_logging.h @@ -22,8 +22,10 @@ #define AUDITLOG_SERIAL 0 #define AUDITLOG_CONCURRENT 1 +#ifdef WITH_YAJL #define AUDITLOGFORMAT_JSON 0 #define AUDITLOGFORMAT_NATIVE 1 +#endif #define AUDITLOG_PART_FIRST 'A' #define AUDITLOG_PART_HEADER 'A' From ddc25dbbaa7183c431059784c55b887da54f3785 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 10 Nov 2015 15:54:42 -0800 Subject: [PATCH 042/477] Fix 'is_chained' value for final rule in chain 'is_chained' should be true for an actionset when the is_chained member of the struct is true, or when its rule has a valid chain_starter member. --- apache2/msc_logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 6a03d8181e..ee7415da8d 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -600,7 +600,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) if (rule->actionset->phase != NOT_SET) { yajl_kv_int(g, "phase", rule->actionset->phase); } - yajl_kv_bool(g, "is_chained", rule->actionset->is_chained); + yajl_kv_bool(g, "is_chained", rule->actionset->is_chained || (rule->chain_starter != NULL)); if (rule->actionset->is_chained && (rule->chain_starter == NULL)) { yajl_kv_bool(g, "chain_starter", 1); } From 8f8645f3d64cfa1e2b52a0766f93fdc1f51e2e55 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 11 Nov 2015 08:17:59 -0800 Subject: [PATCH 043/477] Whitespace fix for pull request --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index b188cb11e4..7517885893 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,7 @@ if test "$build_docs" -eq 1; then TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS docs" fi + # Add PCRE Studying AC_ARG_ENABLE(pcre-study, @@ -659,6 +660,7 @@ else fi MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" + APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" for f in $EXTRA_CFLAGS; do From 2307a8b55be9dbea740239d06c7446aad8a7c613 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Fri, 4 Dec 2015 16:43:24 -0800 Subject: [PATCH 044/477] Add JSON log parse script --- tools/parse_modsec.pl | 576 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 576 insertions(+) create mode 100755 tools/parse_modsec.pl diff --git a/tools/parse_modsec.pl b/tools/parse_modsec.pl new file mode 100755 index 0000000000..3c5db51ff6 --- /dev/null +++ b/tools/parse_modsec.pl @@ -0,0 +1,576 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use DateTime::Format::Strptime; +use Getopt::Long qw(:config no_ignore_case bundling); +use JSON; +use List::MoreUtils qw(any); +use NetAddr::IP; +use Try::Tiny; + +=pod + +=head1 NAME + +parse_modsec.pl + +=head1 SYNOPSIS + +Parse ModSecurity logs generated as JSON + +=head1 USAGE + +Usage: $0 [h] [Gtsrfdbalspj] + -H|--host Search rules based on the Host request header + -t|--transaction-id Search rules based on the unique transaction ID + -s|--source-ip Search rules based on the client IP address (can be presented as an address or CIDR block) + -r|--rule-id Search rules based on the rule ID + -f|--filter Define advanced filters to walk through JSON tree + -d|--delim Define a delimiter for advanced filters. Default is '.' + -b|--before Search rules before this timeframe + -a|--after Search rules after this timeframe + -l|--logpath Define a path to read JSON logs from. Default is '/var/log/modsec_audit.log' + -S|--stdin Read rules from stdin instead of an on-disk file + -p|--partial-chains Do not prune partial chain matches + -j|--json Print rule entries as a JSON blob, rather than nice formatting + -v|--verbose Be verbose about various details such as JSON parse failures + + +=head2 FILTERS + +ModSecurity JSON audit logs are written as a series of atomic JSON documents, as opposed to a single, monolithic structure. This program will read through all JSON documents provided, making certain assumptions about the structure of each document, and will print out relevent entries based on the parameters provided. Log entries can be filtered by key-value pairs; given a key at an arbitrary level in the document, test the value of the key against an expected expression. The best way to understand this is with examples (see EXAMPLES for further details). + +Filter values are treated as regular expressions. Each match is anchored by '^' and'$', meaning that values that do not contain PCRE metacharacters will essentially match by string equality. + +Filters can be used to search a specific key-pair value, or an array of values. Arrays containing sub-elements can also be traversed. Arrays are identified in a filter key expression through the use of the '%' metacharacter. See EXAMPLES for further discussion of filter key expression syntax. + +Multiple filters can be provided, and are used in a logical AND manner (that is, an entry must match all given filters). + + +=head2 FILTER EXAMPLES + +Examine the following entry: + + { + "foo": "bar", + "foo2": "bar2", + "qux": { + "quux": "corge", + "grault": "garply", + "wal.do": "fred" + }, + "baz": [ + "bat", + "bam", + "bif" + ], + "bal": [ + { "hello": "world" }, + { "how": "are" }, + { "you": "doing" } + ] + } + +A search for the top level key "foo" containing the value "bar" would look like: + + -f foo=bar + +However, the following will not result in the entry being matched: + + -f foo=bar2 + +This is because the value of "foo" in the JSON document does not match the regex "^bar2$" + +Searching sub-keys is possible by providing the traversal path as the filter key, separated by a delimiter. By default the delimiter is '.'. For example, to search the value of the "grault" subkey within the "qux" key: + + -f qux.grault=<expression> + +Search arrays is also possible with the use of the '%' metacharacter, which should be used in place of a key name in the filter expression. For example, to search through all the values in the "baz" top-level key: + + -f baz.%=<expression> + +Searching for specific keys that are live in an array is also possible. For example, to search for the value of the "hello" key within the top-level key "bal" array: + + -f bal.%.hello=<expression> + +If any key contains a period character (.), you can specify an alternative delimiter using the '-d' option. To search the "wal.do" key within "qux": + + -d @ quz@wal.do=<expression> + + +=head2 SHORTCUTS + +Quick searches of on-disk log files likely will be performed using simple queries. Rather than forcing users to write a filter for common parameters, we provide a few shortcuts as options. These shortcuts can be combined with additional filters for complex searches. Provided shortcuts (and the matching filter key expression) are listed below: + + Host: request.headers.Host + Transaction ID: transaction.transaction_id + Rule ID: matched_rules.%.rules.%.actionset.id + +Additionally, the '--source-ip' argument allows for searching rule entries based on the remote IP address. This option searches based on CIDR blocks, instead of the filter searching described above. + +=head2 TIMEFRAME + +Log entries can further be narrowed by time range. The --before and --after flags can be used to return only entries that returned before or after (or both) a given date and time. Values for these options can be provided by the following syntax: + + ^\d+[dDhHmM]?$ + +For example, to limit the search of entries to between one and 4 days ago: + + -a 4d -b 1d + +You may provide one, both, or neither of these flags. + + +=head2 USAGE EXAMPLES + +Print all log entries from the default log location: + + parse_modsec.pl + +Print entries matching a specific source IP: + + parse_modsec.pl -s 1.2.3.4 + +Print entries matching a source IP in a given subnet: + + parse_modsec.pl -s 1.2.3.0/24 + +Print entries matching a given host and all its sub domains: + + parse_modsec.pl -H .*example.com + +Print entries matching a specific rule ID, that occurred within the last 12 hours: + + parse_modsec.pl -r 123456 -a 12h + +Print entries matching a given rule ID, even if that ID was present in a partial chain: + + parse_modsec.pl -r 123456 -p + +Print entries that contain an HTTP status code 403 + + parse_modsec.pl -f response.status=403 + +Print entries that contain an HTTP GET request with a 'Content-Length' header + + parse_modsec.pl -f request.headers.Content-Length=.* -f request.request_line=GET.* + +=cut + +sub usage { + print <<"_EOF"; +Usage: $0 [h] [Gtsrfdbalspj] + -h|--help Print this help + -H|--host Search rules based on the Host request header + -t|--transaction-id Search rules based on the unique transaction ID + -s|--source-ip Search rules based on the client IP address (can be presented as an address or CIDR block) + -r|--rule-id Search rules based on the rule ID + -f|--filter Define advanced filters to walk through JSON tree + -d|--delim Define a delimiter for advanced filters. Default is '.' + -b|--before Search rules before this timeframe + -a|--after Search rules after this timeframe + -l|--logpath Define a path to read JSON logs from. Default is '/var/log/modsec_audit.log' + -S|--stdin Read rules from stdin instead of an on-disk file + -p|--partial-chains Do not prune partial chain matches + -j|--json Print rule entries as a JSON blob, rather than nice formatting + -v|--verbose Be verbose about various details such as JSON parse failures + + For detailed explanations of various options and example usages, see 'perldoc $0' + +_EOF + exit 1; +} + +# figure the number of seconds based on the command-line option +sub parse_duration { + my ($duration) = @_; + + if ($duration =~ /^(\d+)[dD]$/) { + return $1 * 60 * 60 * 24; + } elsif ($duration =~ /^(\d+)[hH]$/) { + return $1 * 60 * 60; + } elsif ($duration =~ /^(\d+)[mM]$/) { + return $1 * 60; + } elsif ($duration =~ /^(\d+)[sS]?$/) { + return $1; + } else { + die "Couldn't parse duration $duration!\n"; + } +} + +# build a DateTime representative of the past +sub build_datetime { + my ($duration) = @_; + + return if !$duration; + return DateTime->now()->subtract(seconds => parse_duration($duration)); +} + +# determine if the log entry occurred within the given timeframe +sub within_timeframe { + my ($args) = @_; + my $entry = $args->{entry}; + my $before = $args->{before}; + my $after = $args->{after}; + my $timestamp = parse_modsec_timestamp($entry->{transaction}->{time}); + + return (defined $before ? $timestamp < $before : 1) && + (defined $after ? $timestamp > $after : 1); +} + +# sigh... +sub parse_modsec_timestamp { + my ($input) = @_; + + my $format = '%d/%b/%Y:%H:%M:%S -%z'; + my $locale = 'en_US'; + + my $strp = DateTime::Format::Strptime->new( + pattern => $format, + locale => $locale, + ); + + return $strp->parse_datetime($input); +} + +# figure out if we're reading from a file or stdin +# return a file handle representation of our data +sub get_input { + my ($args) = @_; + my $logpath = $args->{logpath}; + my $stdin = $args->{stdin}; + my $fh; + + $stdin ? + $fh = *STDIN : + open $fh, '<', $logpath or die $!; + + return $fh; +} + +# figure if the target address/cidr contains the entry's remote address +sub cidr_match { + my ($args) = @_; + my $entry = $args->{entry}; + my $target = $args->{target}; + my $client_ip = $entry->{transaction}->{remote_address}; + + return $target ? $target->contains(NetAddr::IP->new($client_ip)) : 1; +} + +# given a file handle, return an arrayref representing pertinent rule entries +sub grok_input { + my ($args) = @_; + my $fh = $args->{fh}; + my $filters = $args->{filters}; + my $delim = $args->{delim}; + my $source_ip = $args->{source_ip}; + my $before = $args->{before}; + my $after = $args->{after}; + my $partial = $args->{partial}; + my $verbose = $args->{verbose}; + + my @ref; + + while (my $line = <$fh>) { + my $entry; + + try { + $entry = decode_json($line); + } catch { + warn "Could not decode as JSON:\n$line\n" if $verbose; + }; + + next if !$entry; + + skim_entry({ + entry => $entry, + partial => $partial, + }); + + next if !filter({ + filters => $filters, + data => $entry, + delim => $delim, + }); + + next if !cidr_match({ + entry => $entry, + target => $source_ip, + }); + + next if !within_timeframe({ + entry => $entry, + before => $before, + after => $after, + }); + + push @ref, $entry; + } + + return \@ref; +} + +# get rid of partial chains and other noise +sub skim_entry { + my ($args) = @_; + my $entry = $args->{entry}; + my $partial = $args->{partial}; + my $ctr = 0; + + for my $matched_rule (@{$entry->{matched_rules}}) { + splice @{$entry->{matched_rules}}, $ctr++, 1 + if $matched_rule->{chain} && !$matched_rule->{full_chain_match} && !$partial; + } +} + +# print entries after filtering and skimming +sub print_matches { + my ($args) = @_; + my $ref = $args->{ref}; + my $json = $args->{json}; + my $verbose = $args->{verbose}; + + for my $entry (@{$ref}) { + if ($json) { + print encode_json($entry) . "\n"; + } else { + printf "\n%s\n", '=' x 80; + + # request + my $transaction = $entry->{transaction}; + my $request = $entry->{request}; + + printf "%s\nTransaction ID: %s\nIP: %s\n\n%s\n", + parse_modsec_timestamp($transaction->{time}), + $transaction->{transaction_id}, + $transaction->{remote_address}, + $request->{request_line}; + + for my $header (sort keys %{$request->{headers}}) { + printf "%s: %s\n", $header, $request->{headers}->{$header}; + } + + # matched rules + for my $chain (@{$entry->{matched_rules}}) { + print "\n"; + my @extra_data; + my $ctr = 0; + + for my $rule (@{$chain->{rules}}) { + printf $rule->{is_matched} ? "%s%s\n" : "%s#%s\n", ' ' x $ctr++, $rule->{unparsed}; + push @extra_data, $rule->{actionset}->{msg} if $rule->{actionset}->{msg}; + push @extra_data, $rule->{actionset}->{logdata} if $rule->{actionset}->{logdata}; + } + + printf "\n-- %s\n", join "\n-- ", @extra_data if @extra_data && $verbose; + } + + # audit message + printf "\n-- %s\n\n", $entry->{audit_data}->{action}->{message} if $verbose; + + printf "%s\n", '=' x 80; + } + } +} + +# filter out rule entries based on given filter definitions +sub filter { + my ($args) = @_; + my $filters = $args->{filters}; + my $data = $args->{data}; + my $delim = $args->{delim}; + + my $valid_match = 1; + + for my $field (keys %{$filters}) { + my $args = { + field => $field, + match => $filters->{$field}, + delim => $delim, + hash => $data, + }; + + if (!match($args)) { + $valid_match = 0; + last; + } + } + return $valid_match; +} + +# match a hash element (may be an array of elements) against a given pattern +sub match { + my ($args) = @_; + my $delim = $args->{delim}; + my $hash = $args->{hash}; + my $match = $args->{match}; + my $field = $args->{field}; + + my @matches = traverse($args); + + return any { $_ =~ m/^$match$/ } @matches; +} + +# walk a JSON structure in search of a given key +# borrowed and butchered from view_signatures.pl +sub traverse { + my ($args) = @_; + my $delim = $args->{delim}; + my $hash = $args->{hash}; + my $match = $args->{match}; + my $field = $args->{field}; + my @traverse = split /\Q$delim\E/, $field; + + my @values; + + while (my $level = shift @traverse) { + if ($level eq '%') { + # match() is called in a list context + # so if we have a bad filter expression + # we need to bail in a sensible way + return () if ref $hash ne 'ARRAY'; + + for my $subhash (@{$hash}) { + my @match = traverse({ + hash => $subhash, + delim => $delim, + match => $match, + field => join $delim, @traverse, + }); + push(@values, @match) if @match; + } + } elsif (ref $hash eq 'HASH' && defined $hash->{$level}) { + $hash = $hash->{$level}; + } else { + $hash = undef; + last; + } + } + + push @values, $hash if defined $hash; + return ref $hash eq 'ARRAY' ? @{$hash} : @values; +} + +# merge any custom-defined filters with shortcut options +sub merge_filters { + my ($args) = @_; + my $filters = $args->{filters}; + my $delim = $args->{delim}; + + my $lookup = { + host => [qw(request headers Host)], + transaction_id => [qw(transaction transaction_id)], + rule_id => [qw(matched_rules % rules % actionset id)] + }; + + for my $field (keys %{$lookup}) { + if (defined $args->{$field}) { + my $key = build_filter_key({ + elements => $lookup->{$field}, + delim => $delim, + }); + + $filters->{$key} = $args->{$field}; + } + } +} + +# stub sub to build a filter key +sub build_filter_key { + my ($args) = @_; + my $elements = $args->{elements}; + my $delim = $args->{delim}; + + return join $delim, @{$elements}; +} + +sub main { + my ( + $host, $transaction_id, # shortcuts + $source_ip, $rule_id, # shortcuts + %filters, $delim, # used by filters/match/traverse to grok the input + $before, $after, # timeframe + $logpath, $stdin, # input + $partial_chains, $json, # output + $verbose, # output + $fh, $parsed_ref, # data structures + ); + + GetOptions( + 'h|help' => sub { usage(); }, + 'H|host=s' => \$host, + 't|transaction-id=s' => \$transaction_id, + 's|source-ip=s' => \$source_ip, + 'r|rule-id=i' => \$rule_id, + 'f|filter=s' => \%filters, + 'd|delim=s' => \$delim, + 'b|before=s' => \$before, + 'a|after=s' => \$after, + 'l|logpath=s' => \$logpath, + 'S|stdin' => \$stdin, + 'p|partial-chains' => \$partial_chains, + 'j|json' => \$json, + 'v|verbose' => \$verbose, + ) or usage(); + + # sanity checks + die "Cannot parse both a file and stdin\n" + if defined $logpath && defined $stdin; + + if (defined $source_ip) { + $source_ip = NetAddr::IP->new($source_ip); + die "Invalid IP/CIDR provided for source IP argument\n" + unless $source_ip; + } + + # build_datetime will bail out if an invalid format was given + $before = build_datetime($before); + $after = build_datetime($after); + + # figure where we're reading from + $logpath ||= '/var/log/modsec_audit.log'; + $fh = get_input({ + logpath => $logpath, + stdin => $stdin, + }); + + die "Could not get a handle on your data\n" + unless $fh; + + # build the filters by merging shortcut options with custom filter directives + $delim ||= '.'; + merge_filters({ + filters => \%filters, + host => $host, + transaction_id => $transaction_id, + source_ip => $source_ip, + rule_id => $rule_id, + delim => $delim, + }); + + # walk through our input, getting an arrayref of entries valid based on filters and timeframe + $parsed_ref = grok_input({ + fh => $fh, + filters => \%filters, + delim => $delim, + source_ip => $source_ip, + before => $before, + after => $after, + partial => $partial_chains, + verbose => $verbose, + }); + + close $fh || warn $!; + + # show me the money! + print_matches({ + ref => $parsed_ref, + json => $json, + verbose => $verbose, + }); +} + +main(); From 374871e10e38ec54f0860ba6bd464ccb4e3b239d Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Mon, 7 Dec 2015 22:15:28 -0800 Subject: [PATCH 045/477] Updates to parse_modsec.pl --- tools/parse_modsec.pl | 69 ++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/tools/parse_modsec.pl b/tools/parse_modsec.pl index 3c5db51ff6..8c3b043e95 100755 --- a/tools/parse_modsec.pl +++ b/tools/parse_modsec.pl @@ -22,7 +22,7 @@ =head1 SYNOPSIS =head1 USAGE -Usage: $0 [h] [Gtsrfdbalspj] +Usage: $0 [h] [Htsrfdbalspjv] -H|--host Search rules based on the Host request header -t|--transaction-id Search rules based on the unique transaction ID -s|--source-ip Search rules based on the client IP address (can be presented as an address or CIDR block) @@ -35,7 +35,7 @@ =head1 USAGE -S|--stdin Read rules from stdin instead of an on-disk file -p|--partial-chains Do not prune partial chain matches -j|--json Print rule entries as a JSON blob, rather than nice formatting - -v|--verbose Be verbose about various details such as JSON parse failures + -v|--verbose Be verbose about various details such as JSON parse failures and log data =head2 FILTERS @@ -129,6 +129,10 @@ =head2 USAGE EXAMPLES parse_modsec.pl +Print all log entries and show more detailed information, such as response data and matched rule details + + parse_modsec.pl -v + Print entries matching a specific source IP: parse_modsec.pl -s 1.2.3.4 @@ -161,7 +165,7 @@ =head2 USAGE EXAMPLES sub usage { print <<"_EOF"; -Usage: $0 [h] [Gtsrfdbalspj] +Usage: $0 [h] [Htsrfdbalspjv] -h|--help Print this help -H|--host Search rules based on the Host request header -t|--transaction-id Search rules based on the unique transaction ID @@ -175,7 +179,7 @@ sub usage { -S|--stdin Read rules from stdin instead of an on-disk file -p|--partial-chains Do not prune partial chain matches -j|--json Print rule entries as a JSON blob, rather than nice formatting - -v|--verbose Be verbose about various details such as JSON parse failures + -v|--verbose Be verbose about various details such as JSON parse failures and log data For detailed explanations of various options and example usages, see 'perldoc $0' @@ -339,22 +343,44 @@ sub print_matches { } else { printf "\n%s\n", '=' x 80; - # request - my $transaction = $entry->{transaction}; - my $request = $entry->{request}; + my $transaction = $entry->{transaction}; + my $request = $entry->{request}; + my $response = $entry->{response}; + my $audit_data = $entry->{audit_data}; + my $matched_rules = $entry->{matched_rules}; + + if ($transaction) { + printf "%s\nTransaction ID: %s\nIP: %s\n\n", + parse_modsec_timestamp($transaction->{time}), + $transaction->{transaction_id}, + $transaction->{remote_address}; + } + + printf "%s\n", $request->{request_line} + if $request->{request_line}; + + if ($request->{headers}) { + for my $header (sort keys %{$request->{headers}}) { + printf "%s: %s\n", $header, $request->{headers}->{$header}; + } + } + + if ($verbose) { + print join ("\n", @{$request->{body}}) . "\n" + if $request->{body}; - printf "%s\nTransaction ID: %s\nIP: %s\n\n%s\n", - parse_modsec_timestamp($transaction->{time}), - $transaction->{transaction_id}, - $transaction->{remote_address}, - $request->{request_line}; + printf "\n%s %s\n", $response->{protocol}, $response->{status} + if $response->{protocol} && $response->{status}; + + for my $header (sort keys %{$response->{headers}}) { + printf "%s: %s\n", $header, $response->{headers}->{$header}; + } - for my $header (sort keys %{$request->{headers}}) { - printf "%s: %s\n", $header, $request->{headers}->{$header}; + printf "\n%s\n", $response->{body} + if $response->{body}; } - # matched rules - for my $chain (@{$entry->{matched_rules}}) { + for my $chain (@{$matched_rules}) { print "\n"; my @extra_data; my $ctr = 0; @@ -365,11 +391,12 @@ sub print_matches { push @extra_data, $rule->{actionset}->{logdata} if $rule->{actionset}->{logdata}; } - printf "\n-- %s\n", join "\n-- ", @extra_data if @extra_data && $verbose; + printf "\n-- %s\n", join "\n-- ", @extra_data + if @extra_data && $verbose; } - # audit message - printf "\n-- %s\n\n", $entry->{audit_data}->{action}->{message} if $verbose; + printf "\n-- %s\n\n", $audit_data->{action}->{message} + if $audit_data->{action}->{message} && $verbose; printf "%s\n", '=' x 80; } @@ -531,7 +558,7 @@ sub main { $after = build_datetime($after); # figure where we're reading from - $logpath ||= '/var/log/modsec_audit.log'; + $logpath ||= '/var/log/mod_sec/modsec_audit.log'; $fh = get_input({ logpath => $logpath, stdin => $stdin, @@ -551,7 +578,7 @@ sub main { delim => $delim, }); - # walk through our input, getting an arrayref of entries valid based on filters and timeframe + # walk through our input, getting an arrayref of valid entries based on filters and timeframe $parsed_ref = grok_input({ fh => $fh, filters => \%filters, From c131dcc93c0ad905b6759a0c48a802ca3af47ea6 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 29 Jan 2016 13:27:30 -0300 Subject: [PATCH 046/477] Adds information about the pull request #914 on the CHANGES file --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index fc30e44b3f..b0aaf34af4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - X.Y.Z (To be released) ------------------------------------ + * Added support to generate audit logs in JSON format. + [Issue #914, #897, #656 - Robert Paprocki] * Creating AuditLog serial file (or paralel index) respecting the permission configured with SecAuditLogFileMode, before, it was used only to save the transactions while in paralel mode. From eef2c03e644059ef26c007cd9d929df3f13d4fb7 Mon Sep 17 00:00:00 2001 From: Chaim Sanders <csanders@sparsa.org> Date: Mon, 1 Feb 2016 11:16:13 -0500 Subject: [PATCH 047/477] Fixed broken link in readme #1059 --- README.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.TXT b/README.TXT index 9442e83a2f..03767e345f 100644 --- a/README.TXT +++ b/README.TXT @@ -100,7 +100,7 @@ vulnerability classes for applications such as: * Joomla * For a complete listing of application coverage, please refer to this link (which is updated daily). -https://modsecurity.org/projects/commercial/rules/application_coverage.html +https://modsecurity.org/application_coverage.html 3. Complements and integrates with the OWASP Core Rule Set 4. IP Reputation capabilities which provide protection against malicious From a157ac2946b9d66873e8ddacdb76f6dfb3f140ac Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 3 Feb 2016 08:08:21 -0300 Subject: [PATCH 048/477] Fix compilation issue on "pedantic" compilers --- apache2/msc_logging.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index ee7415da8d..66394adab2 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -571,12 +571,13 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) yajl_kv_string(g, "version", log_escape(msr->mp, rule->actionset->version)); } if (rule->actionset->logdata) { + char *logdata = NULL; msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); var->value = (char *)rule->actionset->logdata; var->value_len = strlen(rule->actionset->logdata); expand_macros(msr, var, NULL, msr->mp); - char *logdata = apr_pstrdup(msr->mp, log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); + logdata = apr_pstrdup(msr->mp, log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); // if it is > 512 bytes, then truncate at 512 with ellipsis. if (strlen(logdata) > 515) { @@ -611,6 +612,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) for (k = 0; k < tarr->nelts; k++) { msre_action *action = (msre_action *)telts[k].val; if (strcmp(telts[k].key, "tag") == 0) { + msc_string *var = NULL; if (been_opened == 0) { yajl_string(g, "tags"); yajl_gen_array_open(g); @@ -618,7 +620,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) } // expand variables in the tag - msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); var->value = (char *)action->param; var->value_len = strlen(action->param); expand_macros(msr, var, NULL, msr->mp); @@ -676,6 +678,9 @@ void sec_audit_logger_json(modsec_rec *msr) { int arg_min, arg_max, sanitize_matched; yajl_gen g; int been_opened = 0; // helper flag for conditionally opening maps + const unsigned char *final_buf; + size_t len; + /* Return silently if we don't have a request line. This * means we will not be logging request timeouts. @@ -1437,8 +1442,6 @@ void sec_audit_logger_json(modsec_rec *msr) { /* finished building JSON */ yajl_gen_map_close(g); // box it up! - const unsigned char *final_buf; - size_t len; yajl_gen_get_buf(g, &final_buf, &len); sec_auditlog_write(msr, final_buf, len); From ad9257c374079b3fc0202178032db2d03bc6b761 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 3 Feb 2016 11:03:00 -0300 Subject: [PATCH 049/477] Version 2.9.1 Increasing version to 2.9.1 and performed small fixes on the CHANGES file --- CHANGES | 24 +++++++++++------------- apache2/msc_release.h | 4 ++-- iis/installer.wxs | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/CHANGES b/CHANGES index b0aaf34af4..263d04abe0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,34 +1,32 @@ -DD mmm YYYY - X.Y.Z (To be released) ------------------------------------- +03 Feb 2016 - 2.9.1-RC1 +----------------------- * Added support to generate audit logs in JSON format. [Issue #914, #897, #656 - Robert Paprocki] - * Creating AuditLog serial file (or paralel index) respecting the - permission configured with SecAuditLogFileMode, before, it was used - only to save the transactions while in paralel mode. + * Creating AuditLog serial file (or parallel index) respecting the + permission configured with SecAuditLogFileMode. Previously, it was + used only to save the transactions while in parallel mode. [Issue #852 - @littlecho and ModSecurity team] - * Checking for hashing injection response to report in case of failure. + * Checking for hashing injection response, to report in case of failure. [Issue #1041 - ModSecurity team] * Stop buffering when the request is larger than SecRequestBodyLimit in ProcessPartial mode [Issue #709, #705, #728 - Justin Gerace and ModSecurity team] - * Extanded Lua support to include version 5.3 + * Extended Lua support to include version 5.3 [Issue #837, #762, #814 - Athmane Madjoudj and ModSecurity team] - * mlogc: Allow user to choose between TLS versions (TLSProtocol option + * mlogc: Allows user to choose between TLS versions (TLSProtocol option introduced). [Issue #881 - Ishwor Gurung] - * Allow mod_proxy's "nocanon" behavior to be specified in proxy actions - and Perform the intercept_action as well as the disruptive actions. + * Allows mod_proxy's "nocanon" behavior to be specified in proxy actions [Issue #1031, #961, #763 - Mario D. Santana and ModSecurity team] - * Refactoring conditional directives for if wrappers, alternative if - statements and incomplete if conditions. + * Refactoring conditional #if/#defs directives. [Issue #996 - Wesley M and ModSecurity team] * mlogc-batch-load.pl.in: fix searching SecAuditLogStorageDir files with Apache 2.4 [Issue #775 - Elia Pinto] * Understands IIS 10 as compatible on Windows installer. [Issue #931 - Anton Serbulov, Pavel Vasilevich and ModSecurity team] - * Fix apache logging limitation by using correct apache call. + * Fix apache logging limitation by using correct Apache call. [Issue #840 - Christian Folini] * Fix apr_crypto.h check on 32-bit Linux platform [Issue #882, #883 - Kurt Newman] diff --git a/apache2/msc_release.h b/apache2/msc_release.h index a34578b663..c85b3dbcfd 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,9 +38,9 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "0" +#define MODSEC_VERSION_MAINT "1" #define MODSEC_VERSION_TYPE "" -#define MODSEC_VERSION_RELEASE "" +#define MODSEC_VERSION_RELEASE "-RC1" #define MODSEC_VERSION_SUFFIX MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE diff --git a/iis/installer.wxs b/iis/installer.wxs index 49d2e5e42a..b0e2644583 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.0" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.1.1" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> From 88bffb1e3eda8cc5e24965c9e06dec15f91be11a Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Wed, 9 Mar 2016 10:07:44 -0300 Subject: [PATCH 050/477] Version 2.9.1 (final) Increasing version to 2.9.1 (final) --- CHANGES | 5 +++++ apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 263d04abe0..6ca4b4feb6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +09 Mar 2016 - 2.9.1 +------------------- + + * No changes. + 03 Feb 2016 - 2.9.1-RC1 ----------------------- diff --git a/apache2/msc_release.h b/apache2/msc_release.h index c85b3dbcfd..f2fe898d5d 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -40,7 +40,7 @@ #define MODSEC_VERSION_MINOR "9" #define MODSEC_VERSION_MAINT "1" #define MODSEC_VERSION_TYPE "" -#define MODSEC_VERSION_RELEASE "-RC1" +#define MODSEC_VERSION_RELEASE "" #define MODSEC_VERSION_SUFFIX MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE diff --git a/iis/installer.wxs b/iis/installer.wxs index b0e2644583..015c9351f8 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.1.1" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.1" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> From f9c253952c564ffefd6c10b8327ef836832facea Mon Sep 17 00:00:00 2001 From: root <root@ip-10-124-52-70.us-east-1.aws.cloud.in.here.com> Date: Fri, 29 Jan 2016 08:43:28 +0000 Subject: [PATCH 051/477] This is fix for reborn of https://github.com/SpiderLabs/ModSecurity/issues/334 This bug has been reborn, because Apache (at least in RedHat/CentOS) since version 2.2.15-47 returns in same case APR_INCOMPLETE (not APR_EOF). Based on same patch I have added handler for APR_INCOMPLETE. --- apache2/apache2_io.c | 3 +++ apache2/mod_security2.c | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 0d59613e4d..c14dd41318 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -208,6 +208,9 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { * too large and APR_EGENERAL when the client disconnects. */ switch(rc) { + case APR_INCOMPLETE : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -7; case APR_EOF : *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); return -6; diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 5404fd8744..14e9f44234 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1030,6 +1030,13 @@ static int hook_request_late(request_rec *r) { r->connection->keepalive = AP_CONN_CLOSE; return HTTP_BAD_REQUEST; break; + case -7 : /* Partial recieved */ + if (my_error_msg != NULL) { + msr_log(msr, 4, "%s", my_error_msg); + } + r->connection->keepalive = AP_CONN_CLOSE; + return HTTP_BAD_REQUEST; + break; default : /* allow through */ break; From 808ea48263f2123ea7b8d56678b16ea42855cfb3 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Wed, 16 Mar 2016 10:37:01 -0300 Subject: [PATCH 052/477] Adds information about the pull request #1060 on the CHANGES file --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 6ca4b4feb6..f4cb22fe97 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +DD MMM YYYY - 2.9.2 - To be released +------------------------------------ + + * Treat APR_INCOMPLETE as APR_EOF while receiving the request body. + [Issue #1060, #334 - Alexey Sintsov] + 09 Mar 2016 - 2.9.1 ------------------- From c729b6d0ab5c377b983fe58f10940ba2a4069b0a Mon Sep 17 00:00:00 2001 From: Thomas Deutschmann <whissi@whissi.de> Date: Sat, 11 Jun 2016 16:18:17 +0200 Subject: [PATCH 053/477] configure: Fix detection whether libcurl is linked against gnutls The find_curl macro is also checking whether libcurl is linked against gnutls. However the check depends on "CURL_LIBS" which wasn't defined by the macro. This commit will define "CURL_LIBS" so that the check works as expected. --- build/find_curl.m4 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/find_curl.m4 b/build/find_curl.m4 index 6b23ad696e..3310e40494 100644 --- a/build/find_curl.m4 +++ b/build/find_curl.m4 @@ -2,6 +2,7 @@ dnl Check for CURL Libraries dnl CHECK_CURL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) dnl Sets: dnl CURL_CFLAGS +dnl CURL_LDADD dnl CURL_LIBS CURL_CONFIG="" @@ -57,7 +58,8 @@ if test -n "${curl_path}"; then if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl VERSION: $CURL_VERSION); fi CURL_CFLAGS="`${CURL_CONFIG} --cflags`" if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl CFLAGS: $CURL_CFLAGS); fi - CURL_LDADD="`${CURL_CONFIG} --libs`" + CURL_LIBS="`${CURL_CONFIG} --libs`" + CURL_LDADD="${CURL_LIBS}" if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl LDADD: $CURL_LIBS); fi dnl # Check version is ok From 692712cc953bb567c4b7facb5a367b3cd0e3495a Mon Sep 17 00:00:00 2001 From: Thomas Deutschmann <whissi@whissi.de> Date: Sat, 11 Jun 2016 16:48:58 +0200 Subject: [PATCH 054/477] configure: Move verbose_output declaration up to the beginning Macros like "find_curl" are using "verbose_output" variable but because some of them are called before we define the variable we are seeing errors like ./configure: line 13855: test: : integer expression expected This commit will fix the problem by moving the "verbose_output" declaration up to the beginning so that the variable is available for every macro. --- configure.ac | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/configure.ac b/configure.ac index 7517885893..0f32b01bf2 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,22 @@ AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) ### Configure Options +# Verbose output +AC_ARG_ENABLE(verbose-output, + AS_HELP_STRING([--enable-verbose-output], + [Enable more verbose configure output.]), +[ + if test "$enableval" != "no"; then + verbose_output=1 + else + verbose_output=0 + fi +], +[ + verbose_output=0 +]) + + #OS type AC_CANONICAL_HOST @@ -410,20 +426,6 @@ AC_ARG_ENABLE(errors, report_errors=1 ]) -# Verbose output -AC_ARG_ENABLE(verbose-output, - AS_HELP_STRING([--enable-verbose-output], - [Enable more verbose configure output.]), -[ - if test "$enableval" != "no"; then - verbose_output=1 - else - verbose_output=0 - fi -], -[ - verbose_output=0 -]) # Strict Compile AC_ARG_ENABLE(strict-compile, From a2bb610d7c6909cf8c8de259e206c00342eb6c7e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Tue, 14 Jun 2016 15:19:00 -0300 Subject: [PATCH 055/477] Adds information about #1158 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index f4cb22fe97..c05d36ff32 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * configure: Fix detection whether libcurl is linked against gnutls and, + move verbose_output declaration up to the beginning. + [Issue #1158 - Thomas Deutschmann (@Whissi)] * Treat APR_INCOMPLETE as APR_EOF while receiving the request body. [Issue #1060, #334 - Alexey Sintsov] From f2ef2017f148fc78cb50c621b2bde9b1aff7a64d Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 29 Jun 2016 11:38:22 -0700 Subject: [PATCH 056/477] Fix file upload JSON audit log entry Each uploaded file is a separate yajl array, but we forgot to open the a map for the proper k/v pairs. This fixes issue #1173. --- apache2/msc_logging.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 66394adab2..2aff589b3f 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1364,10 +1364,12 @@ void sec_audit_logger_json(modsec_rec *msr) { for(cfiles = 0; cfiles < msr->mpd->parts->nelts; cfiles++) { if (parts[cfiles]->type == MULTIPART_FILE) { if(parts[cfiles]->filename != NULL) { + yajl_gen_map_open(g); yajl_kv_int(g, "file_size", parts[cfiles]->tmp_file_size); yajl_kv_string(g, "file_name", log_escape(msr->mp, parts[cfiles]->filename)); yajl_kv_string(g, "content_type", parts[cfiles]->content_type ? parts[cfiles]->content_type : "<Unknown Content-Type>"); total_size += parts[cfiles]->tmp_file_size; + yajl_gen_map_close(g); } } } From 2538d90e5f8901fb9348311308bc7910a112c523 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Mon, 11 Jul 2016 12:17:31 -0300 Subject: [PATCH 057/477] Adds information about pull request #1181 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c05d36ff32..ffe9cd4772 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix file upload JSON audit log entry + [Issue #1181 and #1173 - Robert Paprocki and Christian Folini] * configure: Fix detection whether libcurl is linked against gnutls and, move verbose_output declaration up to the beginning. [Issue #1158 - Thomas Deutschmann (@Whissi)] From 947cef7c8c4cbb57462d740bcf5c980d8d4460a6 Mon Sep 17 00:00:00 2001 From: Chaim sanders <csanders@sparsa.org> Date: Wed, 22 Jun 2016 19:23:13 -0400 Subject: [PATCH 058/477] Adapted patch from 977 to fix status failing to report in Nginx auditlogs --- apache2/msc_logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 2aff589b3f..608f31c09b 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1897,7 +1897,7 @@ void sec_audit_logger_native(modsec_rec *msr) { /* There are no response headers (or the status line) in HTTP 0.9 */ if (msr->response_headers_sent) { - if (msr->status_line != NULL) { + if (msr->status_line != NULL && msr->status_line[0] != '\0') { text = apr_psprintf(msr->mp, "%s %s\n", msr->response_protocol, msr->status_line); } else { From 923c3c67938da4de4f7f147816b6d2d6ffff5e6f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Mon, 11 Jul 2016 13:36:16 -0300 Subject: [PATCH 059/477] Adds information about pull request #1171 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index ffe9cd4772..67fdbfbdf8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix status failing to report in Nginx auditlogs + [Issue #977, #1171 - @charlymps and Chaim Sanders] * Fix file upload JSON audit log entry [Issue #1181 and #1173 - Robert Paprocki and Christian Folini] * configure: Fix detection whether libcurl is linked against gnutls and, From 21a63cb83e39c660015c1aac5f7f283faff6e07a Mon Sep 17 00:00:00 2001 From: Ephraim Vider <ephraim.vider@verint.com> Date: Sun, 28 Aug 2016 17:58:59 +0300 Subject: [PATCH 060/477] json parser handle cleanup --- apache2/msc_json.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 4bec0f14df..0f9a4645e2 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -306,10 +306,14 @@ int json_complete(modsec_rec *msr, char **error_msg) { } /** - * Frees the resources used for XML parsing. + * Frees the resources used for JSON parsing. */ apr_status_t json_cleanup(modsec_rec *msr) { msr_log(msr, 4, "JSON: Cleaning up JSON results"); + if (msr->json->handle != NULL) { + yajl_free(msr->json->handle); + msr->json->handle = NULL; + } return 1; } From 5f4a098f08150669ba15a5249f4d49f41cf1856d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Wed, 21 Sep 2016 00:05:13 -0300 Subject: [PATCH 061/477] Adds information about pull request #1204 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 67fdbfbdf8..52cf5d9f3e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Better handle the json parser cleanup + [Issue #1204 - Ephraim Vider] * Fix status failing to report in Nginx auditlogs [Issue #977, #1171 - @charlymps and Chaim Sanders] * Fix file upload JSON audit log entry From 2b4ece14c67d84220fab56cf37397884707fec36 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 19 Jul 2016 09:08:58 -0700 Subject: [PATCH 062/477] Remove logdata and msg fields from JSON audit log rule elements Writing macro-expanded strings to JSON elements during the post-logging phase can be misleading, because it's possible that variable contents (such as MATCHED_VAR) could have changed after the rule match, altering their expected contents. Writing macro-epanded audit data really only makes sense when the macros are expanded immediately following the rule match. See issue #1174 for more details. --- apache2/msc_logging.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 608f31c09b..0fe74ab7ca 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -559,36 +559,9 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) if (rule->actionset->rev) { yajl_kv_string(g, "rev", log_escape(msr->mp, rule->actionset->rev)); } - if (rule->actionset->msg) { - msc_string *var = (msc_string *)apr_palloc(msr->mp, sizeof(msc_string)); - var->value = (char *)rule->actionset->msg; - var->value_len = strlen(rule->actionset->msg); - expand_macros(msr, var, NULL, msr->mp); - - yajl_kv_string(g, "msg", log_escape_ex(msr->mp, var->value, var->value_len)); - } if (rule->actionset->version) { yajl_kv_string(g, "version", log_escape(msr->mp, rule->actionset->version)); } - if (rule->actionset->logdata) { - char *logdata = NULL; - msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->value = (char *)rule->actionset->logdata; - var->value_len = strlen(rule->actionset->logdata); - expand_macros(msr, var, NULL, msr->mp); - - logdata = apr_pstrdup(msr->mp, log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); - - // if it is > 512 bytes, then truncate at 512 with ellipsis. - if (strlen(logdata) > 515) { - logdata[512] = '.'; - logdata[513] = '.'; - logdata[514] = '.'; - logdata[515] = '\0'; - } - - yajl_kv_string(g, "logdata", logdata); - } if (rule->actionset->severity != NOT_SET) { yajl_kv_int(g, "severity", rule->actionset->severity); } From b1ee051cee813856f1f7cfcb7a747dcab3008864 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Tue, 4 Oct 2016 09:41:16 -0300 Subject: [PATCH 063/477] Adds information about pull request #1190 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 52cf5d9f3e..3dbd737602 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Remove logdata and msg fields from JSON audit log rule. + [Issue #1190 and #1174 - Robert Paprocki] * Better handle the json parser cleanup [Issue #1204 - Ephraim Vider] * Fix status failing to report in Nginx auditlogs From b83c1109adb709b7e93089805aa7e5647c39c0ee Mon Sep 17 00:00:00 2001 From: culyerr <robert.culyer@actusmobile.com> Date: Tue, 27 Sep 2016 17:09:18 +0100 Subject: [PATCH 064/477] Fixed IPv4+Port address parsing --- iis/mymodule.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 464968cba9..607fdf0a6d 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -88,6 +88,10 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { + const char *format = "%15[0-9.]:%5[0-9]"; + char ip[16] = { 0 }; // ip4 addresses have max len 15 + char port[6] = { 0 }; // port numbers are 16bit, ie 5 digits max + DWORD len = 50; char *buf = (char *)apr_palloc(pool, len); @@ -98,6 +102,14 @@ char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len); + // test for IPV4 with port on the end + if (sscanf(buf, format, ip, port) == 2) { + // IPV4 but with port - remove the port + char* input = ":"; + char* ipv4 = strtok(buf, input); + return ipv4; + } + return buf; } From 137331748c60751a27674692630989b5eaafae94 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Tue, 4 Oct 2016 13:26:43 -0300 Subject: [PATCH 065/477] Adds information about pull request #1220 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 3dbd737602..f906921edd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Remove port from IPV4 address when running under IIS. + [Issue #1220, #1109 and #734 - Robert Culyer] * Remove logdata and msg fields from JSON audit log rule. [Issue #1190 and #1174 - Robert Paprocki] * Better handle the json parser cleanup From e7f029b55aa11a4ac4536adf6003dc127bee4582 Mon Sep 17 00:00:00 2001 From: arminabf <a.abfalterer@gmail.com> Date: Mon, 26 Sep 2016 12:03:50 +0200 Subject: [PATCH 066/477] fix error message both info->format and fmt (for versions prio 2.4) contain the error message format but not the actual formatted error message --- apache2/mod_security2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 14e9f44234..ffb450b4c3 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1144,13 +1144,13 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s em->line = info->line; em->level = info->level; em->status = info->status; - if (info->format != NULL) em->message = apr_pstrdup(msr->mp, info->format); + em->message = apr_pstrdup(msr->mp, errstr); #else if (file != NULL) em->file = apr_pstrdup(msr->mp, file); em->line = line; em->level = level; em->status = status; - if (fmt != NULL) em->message = apr_pstrdup(msr->mp, fmt); + em->message = apr_pstrdup(msr->mp, errstr); #endif /* Remove \n from the end of the message */ if (em->message != NULL) { From fb3bbf37e806de10641f3de37b25e410be00067a Mon Sep 17 00:00:00 2001 From: arminabf <a.abfalterer@gmail.com> Date: Mon, 26 Sep 2016 13:58:31 +0200 Subject: [PATCH 067/477] revert error message assignment for older versions as errstr is only available since version > 2.2 --- apache2/mod_security2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index ffb450b4c3..93c2fbe492 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1150,7 +1150,7 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s em->line = line; em->level = level; em->status = status; - em->message = apr_pstrdup(msr->mp, errstr); + if (fmt != NULL) em->message = apr_pstrdup(msr->mp, fmt); #endif /* Remove \n from the end of the message */ if (em->message != NULL) { From 8559dd3b8bfab22a06d1372a2a20fcaa207c96be Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Thu, 6 Oct 2016 13:30:25 -0300 Subject: [PATCH 068/477] Adds information about pull request #1216 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index f906921edd..1ee330af1d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix error message inside audit logs + [Issue #1216 and #1073 - Armin Abfalterer] * Remove port from IPV4 address when running under IIS. [Issue #1220, #1109 and #734 - Robert Culyer] * Remove logdata and msg fields from JSON audit log rule. From 709042a4720697bf0d2085ef7276a6aa190f2142 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 4 Oct 2016 15:45:25 -0700 Subject: [PATCH 069/477] Don't unnecessarily rename request body parts in cleanup When tmp_dir and upload_dir are identical, there's no reason to rename multipart and request body parts, as this is a non-op. Let's save the cycles and syscall. --- apache2/msc_multipart.c | 5 +++++ apache2/msc_reqbody.c | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 88eff9b7a1..9bf327d2bc 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -1327,6 +1327,11 @@ apr_status_t multipart_cleanup(modsec_rec *msr) { } else { /* Move file to the upload dir. */ if (parts[i]->tmp_file_name != NULL) { + if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { + msr_log(msr, 4, "Not moving part to identical location"); + continue; + } + const char *new_filename = NULL; const char *new_basename = NULL; diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 7d150eedff..a8411fa04d 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -884,6 +884,11 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { if (msr->msc_reqbody_filename != NULL) { if (keep_body) { + if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { + msr_log(msr, 4, "Not moving file to identical location."); + goto nullify; + } + /* Move request body (which is a file) to the storage area. */ const char *put_filename = NULL; const char *put_basename = NULL; @@ -933,6 +938,8 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { msr->msc_reqbody_filename); } +nullify: + msr->msc_reqbody_filename = NULL; } } From c95d93483b76e1ed1eb5a163d1cc2e72019cb866 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Mon, 10 Oct 2016 12:34:04 -0300 Subject: [PATCH 070/477] Adds information about pull request #1223 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 1ee330af1d..4cb1384a4d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * JSON Log: Don't unnecessarily rename request body parts in cleanup + [Issue #1223 - Robert Paprocki] * Fix error message inside audit logs [Issue #1216 and #1073 - Armin Abfalterer] * Remove port from IPV4 address when running under IIS. From a34f9eb785dc1b0069b38f785af00c142ac6d793 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 19 Oct 2016 14:51:59 -0700 Subject: [PATCH 071/477] Append a newline to concurrent JSON audit logs --- apache2/msc_logging.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 0fe74ab7ca..e35da5520f 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1423,11 +1423,12 @@ void sec_audit_logger_json(modsec_rec *msr) { yajl_gen_clear(g); yajl_gen_free(g); + sec_auditlog_write(msr, "\n", 1); + /* Return here if we were writing to a serial log * as it does not need an index file. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - sec_auditlog_write(msr, "\n", 1); /* Unlock the mutex we used to serialise access to the audit log file. */ rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); From bb577950bf983811ff1892e87d815a1909c0b96b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Thu, 20 Oct 2016 09:44:25 -0300 Subject: [PATCH 072/477] Adds information about pull request #1233 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 4cb1384a4d..403a30600f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * JSON Log: Append a newline to concurrent JSON audit logs + [Issue #1233 - Robert Paprocki] * JSON Log: Don't unnecessarily rename request body parts in cleanup [Issue #1223 - Robert Paprocki] * Fix error message inside audit logs From 7ff0e7e7b25530d524dd8beb66826e60ab4403c3 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 17 May 2016 16:50:16 +0200 Subject: [PATCH 073/477] Added ALLOW_ID_NOT_UNIQUE compile flag to allow duplicate rule ids and no id --- apache2/apache2_config.c | 4 +++- configure.ac | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 3ab618a9e2..ce97950f54 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -799,7 +799,8 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, return my_error_msg; } - /* Rules must have uniq ID */ +#ifndef ALLOW_ID_NOT_UNIQUE + /* Rules must have uniq ID */ type_rule = (dcfg->tmp_chain_starter == NULL); #if defined(WITH_LUA) type_rule = (type != RULE_TYPE_LUA && type_rule); @@ -831,6 +832,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, // return "ModSecurity: Found another rule with the same id"; } } +#endif /* Create default actionset if one does not already exist. */ if (dcfg->tmp_default_actionset == NULL) { diff --git a/configure.ac b/configure.ac index 0f32b01bf2..fd576e6e2f 100644 --- a/configure.ac +++ b/configure.ac @@ -411,6 +411,22 @@ AC_ARG_ENABLE(request-early, request_early='-DREQUEST_EARLY' ]) +# Enable duplicate rules id +AC_ARG_ENABLE(rule-id-validation, + AS_HELP_STRING([--enable-rule-id-validation], + [Forbid duplicate rule ids and missing ones. This is the default]), +[ + if test "$enableval" != "no"; then + unique_id= + else + unique_id="-DALLOW_ID_NOT_UNIQUE" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $unique_id" + fi +], +[ + unique_id='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], From 3fce12a96cddee4d702d2082f53b58ee84115fac Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Mon, 21 Nov 2016 10:58:43 -0300 Subject: [PATCH 074/477] Fix on the patch proposal #1150 That is a fix on the top of #1150 without this fix the patch won't work as expected. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fd576e6e2f..4eefad818c 100644 --- a/configure.ac +++ b/configure.ac @@ -677,7 +677,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 3e6f6e63bcaf086af298dfc249aced32709d41ac Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Mon, 21 Nov 2016 11:02:13 -0300 Subject: [PATCH 075/477] Adds information about pull request #1150 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 403a30600f..34f23b638f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-rule-id-validation: Option to disable rule id validation + [Issue #1150 - Marc Stern and ModSecurity team] * JSON Log: Append a newline to concurrent JSON audit logs [Issue #1233 - Robert Paprocki] * JSON Log: Don't unnecessarily rename request body parts in cleanup From 792a351de62339f6943d2e7a43d9f59d3e77d9ae Mon Sep 17 00:00:00 2001 From: Master Yoda <michael.kjeldsen@vaimo.com> Date: Fri, 11 Nov 2016 13:09:44 +0100 Subject: [PATCH 076/477] As of 17 May 2016, the country name "Czechia" replaces this MemberState's former short name of Czech Republic (code 203) --- apache2/msc_geo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index 49cf292c7d..134f40fa21 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -82,7 +82,7 @@ static const char *const geo_country_name[GEO_COUNTRY_LAST + 1] = { "Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia", "Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the", "Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica", - "Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic", + "Cuba","Cape Verde","Christmas Island","Cyprus","Czechia","Germany","Djibouti","Denmark","Dominica","Dominican Republic", "Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji", "Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana", "Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala", From b6053df941f872b5c6ee8754837a8d5b21024769 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Thu, 1 Dec 2016 15:14:39 -0300 Subject: [PATCH 077/477] Adds information about pull request #1258 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 34f23b638f..e39d5eefe9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Using Czechia instea of Czech Republic + [Issue #1258 - Michael Kjeldsen] * {dis|en}able-rule-id-validation: Option to disable rule id validation [Issue #1150 - Marc Stern and ModSecurity team] * JSON Log: Append a newline to concurrent JSON audit logs From 1bb2ffcd6b01bd492a0db48c55295421075d355f Mon Sep 17 00:00:00 2001 From: Andrei Belov <defanator@gmail.com> Date: Mon, 3 Apr 2017 12:52:01 +0300 Subject: [PATCH 078/477] Fix building with nginx >= 1.11.11 Closes SpiderLabs/ModSecurity#1359 See also: http://hg.nginx.org/nginx/rev/e662cbf1b932 --- nginx/modsecurity/ngx_http_modsecurity.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c index 7c1395315b..367b2b8de3 100644 --- a/nginx/modsecurity/ngx_http_modsecurity.c +++ b/nginx/modsecurity/ngx_http_modsecurity.c @@ -528,9 +528,15 @@ ngx_http_modsecurity_save_request_body(ngx_http_request_t *r) hc = r->http_connection; +#if defined(nginx_version) && nginx_version >= 1011011 + if (hc->free && size == cscf->large_client_header_buffers.size) { + + buf = hc->free->buf; +#else if (hc->nfree && size == cscf->large_client_header_buffers.size) { buf = hc->free[--hc->nfree]; +#endif ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ModSecurity: use http free large header buffer: %p %uz", From eb798d8c553d9fd48456cbe443462ddf38bbec44 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 3 Apr 2017 16:23:33 -0300 Subject: [PATCH 079/477] Adds information about pull request #1373 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index e39d5eefe9..0e55eceebb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix building with nginx >= 1.11.11 + [Issue #1373, #1359 - Andrei Belov and Thomas Deutschmann] * Using Czechia instea of Czech Republic [Issue #1258 - Michael Kjeldsen] * {dis|en}able-rule-id-validation: Option to disable rule id validation From 5e4e2af7a6f07854fee6ed36ef4a381d4e03960e Mon Sep 17 00:00:00 2001 From: Chaim Sanders <csanders@sparsa.org> Date: Mon, 3 Apr 2017 19:52:14 -0400 Subject: [PATCH 080/477] add support for soap+xml As was talked about by @emphazer in https://github.com/SpiderLabs/owasp-modsecurity-crs/pull/721, RFC 3902 adds support for the application/soap+xml header used by SOAP 1.2. --- modsecurity.conf-recommended | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 42a6f6c889..728afc1afd 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -19,7 +19,7 @@ SecRequestBodyAccess On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type # -SecRule REQUEST_HEADERS:Content-Type "(?:text|application)/xml" \ +SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" # Enable JSON request body parser. From 6cce8a2764587e5d363504f960ff87ad2a32bc2b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 6 Apr 2017 09:37:52 -0300 Subject: [PATCH 081/477] Adds information about pull request #1374 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 0e55eceebb..c36a540cda 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Changes the configuration to recognize soap+xml as XML + [Issue #1374 - @emphazer and Chaim Sanders] * Fix building with nginx >= 1.11.11 [Issue #1373, #1359 - Andrei Belov and Thomas Deutschmann] * Using Czechia instea of Czech Republic From fd49ca71387b0489168012658417f73652c3f4f2 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Wed, 22 Feb 2017 13:54:49 -0800 Subject: [PATCH 082/477] Don't leak an fd on fuzzy hash initialization Since we're re-opening this file with every invocation, let's close our sanity check fd. --- apache2/re_operators.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 4f748d77da..597891f561 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -3828,6 +3828,7 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; + FILE *fp; char *file; int param_len,threshold; @@ -3876,14 +3877,15 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) } file = resolve_relative_path(rule->ruleset->mp, rule->filename, file); - - if (!fopen(file, "r")) + + fp = fopen(file, "r"); + if (!fp) { *error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open file:" \ " %s.", file); return -1; } - + fclose(fp); param_data->file = file; param_data->threshold = threshold; From 96a1f55e16da7c6b9f09b74a2e5d5227d8aa692d Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Thu, 2 Mar 2017 13:52:45 -0800 Subject: [PATCH 083/477] Read fuzzy hash databases on init Instead of reading the fuzzy db on every invocation, read and store the db contents during initialization and store the contents in memory. The only significant behavior change here is that a change in db contents now (obviously) requires a daemon restart, as no API is provided to flush the list of ssdeep chunks. --- apache2/re.h | 6 +++++ apache2/re_operators.c | 53 +++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/apache2/re.h b/apache2/re.h index 836e2af2b8..c0c5433965 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -409,8 +409,14 @@ struct msre_cache_rec { apr_size_t val_len; }; +struct fuzzy_hash_chunk { + const char *data; + struct fuzzy_hash_chunk *next; +}; + struct fuzzy_hash_param_data { const char *file; + struct fuzzy_hash_chunk *head; int threshold; }; diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 597891f561..e54a540700 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1279,7 +1279,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { strncmp(fn, "http://", strlen("http://")) == 0) { *error_msg = apr_psprintf(rule->ruleset->mp, "HTTPS address or " \ - "file path are expected for operator pmFromFile \"%s\"", fn); + "file path are expected for operator pmFromFile \"%s\"", fn); return 0; } else if (strlen(fn) > strlen("https://") && @@ -1316,7 +1316,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { msc_remote_clean_chunk(&chunk); #else *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ - "compiled with Curl support, it cannot load: \"%s\"", fn); + "compiled with Curl support, it cannot load: \"%s\"", fn); return 0; #endif } @@ -3828,9 +3828,11 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; + struct fuzzy_hash_chunk *chunk, *t; FILE *fp; char *file; int param_len,threshold; + char line[1024]; char *data = NULL; char *threshold_str = NULL; @@ -3838,6 +3840,8 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) param_data = apr_palloc(rule->ruleset->mp, sizeof(struct fuzzy_hash_param_data)); + param_data->head = NULL; + data = apr_pstrdup(rule->ruleset->mp, rule->op_param); threshold_str = data; #endif @@ -3885,6 +3889,28 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) " %s.", file); return -1; } + + while (read_line(line, sizeof(line), fp)) + { + chunk = apr_palloc(rule->ruleset->mp, + sizeof(struct fuzzy_hash_chunk)); + + chunk->data = apr_pstrdup(rule->ruleset->mp, line); + chunk->next = NULL; + + if (param_data->head == NULL) { + param_data->head = chunk; + } else { + t = param_data->head; + + while (t->next) { + t = t->next; + } + + t->next = chunk; + } + } + fclose(fp); param_data->file = file; @@ -3911,8 +3937,7 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, #ifdef WITH_SSDEEP char result[FUZZY_MAX_RESULT]; struct fuzzy_hash_param_data *param = rule->op_param_data; - FILE *fp; - char line[1024]; + struct fuzzy_hash_chunk *chunk = param->head; #endif if (error_msg == NULL) @@ -3931,29 +3956,19 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, return -1; } - fp = fopen(param->file, "r"); - if (!fp) - { - *error_msg = apr_psprintf(rule->ruleset->mp, "Not able to open " \ - "fuzzy hash file: %s", param->file); - - return 1; - } - - while (read_line(line, sizeof(line), fp)) + while (chunk != NULL) { - int i = fuzzy_compare(line, result); + int i = fuzzy_compare(chunk->data, result); + msr_log(msr, 9, "%d (%s)", i, chunk->data); if (i >= param->threshold) { *error_msg = apr_psprintf(msr->mp, "Fuzzy hash of %s matched " \ - "with %s (from: %s). Score: %d.", var->name, line, + "with %s (from: %s). Score: %d.", var->name, chunk->data, param->file, i); - fclose(fp); return 1; } + chunk = chunk->next; } - - fclose(fp); #else *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ "compiled with ssdeep support."); From 42c819d1b97ab48c90dd35bf2267bc793dca6539 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 6 Apr 2017 13:21:32 -0300 Subject: [PATCH 084/477] Adds information about pull request #1339 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c36a540cda..833bef0f3d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Reads fuzzy hash databases on init + [Issue #1339 - Robert Paprocki and @Rendername] * Changes the configuration to recognize soap+xml as XML [Issue #1374 - @emphazer and Chaim Sanders] * Fix building with nginx >= 1.11.11 From c1c91e24cde4bd27e1e0ff5dbd6df48956a7731c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 9 Dec 2016 10:27:24 +0100 Subject: [PATCH 085/477] {dis|en}able-filename-logging: Option to disable logging of filename in audit log [Issue #1065 - Marc Stern] --- CHANGES | 3 +++ apache2/apache2_util.c | 2 ++ apache2/re.c | 2 ++ configure.ac | 17 ++++++++++++++++- 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 833bef0f3d..9765bb2a2a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-filename-logging: Option to disable logging of filename + in audit log. + [Issue #1065 - Marc Stern] * Reads fuzzy hash databases on init [Issue #1339 - Robert Paprocki and @Rendername] * Changes the configuration to recognize soap+xml as XML diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index ed5b0ba216..24bba0cee9 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -339,6 +339,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { if (em == NULL) return NULL; +#ifndef LOG_NO_FILENAME if (em->file != NULL) { s_file = apr_psprintf(mp, "[file \"%s\"] ", log_escape(mp, (char *)em->file)); @@ -349,6 +350,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { s_line = apr_psprintf(mp, "[line %d] ", em->line); if (s_line == NULL) return NULL; } +#endif s_level = apr_psprintf(mp, "[level %d] ", em->level); if (s_level == NULL) return NULL; diff --git a/apache2/re.c b/apache2/re.c index 7e0a238c63..0d643ab6fc 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2194,10 +2194,12 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) { if (actionset == NULL) return ""; +#ifndef LOG_NO_FILENAME if ((actionset->rule != NULL) && (actionset->rule->filename != NULL)) { fn = apr_psprintf(msr->mp, " [file \"%s\"] [line \"%d\"]", actionset->rule->filename, actionset->rule->line_num); } +#endif if (actionset->id != NULL) { id = apr_psprintf(msr->mp, " [id \"%s\"]", log_escape(msr->mp, actionset->id)); diff --git a/configure.ac b/configure.ac index 4eefad818c..e7e5098afd 100644 --- a/configure.ac +++ b/configure.ac @@ -427,6 +427,21 @@ AC_ARG_ENABLE(rule-id-validation, unique_id='' ]) +# Disable logging of filename +AC_ARG_ENABLE(filename-logging, + AS_HELP_STRING([--enable-filename-logging], + [Enable logging of filename in audit log. This is the default]), +[ + if test "$enableval" != "no"; then + log_filename= + else + log_filename="-DLOG_NO_FILENAME" + fi +], +[ + log_filename='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -677,7 +692,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 9244cd9824915aa954beb928e7a21ee5f8e32e90 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 10 Apr 2017 15:03:09 +0200 Subject: [PATCH 086/477] Option to disable logging of "Server" in audit log when log level < 9. [Issue #1070 - Marc Stern] --- CHANGES | 3 +++ apache2/msc_logging.c | 3 +++ configure.ac | 17 ++++++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 9765bb2a2a..f64d6db5b7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-server-logging: Option to disable logging of + "Server" in audit log when log level < 9. + [Issue #1070 - Marc Stern] * {dis|en}able-filename-logging: Option to disable logging of filename in audit log. [Issue #1065 - Marc Stern] diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index e35da5520f..e77ccb855f 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -2004,6 +2004,9 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write_producer_header(msr); /* Server */ +#ifdef LOG_NO_SERVER + if (msr->txcfg->debuglog_level >= 9) +#endif if (msr->server_software != NULL) { text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); sec_auditlog_write(msr, text, strlen(text)); diff --git a/configure.ac b/configure.ac index e7e5098afd..4faa3890bd 100644 --- a/configure.ac +++ b/configure.ac @@ -442,6 +442,21 @@ AC_ARG_ENABLE(filename-logging, log_filename='' ]) +# Disable logging of "Server" +AC_ARG_ENABLE(server-logging, + AS_HELP_STRING([--enable-server-logging], + [Enable logging of "Server" in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server= + else + log_server="-DLOG_NO_SERVER" + fi +], +[ + log_server='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -692,7 +707,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 99eb07d94428c288ba54338b7050ab072a7cd754 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 10 Apr 2017 12:01:17 +0200 Subject: [PATCH 087/477] Fix missing rule id in log See https://github.com/SpiderLabs/ModSecurity/issues/391 --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 0d643ab6fc..e7014bf8dd 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1889,7 +1889,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - msr_log(msr, 1, "Rule processing failed."); + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", rule->actionset->id, rule->actionset->msg); if (msr->txcfg->reqintercept_oe == 1) { @@ -1920,7 +1920,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - msr_log(msr, 1, "Rule processing failed with unknown return code: %d.", rc); + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, rule->actionset->id, rule->actionset->msg); apr_table_clear(msr->matched_vars); return -1; } From 45b7706f1f7a5f2c370bfe08e0fa74b5b8580f9d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 11 Apr 2017 10:01:30 -0300 Subject: [PATCH 088/477] Adds sanity check before print action message in the logs This is a sanity check on top of #1379 --- apache2/re.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index e7014bf8dd..46def9e4d5 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1889,8 +1889,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", rule->actionset->id, rule->actionset->msg); - + if (rule->actionset != NULL && rule->actionset->msg != NULL) { + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", rule->actionset->id, rule->actionset->msg); + } else { + msr_log(msr, 1, "Rule processing failed."); + } if (msr->txcfg->reqintercept_oe == 1) { apr_table_clear(msr->matched_vars); @@ -1920,7 +1923,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, rule->actionset->id, rule->actionset->msg); + if (rule->actionset != NULL && rule->actionset->msg != NULL) { + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, rule->actionset->id, rule->actionset->msg); + } else { + msr_log(msr, 1, "Rule processing failed with unknown return code: %d", rc); + } apr_table_clear(msr->matched_vars); return -1; } From 53a8bb2e18bc3f95db8ce69e739be0a7584f2565 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 11 Apr 2017 11:12:14 -0300 Subject: [PATCH 089/477] Adds information about pull request #1379 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index f64d6db5b7..622d78edae 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Adds rule id in logs whenever a rule fail. + [Issue #1379, #391 - Marc Stern] * {dis|en}able-server-logging: Option to disable logging of "Server" in audit log when log level < 9. [Issue #1070 - Marc Stern] From d243818affebefec127034f9714eb521d8c0ee6e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 26 Apr 2017 14:04:45 -0300 Subject: [PATCH 090/477] {dis|en}able-collection-delete-problem-logging: Option to disable logging of collection delete problem in audit log when log level < 9 in audit log [Issue #576 - Marc Stern] --- CHANGES | 3 +++ apache2/persist_dbm.c | 14 ++++++++++---- configure.ac | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 622d78edae..78f0721522 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-collection-delete-problem-logging: Option to disable logging of + collection delete problem in audit log when log level < 9. + [Issue #576 - Marc Stern] * Adds rule id in logs whenever a rule fail. [Issue #1379, #391 - Marc Stern] * {dis|en}able-server-logging: Option to disable logging of diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 76c3820baf..7f8b6f104c 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -217,10 +217,13 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec rc = apr_sdbm_delete(dbm, key); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " "key \"%s\"): %s", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; + msr->msc_sdbm_delete_error = 1; goto cleanup; } @@ -678,10 +681,13 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { if (expiry_time <= now) { rc = apr_sdbm_delete(dbm, key); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " "key \"%s\"): %s", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; + msr->msc_sdbm_delete_error = 1; goto error; } diff --git a/configure.ac b/configure.ac index 4faa3890bd..83adeebbaa 100644 --- a/configure.ac +++ b/configure.ac @@ -457,6 +457,21 @@ AC_ARG_ENABLE(server-logging, log_server='' ]) +# Disable logging of problem when deleting collection +AC_ARG_ENABLE(collection-delete-problem-logging, + AS_HELP_STRING([--enable-collection-delete-problem-logging], + [Enable logging of collection delete problem in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_collection_delete_problem= + else + log_collection_delete_problem="-DLOG_NO_COLL_DELET_PB" + fi +], +[ + log_collection_delete_problem='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -707,7 +722,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 67908f45f442d7caff9d9525e8d4077d8e8c8517 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Apr 2017 14:09:48 -0300 Subject: [PATCH 091/477] Cosmetics: fix #1380 indentation --- apache2/persist_dbm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 7f8b6f104c..4e891cee84 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -218,12 +218,12 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec rc = apr_sdbm_delete(dbm, key); if (rc != APR_SUCCESS) { #ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) + if (msr->txcfg->debuglog_level >= 9) #endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; goto cleanup; } @@ -682,12 +682,12 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { rc = apr_sdbm_delete(dbm, key); if (rc != APR_SUCCESS) { #ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) + if (msr->txcfg->debuglog_level >= 9) #endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " "key \"%s\"): %s", log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; + msr->msc_sdbm_delete_error = 1; goto error; } From 1a5ff4e3718fa757ee5f2d8a51e15da6fdcc019c Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Apr 2017 15:18:24 -0300 Subject: [PATCH 092/477] Fix help message on configuration option added by #1380 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 83adeebbaa..685a8373d9 100644 --- a/configure.ac +++ b/configure.ac @@ -460,7 +460,7 @@ AC_ARG_ENABLE(server-logging, # Disable logging of problem when deleting collection AC_ARG_ENABLE(collection-delete-problem-logging, AS_HELP_STRING([--enable-collection-delete-problem-logging], - [Enable logging of collection delete problem in audit log when log level < 9. This is the default]), + [Enable logging of collection delete problem even when log level is < 9. This is the default]), [ if test "$enableval" != "no"; then log_collection_delete_problem= From f44852b4e011dff25edf947b7101102044877e3e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Apr 2017 15:57:48 -0300 Subject: [PATCH 093/477] Fix the issue number on Marc's CHANGE log entry --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 78f0721522..0cddedfd38 100644 --- a/CHANGES +++ b/CHANGES @@ -3,7 +3,7 @@ DD MMM YYYY - 2.9.2 - To be released * {dis|en}able-collection-delete-problem-logging: Option to disable logging of collection delete problem in audit log when log level < 9. - [Issue #576 - Marc Stern] + [Issue #1380 - Marc Stern] * Adds rule id in logs whenever a rule fail. [Issue #1379, #391 - Marc Stern] * {dis|en}able-server-logging: Option to disable logging of From d1376c55259517baa1afd11422afa401e45e2136 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 26 Apr 2017 16:01:39 -0300 Subject: [PATCH 094/477] Adds option to disable logging of Apache handler in audit log --- CHANGES | 3 +++ apache2/msc_logging.c | 5 ++++- configure.ac | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 0cddedfd38..f255f7866f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-handler-logging: Option to disable logging of Apache handler + in audit log + [Issue #1070, #1381 - Marc Stern] * {dis|en}able-collection-delete-problem-logging: Option to disable logging of collection delete problem in audit log when log level < 9. [Issue #1380 - Marc Stern] diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index e77ccb855f..6be9a0e188 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1974,7 +1974,10 @@ void sec_audit_logger_native(modsec_rec *msr) { } /* Apache-Handler */ - if (msr->r->handler != NULL) { +#ifdef LOG_NO_HANDLER + if (msr->txcfg->debuglog_level >= 9) +#endif + if (msr->r->handler != NULL) { text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); sec_auditlog_write(msr, text, strlen(text)); } diff --git a/configure.ac b/configure.ac index 685a8373d9..fe1e2f4de6 100644 --- a/configure.ac +++ b/configure.ac @@ -472,6 +472,21 @@ AC_ARG_ENABLE(collection-delete-problem-logging, log_collection_delete_problem='' ]) +# Disable logging of Apache handler +AC_ARG_ENABLE(handler-logging, + AS_HELP_STRING([--enable-handler-logging], + [Enable logging of Apache handler in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_handler= + else + log_handler="-DLOG_NO_HANDLER" + fi +], +[ + log_handler='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], From 3de0dfc5fd8ef0106020f69ad1035f6d05190ec8 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Apr 2017 16:04:31 -0300 Subject: [PATCH 095/477] Cosmetics: fix #1381 indentation --- apache2/msc_logging.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 6be9a0e188..1e401b8767 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1975,9 +1975,9 @@ void sec_audit_logger_native(modsec_rec *msr) { /* Apache-Handler */ #ifdef LOG_NO_HANDLER - if (msr->txcfg->debuglog_level >= 9) + if (msr->txcfg->debuglog_level >= 9) #endif - if (msr->r->handler != NULL) { + if (msr->r->handler != NULL) { text = apr_psprintf(msr->mp, "Apache-Handler: %s\n", msr->r->handler); sec_auditlog_write(msr, text, strlen(text)); } From 7b86d8c51d1d93498c179e4a92960326ed693097 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 26 Apr 2017 16:38:12 -0300 Subject: [PATCH 096/477] Extends a7731c by adding JSON support --- apache2/msc_logging.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 1e401b8767..39fcdd719b 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1156,6 +1156,9 @@ void sec_audit_logger_json(modsec_rec *msr) { } /* Apache-Handler */ +#ifdef LOG_NO_HANDLER + if (msr->txcfg->debuglog_level >= 9) +#endif if (msr->r->handler != NULL) { yajl_kv_string(g, "handler", msr->r->handler); } @@ -2007,9 +2010,6 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write_producer_header(msr); /* Server */ -#ifdef LOG_NO_SERVER - if (msr->txcfg->debuglog_level >= 9) -#endif if (msr->server_software != NULL) { text = apr_psprintf(msr->mp, "Server: %s\n", msr->server_software); sec_auditlog_write(msr, text, strlen(text)); From 2c07a17fa372f50f0ce0daa4640121b429f6ce49 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Apr 2017 16:47:42 -0300 Subject: [PATCH 097/477] Fix help message on configuration option added by #1381 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index fe1e2f4de6..fb0fa5d9f6 100644 --- a/configure.ac +++ b/configure.ac @@ -475,7 +475,7 @@ AC_ARG_ENABLE(collection-delete-problem-logging, # Disable logging of Apache handler AC_ARG_ENABLE(handler-logging, AS_HELP_STRING([--enable-handler-logging], - [Enable logging of Apache handler in audit log when log level < 9. This is the default]), + [Enable logging of Apache handler in audit log even when log level is < 9. This is the default]), [ if test "$enableval" != "no"; then log_handler= From a4724dfdab9bf6d073d308c16d211294dbd20773 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 27 Apr 2017 18:40:50 -0300 Subject: [PATCH 098/477] Updates the libinjection --- CHANGES | 2 + apache2/libinjection/libinjection.h | 12 +- apache2/libinjection/libinjection_html5.c | 118 +- apache2/libinjection/libinjection_sqli.c | 132 +- apache2/libinjection/libinjection_sqli.h | 28 +- apache2/libinjection/libinjection_sqli_data.h | 1157 +++++++++++------ apache2/libinjection/libinjection_xss.c | 411 +++--- 7 files changed, 1158 insertions(+), 702 deletions(-) diff --git a/CHANGES b/CHANGES index f255f7866f..b1a148e92d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4 + [ModSecurity team] * {dis|en}able-handler-logging: Option to disable logging of Apache handler in audit log [Issue #1070, #1381 - Marc Stern] diff --git a/apache2/libinjection/libinjection.h b/apache2/libinjection/libinjection.h index 11b14ac5f3..6b40b1df6a 100644 --- a/apache2/libinjection/libinjection.h +++ b/apache2/libinjection/libinjection.h @@ -1,5 +1,5 @@ /** - * Copyright 2012, 2013 Nick Galbreath + * Copyright 2012-2016 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -7,8 +7,8 @@ * */ -#ifndef _LIBINJECTION_H -#define _LIBINJECTION_H +#ifndef LIBINJECTION_H +#define LIBINJECTION_H #ifdef __cplusplus # define LIBINJECTION_BEGIN_DECLS extern "C" { @@ -49,9 +49,9 @@ const char* libinjection_version(void); */ int libinjection_sqli(const char* s, size_t slen, char fingerprint[]); -/** ALPHA version of xss detector. +/** ALPHA version of xss detector. * - * NOT DONE. + * NOT DONE. * * \param[in] s input string, may contain nulls, does not need to be null-terminated * \param[in] slen input string length @@ -62,4 +62,4 @@ int libinjection_xss(const char* s, size_t slen); LIBINJECTION_END_DECLS -#endif /* _LIBINJECTION_H */ +#endif /* LIBINJECTION_H */ diff --git a/apache2/libinjection/libinjection_html5.c b/apache2/libinjection/libinjection_html5.c index 38ef9f0f64..379bb9960d 100644 --- a/apache2/libinjection/libinjection_html5.c +++ b/apache2/libinjection/libinjection_html5.c @@ -71,20 +71,20 @@ void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_ switch (flags) { case DATA_STATE: - hs->state = h5_state_data; - break; + hs->state = h5_state_data; + break; case VALUE_NO_QUOTE: - hs->state = h5_state_before_attribute_name; - break; + hs->state = h5_state_before_attribute_name; + break; case VALUE_SINGLE_QUOTE: - hs->state = h5_state_attribute_value_single_quote; - break; + hs->state = h5_state_attribute_value_single_quote; + break; case VALUE_DOUBLE_QUOTE: - hs->state = h5_state_attribute_value_double_quote; - break; + hs->state = h5_state_attribute_value_double_quote; + break; case VALUE_BACK_QUOTE: - hs->state = h5_state_attribute_value_back_quote; - break; + hs->state = h5_state_attribute_value_back_quote; + break; } } @@ -100,10 +100,18 @@ int libinjection_h5_next(h5_state_t* hs) /** * Everything below here is private * -*/ + */ + static int h5_is_white(char ch) { + /* + * \t = horizontal tab = 0x09 + * \n = newline = 0x0A + * \v = vertical tab = 0x0B + * \f = form feed = 0x0C + * \r = cr = 0x0D + */ return strchr(" \t\n\v\f\r", ch) != NULL; } @@ -112,19 +120,19 @@ static int h5_skip_white(h5_state_t* hs) char ch; while (hs->pos < hs->len) { ch = hs->s[hs->pos]; - switch (ch) { - case 0x00: /* IE only */ - case 0x20: - case 0x09: - case 0x0A: - case 0x0B: /* IE only */ - case 0x0C: + switch (ch) { + case 0x00: /* IE only */ + case 0x20: + case 0x09: + case 0x0A: + case 0x0B: /* IE only */ + case 0x0C: case 0x0D: /* IE only */ hs->pos += 1; - break; - default: + break; + default: return ch; - } + } } return CHAR_EOF; } @@ -259,12 +267,12 @@ static int h5_state_tag_name(h5_state_t* hs) pos = hs->pos; while (pos < hs->len) { ch = hs->s[pos]; - if (ch == 0) { - /* special non-standard case */ - /* allow nulls in tag name */ - /* some old browsers apparently allow and ignore them */ - pos += 1; - } else if (h5_is_white(ch)) { + if (ch == 0) { + /* special non-standard case */ + /* allow nulls in tag name */ + /* some old browsers apparently allow and ignore them */ + pos += 1; + } else if (h5_is_white(ch)) { hs->token_start = hs->s + hs->pos; hs->token_len = pos - hs->pos; hs->token_type = TAG_NAME_OPEN; @@ -332,7 +340,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs) default: { return h5_state_attribute_name(hs); } - } + } } static int h5_state_attribute_name(h5_state_t* hs) @@ -450,12 +458,12 @@ static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar) TRACE(); /* skip initial quote in normal case. - * dont do this is pos == 0 since it means we have started + * don't do this "if (pos == 0)" since it means we have started * in a non-data state. given an input of '><foo * we want to make 0-length attribute name */ if (hs->pos > 0) { - hs->pos += 1; + hs->pos += 1; } @@ -705,10 +713,13 @@ static int h5_state_comment(h5_state_t* hs) char ch; const char* idx; size_t pos; + size_t offset; + const char* end = hs->s + hs->len; TRACE(); pos = hs->pos; while (1) { + idx = (const char*) memchr(hs->s + pos, CHAR_DASH, hs->len - pos); /* did not find anything or has less than 3 chars left */ @@ -719,21 +730,62 @@ static int h5_state_comment(h5_state_t* hs) hs->token_type = TAG_COMMENT; return 1; } - ch = *(idx + 1); + offset = 1; + + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + ch = *(idx + offset); if (ch != CHAR_DASH && ch != CHAR_BANG) { pos = (size_t)(idx - hs->s) + 1; continue; } - ch = *(idx + 2); + + /* need to test */ +#if 0 + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } +#endif + + offset += 1; + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + + ch = *(idx + offset); if (ch != CHAR_GT) { pos = (size_t)(idx - hs->s) + 1; continue; } + offset += 1; /* ends in --> or -!> */ hs->token_start = hs->s + hs->pos; hs->token_len = (size_t)(idx - hs->s) - hs->pos; - hs->pos = (size_t)(idx - hs->s) + 3; + hs->pos = (size_t)(idx + offset - hs->s); hs->state = h5_state_data; hs->token_type = TAG_COMMENT; return 1; diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index 0b67c5cc49..ed506c651e 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -1,5 +1,5 @@ /** - * Copyright 2012,2013 Nick Galbreath + * Copyright 2012,2016 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -112,15 +112,11 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) } while (cur < last) { - if (cur[0] == c0) { - if (cur[1] == c1) { - return cur; - } else { - cur += 2; /* (c0 == c1) ? 1 : 2; */ - } - } else { - cur += 1; + /* safe since cur < len - 1 always */ + if (cur[0] == c0 && cur[1] == c1) { + return cur; } + cur += 1; } return NULL; @@ -191,11 +187,11 @@ static int char_is_white(char ch) { /* ' ' space is 0x32 '\t 0x09 \011 horizontal tab '\n' 0x0a \012 new line - '\v' 0x0b \013 verical tab + '\v' 0x0b \013 vertical tab '\f' 0x0c \014 new page '\r' 0x0d \015 carriage return 0x00 \000 null (oracle) - 0xa0 \240 is latin1 + 0xa0 \240 is Latin-1 */ return strchr(" \t\n\v\f\r\240\000", ch) != NULL; } @@ -294,7 +290,7 @@ static void st_clear(stoken_t * st) static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len, const char value) { - /* done to elimiate unused warning */ + /* done to eliminate unused warning */ (void)len; st->type = (char) stype; st->pos = pos; @@ -402,7 +398,7 @@ static size_t parse_eol_comment(struct libinjection_sqli_state * sf) } } -/** In Ansi mode, hash is an operator +/** In ANSI mode, hash is an operator * In MYSQL mode, it's a EOL comment like '--' */ static size_t parse_hash(struct libinjection_sqli_state * sf) @@ -842,7 +838,7 @@ static size_t parse_bstring(struct libinjection_sqli_state *sf) /* * hex literal string - * re: [XX]'[0123456789abcdefABCDEF]*' + * re: [xX]'[0123456789abcdefABCDEF]*' * mysql has requirement of having EVEN number of chars, * but pgsql does not */ @@ -1072,7 +1068,7 @@ static size_t parse_money(struct libinjection_sqli_state *sf) /* we have $foobar$ ... find it again */ strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); - if (strend == NULL) { + if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { /* fell off edge */ st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); sf->current->str_open = '$'; @@ -1104,7 +1100,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; - int have_dot = 0; int have_e = 0; int have_exp = 0; @@ -1136,7 +1131,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } if (pos < slen && cs[pos] == '.') { - have_dot = 1; pos += 1; while (pos < slen && ISDIGIT(cs[pos])) { pos += 1; @@ -1185,7 +1179,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } } - if (have_dot == 1 && have_e == 1 && have_exp == 0) { + if (have_e == 1 && have_exp == 0) { /* very special form of * "1234.e" * "10.10E" @@ -1242,29 +1236,13 @@ int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) const unsigned char ch = (unsigned char) (s[*pos]); /* - * if not ascii, then continue... - * actually probably need to just assuming - * it's a string + * look up the parser, and call it + * + * Porting Note: this is mapping of char to function + * charparsers[ch]() */ - if (ch > 127) { + fnptr = char_parse_map[ch]; - /* 160 or 0xA0 or octal 240 is "latin1 non-breaking space" - * but is treated as a space in mysql. - */ - if (ch == 160) { - fnptr = parse_white; - } else { - fnptr = parse_word; - } - } else { - /* - * look up the parser, and call it - * - * Porting Note: this is mapping of char to function - * charparsers[ch]() - */ - fnptr = char_parse_map[ch]; - } *pos = (*fnptr) (sf); /* @@ -1349,16 +1327,22 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, a->type == TYPE_UNION || a->type == TYPE_FUNCTION || a->type == TYPE_EXPRESSION || + a->type == TYPE_TSQL || a->type == TYPE_SQLTYPE)) { - return CHAR_NULL; + return FALSE; } - if (b->type != TYPE_KEYWORD && b->type != TYPE_BAREWORD && - b->type != TYPE_OPERATOR && b->type != TYPE_SQLTYPE && - b->type != TYPE_LOGIC_OPERATOR && - b->type != TYPE_FUNCTION && - b->type != TYPE_UNION && b->type != TYPE_EXPRESSION) { - return CHAR_NULL; + if (! + (b->type == TYPE_KEYWORD || + b->type == TYPE_BAREWORD || + b->type == TYPE_OPERATOR || + b->type == TYPE_UNION || + b->type == TYPE_FUNCTION || + b->type == TYPE_EXPRESSION || + b->type == TYPE_TSQL || + b->type == TYPE_SQLTYPE || + b->type == TYPE_LOGIC_OPERATOR)) { + return FALSE; } sz1 = a->len; @@ -1374,7 +1358,6 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, tmp[sz1] = ' '; memcpy(tmp + sz1 + 1, b->val, sz2); tmp[sz3] = CHAR_NULL; - ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3); if (ch != CHAR_NULL) { @@ -1450,6 +1433,13 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) sf->tokenvec[2].type == TYPE_COMMA && sf->tokenvec[3].type == TYPE_LEFTPARENS && sf->tokenvec[4].type == TYPE_NUMBER + ) || + ( + sf->tokenvec[0].type == TYPE_BAREWORD && + sf->tokenvec[1].type == TYPE_RIGHTPARENS && + sf->tokenvec[2].type == TYPE_OPERATOR && + sf->tokenvec[3].type == TYPE_LEFTPARENS && + sf->tokenvec[4].type == TYPE_BAREWORD ) ) { @@ -1541,7 +1531,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) continue; } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) && sf->tokenvec[left+1].type == TYPE_LEFTPARENS && ( - /* TSQL functions but common enough to be collumn names */ + /* TSQL functions but common enough to be column names */ cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || @@ -1564,7 +1554,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) /* pos is the same * other conversions need to go here... for instance - * password CAN be a function, coalese CAN be a function + * password CAN be a function, coalesce CAN be a function */ sf->tokenvec[left].type = TYPE_FUNCTION; continue; @@ -1828,7 +1818,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) * 1,-sin(1) --> 1 (1) * Here, just do * 1,-sin(1) --> 1,sin(1) - * just remove unary opartor + * just remove unary operator */ st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); pos -= 1; @@ -1852,9 +1842,21 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; left = 0; continue; + } else if ((sf->tokenvec[left].type == TYPE_FUNCTION) && + (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) && + (sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) { + /* + * whats going on here + * Some SQL functions like USER() have 0 args + * if we get User(foo), then User is not a function + * This should be expanded since it eliminated a lot of false + * positives. + */ + if (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) { + sf->tokenvec[left].type = TYPE_BAREWORD; + } } - /* no folding -- assume left-most token is is good, now use the existing 2 tokens -- do not get another @@ -2019,7 +2021,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state) } /* - * return TRUE if sqli, false is benign + * return TRUE if SQLi, false is benign */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) { @@ -2033,10 +2035,10 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { /* - * if ending comment is contains 'sp_password' then it's sqli! + * if ending comment is contains 'sp_password' then it's SQLi! * MS Audit log apparently ignores anything with - * 'sp_password' in it. Unable to find primary refernece to - * this "feature" of SQL Server but seems to be known sqli + * 'sp_password' in it. Unable to find primary reference to + * this "feature" of SQL Server but seems to be known SQLi * technique */ if (my_memmem(sql_state->s, sql_state->slen, @@ -2055,7 +2057,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->fingerprint[1] == TYPE_UNION) { if (sql_state->stats_tokens == 2) { - /* not sure why but 1U comes up in Sqli attack + /* not sure why but 1U comes up in SQLi attack * likely part of parameter splitting/etc. * lots of reasons why "1 union" might be normal * input, so beep only if other SQLi things are present @@ -2080,7 +2082,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) /* * for fingerprint like 'nc', only comments of /x are treated - * as SQL... ending comments of "--" and "#" are not sqli + * as SQL... ending comments of "--" and "#" are not SQLi */ if (sql_state->tokenvec[0].type == TYPE_BAREWORD && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2090,7 +2092,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * if '1c' ends with '/x' then it's sqli + * if '1c' ends with '/x' then it's SQLi */ if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2113,13 +2115,13 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT) { if (sql_state->stats_tokens > 2) { - /* we have some folding going on, highly likely sqli */ + /* we have some folding going on, highly likely SQLi */ sql_state->reason = __LINE__; return TRUE; } /* * we check that next character after the number is either whitespace, - * or '/' or a '-' ==> sqli. + * or '/' or a '-' ==> SQLi. */ ch = sql_state->s[sql_state->tokenvec[0].len]; if ( ch <= 32 ) { @@ -2141,7 +2143,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * detect obvious sqli scans.. many people put '--' in plain text + * detect obvious SQLi scans.. many people put '--' in plain text * so only detect if input ends with '--', e.g. 1-- but not 1-- foo */ if ((sql_state->tokenvec[1].len > 2) @@ -2177,7 +2179,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * not sqli + * not SQLi */ sql_state->reason = __LINE__; return FALSE; @@ -2186,8 +2188,8 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) streq(sql_state->fingerprint, "1&1") || streq(sql_state->fingerprint, "1&v") || streq(sql_state->fingerprint, "1&s")) { - /* 'sexy and 17' not sqli - * 'sexy and 17<18' sqli + /* 'sexy and 17' not SQLi + * 'sexy and 17<18' SQLi */ if (sql_state->stats_tokens == 3) { sql_state->reason = __LINE__; @@ -2243,7 +2245,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) size_t slen = sql_state->slen; /* - * no input? not sqli + * no input? not SQLi */ if (slen == 0) { return FALSE; diff --git a/apache2/libinjection/libinjection_sqli.h b/apache2/libinjection/libinjection_sqli.h index 4f16db8dbf..749f7a44a3 100644 --- a/apache2/libinjection/libinjection_sqli.h +++ b/apache2/libinjection/libinjection_sqli.h @@ -1,14 +1,14 @@ /** - * Copyright 2012, 2013 Nick Galbreath + * Copyright 2012-2016 Nick Galbreath * nickg@client9.com - * BSD License -- see COPYING.txt for details + * BSD License -- see `COPYING.txt` for details * * https://libinjection.client9.com/ * */ -#ifndef _LIBINJECTION_SQLI_H -#define _LIBINJECTION_SQLI_H +#ifndef LIBINJECTION_SQLI_H +#define LIBINJECTION_SQLI_H #ifdef __cplusplus extern "C" { @@ -53,7 +53,7 @@ struct libinjection_sqli_token { /* count: * in type 'v', used for number of opening '@' - * but maybe unsed in other contexts + * but maybe used in other contexts */ int count; @@ -63,7 +63,7 @@ struct libinjection_sqli_token { typedef struct libinjection_sqli_token stoken_t; /** - * Pointer to function, takes cstr input, + * Pointer to function, takes c-string input, * returns '\0' for no match, else a char */ struct libinjection_sqli_state; @@ -97,7 +97,7 @@ struct libinjection_sqli_state { int flags; /* - * pos is index in string we are at when tokenizing + * pos is the index in the string during tokenization */ size_t pos; @@ -118,7 +118,7 @@ struct libinjection_sqli_state { /* * fingerprint pattern c-string * +1 for ending null - * Mimimum of 8 bytes to add gcc's -fstack-protector to work + * Minimum of 8 bytes to add gcc's -fstack-protector to work */ char fingerprint[8]; @@ -156,7 +156,7 @@ struct libinjection_sqli_state { */ int stats_comment_c; - /* '#' operators or mysql EOL comments found + /* '#' operators or MySQL EOL comments found * */ int stats_comment_hash; @@ -208,8 +208,8 @@ void libinjection_sqli_init(struct libinjection_sqli_state* sql_state, */ int libinjection_is_sqli(struct libinjection_sqli_state* sql_state); -/* FOR H@CKERS ONLY - * +/* FOR HACKERS ONLY + * provides deep hooks into the decision making process */ void libinjection_sqli_callback(struct libinjection_sqli_state* sql_state, ptr_lookup_fn fn, @@ -269,7 +269,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sql_state); * two functions. With this, you over-ride one part or the other. * * return libinjection_sqli_blacklist(sql_state) && - * libinject_sqli_not_whitelist(sql_state); + * libinjection_sqli_not_whitelist(sql_state); * * \param sql_state should be filled out after libinjection_sqli_fingerprint is called */ @@ -284,7 +284,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state); /* Given a positive match for a pattern (i.e. pattern is SQLi), this function * does additional analysis to reduce false positives. * - * \return TRUE if sqli, false otherwise + * \return TRUE if SQLi, false otherwise */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state); @@ -292,4 +292,4 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state); } #endif -#endif /* _LIBINJECTION_SQLI_H */ +#endif /* LIBINJECTION_SQLI_H */ diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h index 8f3a2e0e23..14b969e3de 100644 --- a/apache2/libinjection/libinjection_sqli_data.h +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -1,6 +1,6 @@ -#ifndef _LIBINJECTION_SQLI_DATA_H -#define _LIBINJECTION_SQLI_DATA_H +#ifndef LIBINJECTION_SQLI_DATA_H +#define LIBINJECTION_SQLI_DATA_H #include "libinjection.h" #include "libinjection_sqli.h" @@ -164,6 +164,134 @@ static const pt2Function char_parse_map[] = { &parse_char, /* 125 */ &parse_operator1, /* 126 */ &parse_white, /* 127 */ + &parse_word, /* 128 */ + &parse_word, /* 129 */ + &parse_word, /* 130 */ + &parse_word, /* 131 */ + &parse_word, /* 132 */ + &parse_word, /* 133 */ + &parse_word, /* 134 */ + &parse_word, /* 135 */ + &parse_word, /* 136 */ + &parse_word, /* 137 */ + &parse_word, /* 138 */ + &parse_word, /* 139 */ + &parse_word, /* 140 */ + &parse_word, /* 141 */ + &parse_word, /* 142 */ + &parse_word, /* 143 */ + &parse_word, /* 144 */ + &parse_word, /* 145 */ + &parse_word, /* 146 */ + &parse_word, /* 147 */ + &parse_word, /* 148 */ + &parse_word, /* 149 */ + &parse_word, /* 150 */ + &parse_word, /* 151 */ + &parse_word, /* 152 */ + &parse_word, /* 153 */ + &parse_word, /* 154 */ + &parse_word, /* 155 */ + &parse_word, /* 156 */ + &parse_word, /* 157 */ + &parse_word, /* 158 */ + &parse_word, /* 159 */ + &parse_white, /* 160 */ + &parse_word, /* 161 */ + &parse_word, /* 162 */ + &parse_word, /* 163 */ + &parse_word, /* 164 */ + &parse_word, /* 165 */ + &parse_word, /* 166 */ + &parse_word, /* 167 */ + &parse_word, /* 168 */ + &parse_word, /* 169 */ + &parse_word, /* 170 */ + &parse_word, /* 171 */ + &parse_word, /* 172 */ + &parse_word, /* 173 */ + &parse_word, /* 174 */ + &parse_word, /* 175 */ + &parse_word, /* 176 */ + &parse_word, /* 177 */ + &parse_word, /* 178 */ + &parse_word, /* 179 */ + &parse_word, /* 180 */ + &parse_word, /* 181 */ + &parse_word, /* 182 */ + &parse_word, /* 183 */ + &parse_word, /* 184 */ + &parse_word, /* 185 */ + &parse_word, /* 186 */ + &parse_word, /* 187 */ + &parse_word, /* 188 */ + &parse_word, /* 189 */ + &parse_word, /* 190 */ + &parse_word, /* 191 */ + &parse_word, /* 192 */ + &parse_word, /* 193 */ + &parse_word, /* 194 */ + &parse_word, /* 195 */ + &parse_word, /* 196 */ + &parse_word, /* 197 */ + &parse_word, /* 198 */ + &parse_word, /* 199 */ + &parse_word, /* 200 */ + &parse_word, /* 201 */ + &parse_word, /* 202 */ + &parse_word, /* 203 */ + &parse_word, /* 204 */ + &parse_word, /* 205 */ + &parse_word, /* 206 */ + &parse_word, /* 207 */ + &parse_word, /* 208 */ + &parse_word, /* 209 */ + &parse_word, /* 210 */ + &parse_word, /* 211 */ + &parse_word, /* 212 */ + &parse_word, /* 213 */ + &parse_word, /* 214 */ + &parse_word, /* 215 */ + &parse_word, /* 216 */ + &parse_word, /* 217 */ + &parse_word, /* 218 */ + &parse_word, /* 219 */ + &parse_word, /* 220 */ + &parse_word, /* 221 */ + &parse_word, /* 222 */ + &parse_word, /* 223 */ + &parse_word, /* 224 */ + &parse_word, /* 225 */ + &parse_word, /* 226 */ + &parse_word, /* 227 */ + &parse_word, /* 228 */ + &parse_word, /* 229 */ + &parse_word, /* 230 */ + &parse_word, /* 231 */ + &parse_word, /* 232 */ + &parse_word, /* 233 */ + &parse_word, /* 234 */ + &parse_word, /* 235 */ + &parse_word, /* 236 */ + &parse_word, /* 237 */ + &parse_word, /* 238 */ + &parse_word, /* 239 */ + &parse_word, /* 240 */ + &parse_word, /* 241 */ + &parse_word, /* 242 */ + &parse_word, /* 243 */ + &parse_word, /* 244 */ + &parse_word, /* 245 */ + &parse_word, /* 246 */ + &parse_word, /* 247 */ + &parse_word, /* 248 */ + &parse_word, /* 249 */ + &parse_word, /* 250 */ + &parse_word, /* 251 */ + &parse_word, /* 252 */ + &parse_word, /* 253 */ + &parse_word, /* 254 */ + &parse_word, /* 255 */ }; static const keyword_t sql_keywords[] = { @@ -395,7 +523,6 @@ static const keyword_t sql_keywords[] = { {"01&1KV", 'F'}, {"01&1O(", 'F'}, {"01&1OF", 'F'}, - {"01&1OO", 'F'}, {"01&1OS", 'F'}, {"01&1OV", 'F'}, {"01&1TN", 'F'}, @@ -522,7 +649,6 @@ static const keyword_t sql_keywords[] = { {"01&S1", 'F'}, {"01&S1;", 'F'}, {"01&S1C", 'F'}, - {"01&S1O", 'F'}, {"01&S;", 'F'}, {"01&S;C", 'F'}, {"01&S;E", 'F'}, @@ -547,7 +673,6 @@ static const keyword_t sql_keywords[] = { {"01&SO1", 'F'}, {"01&SOF", 'F'}, {"01&SON", 'F'}, - {"01&SOO", 'F'}, {"01&SOS", 'F'}, {"01&SOV", 'F'}, {"01&STN", 'F'}, @@ -593,7 +718,6 @@ static const keyword_t sql_keywords[] = { {"01&VKV", 'F'}, {"01&VO(", 'F'}, {"01&VOF", 'F'}, - {"01&VOO", 'F'}, {"01&VOS", 'F'}, {"01&VS", 'F'}, {"01&VS;", 'F'}, @@ -730,6 +854,7 @@ static const keyword_t sql_keywords[] = { {"01)ESO", 'F'}, {"01)EVC", 'F'}, {"01)EVO", 'F'}, + {"01)F(F", 'F'}, {"01)K(1", 'F'}, {"01)K(F", 'F'}, {"01)K(N", 'F'}, @@ -882,6 +1007,7 @@ static const keyword_t sql_keywords[] = { {"01;T(N", 'F'}, {"01;T(S", 'F'}, {"01;T(V", 'F'}, + {"01;T1(", 'F'}, {"01;T1,", 'F'}, {"01;T1;", 'F'}, {"01;T1C", 'F'}, @@ -913,6 +1039,7 @@ static const keyword_t sql_keywords[] = { {"01;TNT", 'F'}, {"01;TNV", 'F'}, {"01;TO(", 'F'}, + {"01;TS(", 'F'}, {"01;TS,", 'F'}, {"01;TS;", 'F'}, {"01;TSC", 'F'}, @@ -920,12 +1047,8 @@ static const keyword_t sql_keywords[] = { {"01;TSK", 'F'}, {"01;TSO", 'F'}, {"01;TST", 'F'}, - {"01;TT(", 'F'}, - {"01;TT1", 'F'}, - {"01;TTF", 'F'}, {"01;TTN", 'F'}, - {"01;TTS", 'F'}, - {"01;TTV", 'F'}, + {"01;TV(", 'F'}, {"01;TV,", 'F'}, {"01;TV;", 'F'}, {"01;TVC", 'F'}, @@ -967,7 +1090,6 @@ static const keyword_t sql_keywords[] = { {"01B(1)", 'F'}, {"01B(1O", 'F'}, {"01B(F(", 'F'}, - {"01B(N)", 'F'}, {"01B(NO", 'F'}, {"01B(S)", 'F'}, {"01B(SO", 'F'}, @@ -1116,11 +1238,18 @@ static const keyword_t sql_keywords[] = { {"01E(SO", 'F'}, {"01E(V)", 'F'}, {"01E(VO", 'F'}, + {"01E1;T", 'F'}, {"01E1C", 'F'}, {"01E1O(", 'F'}, {"01E1OF", 'F'}, {"01E1OS", 'F'}, {"01E1OV", 'F'}, + {"01E1T(", 'F'}, + {"01E1T1", 'F'}, + {"01E1TF", 'F'}, + {"01E1TN", 'F'}, + {"01E1TS", 'F'}, + {"01E1TV", 'F'}, {"01E1UE", 'F'}, {"01EF()", 'F'}, {"01EF(1", 'F'}, @@ -1134,35 +1263,50 @@ static const keyword_t sql_keywords[] = { {"01EK(N", 'F'}, {"01EK(S", 'F'}, {"01EK(V", 'F'}, + {"01EK1;", 'F'}, {"01EK1C", 'F'}, {"01EK1O", 'F'}, + {"01EK1T", 'F'}, {"01EK1U", 'F'}, {"01EKF(", 'F'}, + {"01EKN;", 'F'}, {"01EKNC", 'F'}, {"01EKNE", 'F'}, + {"01EKNT", 'F'}, {"01EKNU", 'F'}, {"01EKOK", 'F'}, + {"01EKS;", 'F'}, {"01EKSC", 'F'}, {"01EKSO", 'F'}, + {"01EKST", 'F'}, {"01EKSU", 'F'}, {"01EKU(", 'F'}, {"01EKU1", 'F'}, {"01EKUE", 'F'}, {"01EKUF", 'F'}, - {"01EKUN", 'F'}, {"01EKUS", 'F'}, {"01EKUV", 'F'}, + {"01EKV;", 'F'}, {"01EKVC", 'F'}, {"01EKVO", 'F'}, + {"01EKVT", 'F'}, {"01EKVU", 'F'}, + {"01EN;T", 'F'}, {"01ENC", 'F'}, {"01ENEN", 'F'}, {"01ENO(", 'F'}, {"01ENOF", 'F'}, {"01ENOS", 'F'}, {"01ENOV", 'F'}, + {"01ENT(", 'F'}, + {"01ENT1", 'F'}, + {"01ENTF", 'F'}, + {"01ENTN", 'F'}, + {"01ENTS", 'F'}, + {"01ENTV", 'F'}, {"01ENUE", 'F'}, {"01EOKN", 'F'}, + {"01ES;T", 'F'}, {"01ESC", 'F'}, {"01ESO(", 'F'}, {"01ESO1", 'F'}, @@ -1170,6 +1314,12 @@ static const keyword_t sql_keywords[] = { {"01ESON", 'F'}, {"01ESOS", 'F'}, {"01ESOV", 'F'}, + {"01EST(", 'F'}, + {"01EST1", 'F'}, + {"01ESTF", 'F'}, + {"01ESTN", 'F'}, + {"01ESTS", 'F'}, + {"01ESTV", 'F'}, {"01ESUE", 'F'}, {"01EU(1", 'F'}, {"01EU(F", 'F'}, @@ -1182,19 +1332,23 @@ static const keyword_t sql_keywords[] = { {"01EUEF", 'F'}, {"01EUEK", 'F'}, {"01EUF(", 'F'}, - {"01EUN,", 'F'}, - {"01EUNC", 'F'}, - {"01EUNO", 'F'}, {"01EUS,", 'F'}, {"01EUSC", 'F'}, {"01EUSO", 'F'}, {"01EUV,", 'F'}, {"01EUVC", 'F'}, {"01EUVO", 'F'}, + {"01EV;T", 'F'}, {"01EVC", 'F'}, {"01EVO(", 'F'}, {"01EVOF", 'F'}, {"01EVOS", 'F'}, + {"01EVT(", 'F'}, + {"01EVT1", 'F'}, + {"01EVTF", 'F'}, + {"01EVTN", 'F'}, + {"01EVTS", 'F'}, + {"01EVTV", 'F'}, {"01EVUE", 'F'}, {"01F()1", 'F'}, {"01F()F", 'F'}, @@ -1251,6 +1405,8 @@ static const keyword_t sql_keywords[] = { {"01K)EN", 'F'}, {"01K)ES", 'F'}, {"01K)EV", 'F'}, + {"01K)F(", 'F'}, + {"01K)O(", 'F'}, {"01K)OF", 'F'}, {"01K)UE", 'F'}, {"01K1", 'F'}, @@ -1387,7 +1543,6 @@ static const keyword_t sql_keywords[] = { {"01KVU(", 'F'}, {"01KVUE", 'F'}, {"01N&F(", 'F'}, - {"01N(1)", 'F'}, {"01N(1O", 'F'}, {"01N(F(", 'F'}, {"01N(S)", 'F'}, @@ -1410,12 +1565,6 @@ static const keyword_t sql_keywords[] = { {"01NESO", 'F'}, {"01NEVC", 'F'}, {"01NEVO", 'F'}, - {"01NF()", 'F'}, - {"01NF(1", 'F'}, - {"01NF(F", 'F'}, - {"01NF(N", 'F'}, - {"01NF(S", 'F'}, - {"01NF(V", 'F'}, {"01NU(E", 'F'}, {"01NUE", 'F'}, {"01NUE(", 'F'}, @@ -1437,6 +1586,7 @@ static const keyword_t sql_keywords[] = { {"01O(EF", 'F'}, {"01O(EK", 'F'}, {"01O(EN", 'F'}, + {"01O(EO", 'F'}, {"01O(ES", 'F'}, {"01O(EV", 'F'}, {"01O(F(", 'F'}, @@ -1502,6 +1652,7 @@ static const keyword_t sql_keywords[] = { {"01OS)B", 'F'}, {"01OS)C", 'F'}, {"01OS)E", 'F'}, + {"01OS)F", 'F'}, {"01OS)K", 'F'}, {"01OS)O", 'F'}, {"01OS)U", 'F'}, @@ -1550,6 +1701,14 @@ static const keyword_t sql_keywords[] = { {"01OSKS", 'F'}, {"01OSKU", 'F'}, {"01OSKV", 'F'}, + {"01OST(", 'F'}, + {"01OST1", 'F'}, + {"01OSTE", 'F'}, + {"01OSTF", 'F'}, + {"01OSTN", 'F'}, + {"01OSTS", 'F'}, + {"01OSTT", 'F'}, + {"01OSTV", 'F'}, {"01OSU", 'F'}, {"01OSU(", 'F'}, {"01OSU1", 'F'}, @@ -1558,7 +1717,6 @@ static const keyword_t sql_keywords[] = { {"01OSUE", 'F'}, {"01OSUF", 'F'}, {"01OSUK", 'F'}, - {"01OSUN", 'F'}, {"01OSUO", 'F'}, {"01OSUS", 'F'}, {"01OSUT", 'F'}, @@ -1589,6 +1747,7 @@ static const keyword_t sql_keywords[] = { {"01OV)B", 'F'}, {"01OV)C", 'F'}, {"01OV)E", 'F'}, + {"01OV)F", 'F'}, {"01OV)K", 'F'}, {"01OV)O", 'F'}, {"01OV)U", 'F'}, @@ -1642,6 +1801,14 @@ static const keyword_t sql_keywords[] = { {"01OVSO", 'F'}, {"01OVSU", 'F'}, {"01OVSV", 'F'}, + {"01OVT(", 'F'}, + {"01OVT1", 'F'}, + {"01OVTE", 'F'}, + {"01OVTF", 'F'}, + {"01OVTN", 'F'}, + {"01OVTS", 'F'}, + {"01OVTT", 'F'}, + {"01OVTV", 'F'}, {"01OVU", 'F'}, {"01OVU(", 'F'}, {"01OVU1", 'F'}, @@ -1650,7 +1817,6 @@ static const keyword_t sql_keywords[] = { {"01OVUE", 'F'}, {"01OVUF", 'F'}, {"01OVUK", 'F'}, - {"01OVUN", 'F'}, {"01OVUO", 'F'}, {"01OVUS", 'F'}, {"01OVUT", 'F'}, @@ -1672,6 +1838,96 @@ static const keyword_t sql_keywords[] = { {"01SVO(", 'F'}, {"01SVOF", 'F'}, {"01SVOS", 'F'}, + {"01T(1)", 'F'}, + {"01T(1O", 'F'}, + {"01T(F(", 'F'}, + {"01T(N)", 'F'}, + {"01T(NO", 'F'}, + {"01T(S)", 'F'}, + {"01T(SO", 'F'}, + {"01T(V)", 'F'}, + {"01T(VO", 'F'}, + {"01T1(F", 'F'}, + {"01T1O(", 'F'}, + {"01T1OF", 'F'}, + {"01T1OS", 'F'}, + {"01T1OV", 'F'}, + {"01TE(1", 'F'}, + {"01TE(F", 'F'}, + {"01TE(N", 'F'}, + {"01TE(S", 'F'}, + {"01TE(V", 'F'}, + {"01TE1N", 'F'}, + {"01TE1O", 'F'}, + {"01TEF(", 'F'}, + {"01TEK(", 'F'}, + {"01TEK1", 'F'}, + {"01TEKF", 'F'}, + {"01TEKN", 'F'}, + {"01TEKS", 'F'}, + {"01TEKV", 'F'}, + {"01TENN", 'F'}, + {"01TENO", 'F'}, + {"01TESN", 'F'}, + {"01TESO", 'F'}, + {"01TEVN", 'F'}, + {"01TEVO", 'F'}, + {"01TF()", 'F'}, + {"01TF(1", 'F'}, + {"01TF(F", 'F'}, + {"01TF(N", 'F'}, + {"01TF(S", 'F'}, + {"01TF(V", 'F'}, + {"01TN(1", 'F'}, + {"01TN(F", 'F'}, + {"01TN(S", 'F'}, + {"01TN(V", 'F'}, + {"01TN1C", 'F'}, + {"01TN1O", 'F'}, + {"01TN;E", 'F'}, + {"01TN;N", 'F'}, + {"01TN;T", 'F'}, + {"01TNE(", 'F'}, + {"01TNE1", 'F'}, + {"01TNEF", 'F'}, + {"01TNEN", 'F'}, + {"01TNES", 'F'}, + {"01TNEV", 'F'}, + {"01TNF(", 'F'}, + {"01TNKN", 'F'}, + {"01TNN:", 'F'}, + {"01TNNC", 'F'}, + {"01TNNO", 'F'}, + {"01TNO(", 'F'}, + {"01TNOF", 'F'}, + {"01TNOS", 'F'}, + {"01TNOV", 'F'}, + {"01TNSC", 'F'}, + {"01TNSO", 'F'}, + {"01TNT(", 'F'}, + {"01TNT1", 'F'}, + {"01TNTF", 'F'}, + {"01TNTN", 'F'}, + {"01TNTS", 'F'}, + {"01TNTV", 'F'}, + {"01TNVC", 'F'}, + {"01TNVO", 'F'}, + {"01TS(F", 'F'}, + {"01TSO(", 'F'}, + {"01TSO1", 'F'}, + {"01TSOF", 'F'}, + {"01TSON", 'F'}, + {"01TSOS", 'F'}, + {"01TSOV", 'F'}, + {"01TTNE", 'F'}, + {"01TTNK", 'F'}, + {"01TTNN", 'F'}, + {"01TTNT", 'F'}, + {"01TV(1", 'F'}, + {"01TV(F", 'F'}, + {"01TVO(", 'F'}, + {"01TVOF", 'F'}, + {"01TVOS", 'F'}, {"01U", 'F'}, {"01U(1)", 'F'}, {"01U(1O", 'F'}, @@ -1757,7 +2013,6 @@ static const keyword_t sql_keywords[] = { {"01UENU", 'F'}, {"01UEOK", 'F'}, {"01UEON", 'F'}, - {"01UEOO", 'F'}, {"01UES", 'F'}, {"01UES&", 'F'}, {"01UES(", 'F'}, @@ -1793,30 +2048,6 @@ static const keyword_t sql_keywords[] = { {"01UF(S", 'F'}, {"01UF(V", 'F'}, {"01UK(E", 'F'}, - {"01UN(1", 'F'}, - {"01UN(F", 'F'}, - {"01UN(S", 'F'}, - {"01UN(V", 'F'}, - {"01UN,(", 'F'}, - {"01UN,F", 'F'}, - {"01UN1(", 'F'}, - {"01UN1,", 'F'}, - {"01UN1O", 'F'}, - {"01UNC", 'F'}, - {"01UNE(", 'F'}, - {"01UNE1", 'F'}, - {"01UNEF", 'F'}, - {"01UNEN", 'F'}, - {"01UNES", 'F'}, - {"01UNEV", 'F'}, - {"01UNF(", 'F'}, - {"01UNO(", 'F'}, - {"01UNOF", 'F'}, - {"01UNOS", 'F'}, - {"01UNOV", 'F'}, - {"01UNS(", 'F'}, - {"01UNS,", 'F'}, - {"01UNSO", 'F'}, {"01UO(E", 'F'}, {"01UON(", 'F'}, {"01UON1", 'F'}, @@ -1834,7 +2065,9 @@ static const keyword_t sql_keywords[] = { {"01UTN(", 'F'}, {"01UTN1", 'F'}, {"01UTNF", 'F'}, + {"01UTNN", 'F'}, {"01UTNS", 'F'}, + {"01UTNV", 'F'}, {"01UV,(", 'F'}, {"01UV,F", 'F'}, {"01UVC", 'F'}, @@ -1986,7 +2219,6 @@ static const keyword_t sql_keywords[] = { {"0E(S)V", 'F'}, {"0E(S,F", 'F'}, {"0E(S1)", 'F'}, - {"0E(S1O", 'F'}, {"0E(SF(", 'F'}, {"0E(SO(", 'F'}, {"0E(SO1", 'F'}, @@ -2270,7 +2502,6 @@ static const keyword_t sql_keywords[] = { {"0EK1N)", 'F'}, {"0EK1N;", 'F'}, {"0EK1NC", 'F'}, - {"0EK1NF", 'F'}, {"0EK1NK", 'F'}, {"0EK1O(", 'F'}, {"0EK1OF", 'F'}, @@ -2321,7 +2552,6 @@ static const keyword_t sql_keywords[] = { {"0EKN1", 'F'}, {"0EKN1;", 'F'}, {"0EKN1C", 'F'}, - {"0EKN1F", 'F'}, {"0EKN1K", 'F'}, {"0EKN1O", 'F'}, {"0EKN;(", 'F'}, @@ -2367,7 +2597,6 @@ static const keyword_t sql_keywords[] = { {"0EKS1C", 'F'}, {"0EKS1F", 'F'}, {"0EKS1K", 'F'}, - {"0EKS1O", 'F'}, {"0EKS;(", 'F'}, {"0EKSB(", 'F'}, {"0EKSB1", 'F'}, @@ -2486,7 +2715,6 @@ static const keyword_t sql_keywords[] = { {"0EN,F(", 'F'}, {"0EN1;", 'F'}, {"0EN1;C", 'F'}, - {"0EN1C", 'F'}, {"0EN1O(", 'F'}, {"0EN1OF", 'F'}, {"0EN1OS", 'F'}, @@ -2620,10 +2848,6 @@ static const keyword_t sql_keywords[] = { {"0ES1;", 'F'}, {"0ES1;C", 'F'}, {"0ES1C", 'F'}, - {"0ES1O(", 'F'}, - {"0ES1OF", 'F'}, - {"0ES1OS", 'F'}, - {"0ES1OV", 'F'}, {"0ES;(E", 'F'}, {"0ESB(1", 'F'}, {"0ESB(F", 'F'}, @@ -2942,6 +3166,14 @@ static const keyword_t sql_keywords[] = { {"0F()SO", 'F'}, {"0F()SU", 'F'}, {"0F()SV", 'F'}, + {"0F()T(", 'F'}, + {"0F()T1", 'F'}, + {"0F()TE", 'F'}, + {"0F()TF", 'F'}, + {"0F()TN", 'F'}, + {"0F()TS", 'F'}, + {"0F()TT", 'F'}, + {"0F()TV", 'F'}, {"0F()U", 'F'}, {"0F()U(", 'F'}, {"0F()U1", 'F'}, @@ -2950,7 +3182,6 @@ static const keyword_t sql_keywords[] = { {"0F()UE", 'F'}, {"0F()UF", 'F'}, {"0F()UK", 'F'}, - {"0F()UN", 'F'}, {"0F()UO", 'F'}, {"0F()US", 'F'}, {"0F()UT", 'F'}, @@ -2980,6 +3211,7 @@ static const keyword_t sql_keywords[] = { {"0F(1)N", 'F'}, {"0F(1)O", 'F'}, {"0F(1)S", 'F'}, + {"0F(1)T", 'F'}, {"0F(1)U", 'F'}, {"0F(1)V", 'F'}, {"0F(1,(", 'F'}, @@ -3003,12 +3235,14 @@ static const keyword_t sql_keywords[] = { {"0F(EK1", 'F'}, {"0F(EKF", 'F'}, {"0F(EKN", 'F'}, + {"0F(EKO", 'F'}, {"0F(EKS", 'F'}, {"0F(EKV", 'F'}, {"0F(EN&", 'F'}, {"0F(EN)", 'F'}, {"0F(ENK", 'F'}, {"0F(ENO", 'F'}, + {"0F(EOK", 'F'}, {"0F(ES&", 'F'}, {"0F(ES)", 'F'}, {"0F(ESK", 'F'}, @@ -3047,6 +3281,7 @@ static const keyword_t sql_keywords[] = { {"0F(N)N", 'F'}, {"0F(N)O", 'F'}, {"0F(N)S", 'F'}, + {"0F(N)T", 'F'}, {"0F(N)U", 'F'}, {"0F(N)V", 'F'}, {"0F(N,(", 'F'}, @@ -3075,6 +3310,7 @@ static const keyword_t sql_keywords[] = { {"0F(S)N", 'F'}, {"0F(S)O", 'F'}, {"0F(S)S", 'F'}, + {"0F(S)T", 'F'}, {"0F(S)U", 'F'}, {"0F(S)V", 'F'}, {"0F(S,(", 'F'}, @@ -3107,6 +3343,7 @@ static const keyword_t sql_keywords[] = { {"0F(V)N", 'F'}, {"0F(V)O", 'F'}, {"0F(V)S", 'F'}, + {"0F(V)T", 'F'}, {"0F(V)U", 'F'}, {"0F(V)V", 'F'}, {"0F(V,(", 'F'}, @@ -3395,7 +3632,6 @@ static const keyword_t sql_keywords[] = { {"0N&1KV", 'F'}, {"0N&1O(", 'F'}, {"0N&1OF", 'F'}, - {"0N&1OO", 'F'}, {"0N&1OS", 'F'}, {"0N&1OV", 'F'}, {"0N&1TN", 'F'}, @@ -3481,7 +3717,6 @@ static const keyword_t sql_keywords[] = { {"0N&NB(", 'F'}, {"0N&NB1", 'F'}, {"0N&NBF", 'F'}, - {"0N&NBN", 'F'}, {"0N&NBS", 'F'}, {"0N&NBV", 'F'}, {"0N&NF(", 'F'}, @@ -3512,7 +3747,6 @@ static const keyword_t sql_keywords[] = { {"0N&S1", 'F'}, {"0N&S1;", 'F'}, {"0N&S1C", 'F'}, - {"0N&S1O", 'F'}, {"0N&S;", 'F'}, {"0N&S;C", 'F'}, {"0N&S;E", 'F'}, @@ -3537,7 +3771,6 @@ static const keyword_t sql_keywords[] = { {"0N&SO1", 'F'}, {"0N&SOF", 'F'}, {"0N&SON", 'F'}, - {"0N&SOO", 'F'}, {"0N&SOS", 'F'}, {"0N&SOV", 'F'}, {"0N&STN", 'F'}, @@ -3583,7 +3816,6 @@ static const keyword_t sql_keywords[] = { {"0N&VKV", 'F'}, {"0N&VO(", 'F'}, {"0N&VOF", 'F'}, - {"0N&VOO", 'F'}, {"0N&VOS", 'F'}, {"0N&VS", 'F'}, {"0N&VS;", 'F'}, @@ -3595,48 +3827,6 @@ static const keyword_t sql_keywords[] = { {"0N&VU;", 'F'}, {"0N&VUC", 'F'}, {"0N&VUE", 'F'}, - {"0N(1)F", 'F'}, - {"0N(1)O", 'F'}, - {"0N(1)U", 'F'}, - {"0N(1)V", 'F'}, - {"0N(1O(", 'F'}, - {"0N(1OF", 'F'}, - {"0N(1OS", 'F'}, - {"0N(1OV", 'F'}, - {"0N(EF(", 'F'}, - {"0N(EKF", 'F'}, - {"0N(EKN", 'F'}, - {"0N(ENK", 'F'}, - {"0N(F()", 'F'}, - {"0N(F(1", 'F'}, - {"0N(F(F", 'F'}, - {"0N(F(N", 'F'}, - {"0N(F(S", 'F'}, - {"0N(F(V", 'F'}, - {"0N(S)1", 'F'}, - {"0N(S)F", 'F'}, - {"0N(S)N", 'F'}, - {"0N(S)O", 'F'}, - {"0N(S)S", 'F'}, - {"0N(S)U", 'F'}, - {"0N(S)V", 'F'}, - {"0N(SO(", 'F'}, - {"0N(SO1", 'F'}, - {"0N(SOF", 'F'}, - {"0N(SON", 'F'}, - {"0N(SOS", 'F'}, - {"0N(SOV", 'F'}, - {"0N(U(E", 'F'}, - {"0N(V)1", 'F'}, - {"0N(V)F", 'F'}, - {"0N(V)N", 'F'}, - {"0N(V)O", 'F'}, - {"0N(V)S", 'F'}, - {"0N(V)U", 'F'}, - {"0N(V)V", 'F'}, - {"0N(VO(", 'F'}, - {"0N(VOF", 'F'}, - {"0N(VOS", 'F'}, {"0N)&(1", 'F'}, {"0N)&(E", 'F'}, {"0N)&(F", 'F'}, @@ -3756,6 +3946,7 @@ static const keyword_t sql_keywords[] = { {"0N)ESO", 'F'}, {"0N)EVC", 'F'}, {"0N)EVO", 'F'}, + {"0N)F(F", 'F'}, {"0N)K(1", 'F'}, {"0N)K(F", 'F'}, {"0N)K(N", 'F'}, @@ -3807,7 +3998,6 @@ static const keyword_t sql_keywords[] = { {"0N)O1K", 'F'}, {"0N)O1U", 'F'}, {"0N)OF(", 'F'}, - {"0N)ON", 'F'}, {"0N)ON&", 'F'}, {"0N)ON)", 'F'}, {"0N)ON;", 'F'}, @@ -3861,12 +4051,6 @@ static const keyword_t sql_keywords[] = { {"0N,F(N", 'F'}, {"0N,F(S", 'F'}, {"0N,F(V", 'F'}, - {"0N1F()", 'F'}, - {"0N1F(1", 'F'}, - {"0N1F(F", 'F'}, - {"0N1F(N", 'F'}, - {"0N1F(S", 'F'}, - {"0N1F(V", 'F'}, {"0N1O(1", 'F'}, {"0N1O(F", 'F'}, {"0N1O(N", 'F'}, @@ -3942,6 +4126,7 @@ static const keyword_t sql_keywords[] = { {"0N;T(N", 'F'}, {"0N;T(S", 'F'}, {"0N;T(V", 'F'}, + {"0N;T1(", 'F'}, {"0N;T1,", 'F'}, {"0N;T1;", 'F'}, {"0N;T1C", 'F'}, @@ -3956,7 +4141,6 @@ static const keyword_t sql_keywords[] = { {"0N;TK1", 'F'}, {"0N;TKF", 'F'}, {"0N;TKK", 'F'}, - {"0N;TKN", 'F'}, {"0N;TKO", 'F'}, {"0N;TKS", 'F'}, {"0N;TKV", 'F'}, @@ -3974,6 +4158,7 @@ static const keyword_t sql_keywords[] = { {"0N;TNT", 'F'}, {"0N;TNV", 'F'}, {"0N;TO(", 'F'}, + {"0N;TS(", 'F'}, {"0N;TS,", 'F'}, {"0N;TS;", 'F'}, {"0N;TSC", 'F'}, @@ -3981,12 +4166,8 @@ static const keyword_t sql_keywords[] = { {"0N;TSK", 'F'}, {"0N;TSO", 'F'}, {"0N;TST", 'F'}, - {"0N;TT(", 'F'}, - {"0N;TT1", 'F'}, - {"0N;TTF", 'F'}, {"0N;TTN", 'F'}, - {"0N;TTS", 'F'}, - {"0N;TTV", 'F'}, + {"0N;TV(", 'F'}, {"0N;TV,", 'F'}, {"0N;TV;", 'F'}, {"0N;TVC", 'F'}, @@ -4028,7 +4209,6 @@ static const keyword_t sql_keywords[] = { {"0NB(1)", 'F'}, {"0NB(1O", 'F'}, {"0NB(F(", 'F'}, - {"0NB(N)", 'F'}, {"0NB(NO", 'F'}, {"0NB(S)", 'F'}, {"0NB(SO", 'F'}, @@ -4176,11 +4356,18 @@ static const keyword_t sql_keywords[] = { {"0NE(SO", 'F'}, {"0NE(V)", 'F'}, {"0NE(VO", 'F'}, + {"0NE1;T", 'F'}, {"0NE1C", 'F'}, {"0NE1O(", 'F'}, {"0NE1OF", 'F'}, {"0NE1OS", 'F'}, {"0NE1OV", 'F'}, + {"0NE1T(", 'F'}, + {"0NE1T1", 'F'}, + {"0NE1TF", 'F'}, + {"0NE1TN", 'F'}, + {"0NE1TS", 'F'}, + {"0NE1TV", 'F'}, {"0NE1UE", 'F'}, {"0NEF()", 'F'}, {"0NEF(1", 'F'}, @@ -4188,13 +4375,20 @@ static const keyword_t sql_keywords[] = { {"0NEF(N", 'F'}, {"0NEF(S", 'F'}, {"0NEF(V", 'F'}, - {"0NENC", 'F'}, + {"0NEN;T", 'F'}, {"0NENO(", 'F'}, {"0NENOF", 'F'}, {"0NENOS", 'F'}, {"0NENOV", 'F'}, + {"0NENT(", 'F'}, + {"0NENT1", 'F'}, + {"0NENTF", 'F'}, + {"0NENTN", 'F'}, + {"0NENTS", 'F'}, + {"0NENTV", 'F'}, {"0NENUE", 'F'}, {"0NEOKN", 'F'}, + {"0NES;T", 'F'}, {"0NESC", 'F'}, {"0NESO(", 'F'}, {"0NESO1", 'F'}, @@ -4202,6 +4396,12 @@ static const keyword_t sql_keywords[] = { {"0NESON", 'F'}, {"0NESOS", 'F'}, {"0NESOV", 'F'}, + {"0NEST(", 'F'}, + {"0NEST1", 'F'}, + {"0NESTF", 'F'}, + {"0NESTN", 'F'}, + {"0NESTS", 'F'}, + {"0NESTV", 'F'}, {"0NESUE", 'F'}, {"0NEU(1", 'F'}, {"0NEU(F", 'F'}, @@ -4214,19 +4414,23 @@ static const keyword_t sql_keywords[] = { {"0NEUEF", 'F'}, {"0NEUEK", 'F'}, {"0NEUF(", 'F'}, - {"0NEUN,", 'F'}, - {"0NEUNC", 'F'}, - {"0NEUNO", 'F'}, {"0NEUS,", 'F'}, {"0NEUSC", 'F'}, {"0NEUSO", 'F'}, {"0NEUV,", 'F'}, {"0NEUVC", 'F'}, {"0NEUVO", 'F'}, + {"0NEV;T", 'F'}, {"0NEVC", 'F'}, {"0NEVO(", 'F'}, {"0NEVOF", 'F'}, {"0NEVOS", 'F'}, + {"0NEVT(", 'F'}, + {"0NEVT1", 'F'}, + {"0NEVTF", 'F'}, + {"0NEVTN", 'F'}, + {"0NEVTS", 'F'}, + {"0NEVTV", 'F'}, {"0NEVUE", 'F'}, {"0NF()1", 'F'}, {"0NF()F", 'F'}, @@ -4237,7 +4441,6 @@ static const keyword_t sql_keywords[] = { {"0NF()U", 'F'}, {"0NF()V", 'F'}, {"0NF(1)", 'F'}, - {"0NF(1N", 'F'}, {"0NF(1O", 'F'}, {"0NF(E(", 'F'}, {"0NF(E1", 'F'}, @@ -4247,7 +4450,6 @@ static const keyword_t sql_keywords[] = { {"0NF(ES", 'F'}, {"0NF(EV", 'F'}, {"0NF(F(", 'F'}, - {"0NF(N)", 'F'}, {"0NF(N,", 'F'}, {"0NF(NO", 'F'}, {"0NF(S)", 'F'}, @@ -4257,7 +4459,6 @@ static const keyword_t sql_keywords[] = { {"0NK(1)", 'F'}, {"0NK(1O", 'F'}, {"0NK(F(", 'F'}, - {"0NK(N)", 'F'}, {"0NK(NO", 'F'}, {"0NK(S)", 'F'}, {"0NK(SO", 'F'}, @@ -4284,6 +4485,8 @@ static const keyword_t sql_keywords[] = { {"0NK)EN", 'F'}, {"0NK)ES", 'F'}, {"0NK)EV", 'F'}, + {"0NK)F(", 'F'}, + {"0NK)O(", 'F'}, {"0NK)OF", 'F'}, {"0NK)UE", 'F'}, {"0NK1", 'F'}, @@ -4337,7 +4540,6 @@ static const keyword_t sql_keywords[] = { {"0NKNBN", 'F'}, {"0NKNBS", 'F'}, {"0NKNBV", 'F'}, - {"0NKNC", 'F'}, {"0NKNE(", 'F'}, {"0NKNE1", 'F'}, {"0NKNEF", 'F'}, @@ -4425,6 +4627,7 @@ static const keyword_t sql_keywords[] = { {"0NO(EF", 'F'}, {"0NO(EK", 'F'}, {"0NO(EN", 'F'}, + {"0NO(EO", 'F'}, {"0NO(ES", 'F'}, {"0NO(EV", 'F'}, {"0NO(F(", 'F'}, @@ -4448,11 +4651,6 @@ static const keyword_t sql_keywords[] = { {"0NOF(S", 'F'}, {"0NOF(V", 'F'}, {"0NOK&(", 'F'}, - {"0NOK&1", 'F'}, - {"0NOK&F", 'F'}, - {"0NOK&N", 'F'}, - {"0NOK&S", 'F'}, - {"0NOK&V", 'F'}, {"0NOK(1", 'F'}, {"0NOK(F", 'F'}, {"0NOK(N", 'F'}, @@ -4490,6 +4688,7 @@ static const keyword_t sql_keywords[] = { {"0NOS)B", 'F'}, {"0NOS)C", 'F'}, {"0NOS)E", 'F'}, + {"0NOS)F", 'F'}, {"0NOS)K", 'F'}, {"0NOS)O", 'F'}, {"0NOS)U", 'F'}, @@ -4498,7 +4697,6 @@ static const keyword_t sql_keywords[] = { {"0NOS1(", 'F'}, {"0NOS1F", 'F'}, {"0NOS1N", 'F'}, - {"0NOS1O", 'F'}, {"0NOS1S", 'F'}, {"0NOS1U", 'F'}, {"0NOS1V", 'F'}, @@ -4538,6 +4736,14 @@ static const keyword_t sql_keywords[] = { {"0NOSKS", 'F'}, {"0NOSKU", 'F'}, {"0NOSKV", 'F'}, + {"0NOST(", 'F'}, + {"0NOST1", 'F'}, + {"0NOSTE", 'F'}, + {"0NOSTF", 'F'}, + {"0NOSTN", 'F'}, + {"0NOSTS", 'F'}, + {"0NOSTT", 'F'}, + {"0NOSTV", 'F'}, {"0NOSU", 'F'}, {"0NOSU(", 'F'}, {"0NOSU1", 'F'}, @@ -4546,7 +4752,6 @@ static const keyword_t sql_keywords[] = { {"0NOSUE", 'F'}, {"0NOSUF", 'F'}, {"0NOSUK", 'F'}, - {"0NOSUN", 'F'}, {"0NOSUO", 'F'}, {"0NOSUS", 'F'}, {"0NOSUT", 'F'}, @@ -4576,6 +4781,7 @@ static const keyword_t sql_keywords[] = { {"0NOV)B", 'F'}, {"0NOV)C", 'F'}, {"0NOV)E", 'F'}, + {"0NOV)F", 'F'}, {"0NOV)K", 'F'}, {"0NOV)O", 'F'}, {"0NOV)U", 'F'}, @@ -4629,6 +4835,14 @@ static const keyword_t sql_keywords[] = { {"0NOVSO", 'F'}, {"0NOVSU", 'F'}, {"0NOVSV", 'F'}, + {"0NOVT(", 'F'}, + {"0NOVT1", 'F'}, + {"0NOVTE", 'F'}, + {"0NOVTF", 'F'}, + {"0NOVTN", 'F'}, + {"0NOVTS", 'F'}, + {"0NOVTT", 'F'}, + {"0NOVTV", 'F'}, {"0NOVU", 'F'}, {"0NOVU(", 'F'}, {"0NOVU1", 'F'}, @@ -4637,7 +4851,6 @@ static const keyword_t sql_keywords[] = { {"0NOVUE", 'F'}, {"0NOVUF", 'F'}, {"0NOVUK", 'F'}, - {"0NOVUN", 'F'}, {"0NOVUO", 'F'}, {"0NOVUS", 'F'}, {"0NOVUT", 'F'}, @@ -4650,6 +4863,96 @@ static const keyword_t sql_keywords[] = { {"0NSUE;", 'F'}, {"0NSUEC", 'F'}, {"0NSUEK", 'F'}, + {"0NT(1)", 'F'}, + {"0NT(1O", 'F'}, + {"0NT(F(", 'F'}, + {"0NT(N)", 'F'}, + {"0NT(NO", 'F'}, + {"0NT(S)", 'F'}, + {"0NT(SO", 'F'}, + {"0NT(V)", 'F'}, + {"0NT(VO", 'F'}, + {"0NT1(F", 'F'}, + {"0NT1O(", 'F'}, + {"0NT1OF", 'F'}, + {"0NT1OS", 'F'}, + {"0NT1OV", 'F'}, + {"0NTE(1", 'F'}, + {"0NTE(F", 'F'}, + {"0NTE(N", 'F'}, + {"0NTE(S", 'F'}, + {"0NTE(V", 'F'}, + {"0NTE1N", 'F'}, + {"0NTE1O", 'F'}, + {"0NTEF(", 'F'}, + {"0NTEK(", 'F'}, + {"0NTEK1", 'F'}, + {"0NTEKF", 'F'}, + {"0NTEKN", 'F'}, + {"0NTEKS", 'F'}, + {"0NTEKV", 'F'}, + {"0NTENN", 'F'}, + {"0NTENO", 'F'}, + {"0NTESN", 'F'}, + {"0NTESO", 'F'}, + {"0NTEVN", 'F'}, + {"0NTEVO", 'F'}, + {"0NTF()", 'F'}, + {"0NTF(1", 'F'}, + {"0NTF(F", 'F'}, + {"0NTF(N", 'F'}, + {"0NTF(S", 'F'}, + {"0NTF(V", 'F'}, + {"0NTN(1", 'F'}, + {"0NTN(F", 'F'}, + {"0NTN(S", 'F'}, + {"0NTN(V", 'F'}, + {"0NTN1C", 'F'}, + {"0NTN1O", 'F'}, + {"0NTN;E", 'F'}, + {"0NTN;N", 'F'}, + {"0NTN;T", 'F'}, + {"0NTNE(", 'F'}, + {"0NTNE1", 'F'}, + {"0NTNEF", 'F'}, + {"0NTNEN", 'F'}, + {"0NTNES", 'F'}, + {"0NTNEV", 'F'}, + {"0NTNF(", 'F'}, + {"0NTNKN", 'F'}, + {"0NTNN:", 'F'}, + {"0NTNNC", 'F'}, + {"0NTNNO", 'F'}, + {"0NTNO(", 'F'}, + {"0NTNOF", 'F'}, + {"0NTNOS", 'F'}, + {"0NTNOV", 'F'}, + {"0NTNSC", 'F'}, + {"0NTNSO", 'F'}, + {"0NTNT(", 'F'}, + {"0NTNT1", 'F'}, + {"0NTNTF", 'F'}, + {"0NTNTN", 'F'}, + {"0NTNTS", 'F'}, + {"0NTNTV", 'F'}, + {"0NTNVC", 'F'}, + {"0NTNVO", 'F'}, + {"0NTS(F", 'F'}, + {"0NTSO(", 'F'}, + {"0NTSO1", 'F'}, + {"0NTSOF", 'F'}, + {"0NTSON", 'F'}, + {"0NTSOS", 'F'}, + {"0NTSOV", 'F'}, + {"0NTTNE", 'F'}, + {"0NTTNK", 'F'}, + {"0NTTNN", 'F'}, + {"0NTTNT", 'F'}, + {"0NTV(1", 'F'}, + {"0NTV(F", 'F'}, + {"0NTVO(", 'F'}, + {"0NTVOF", 'F'}, + {"0NTVOS", 'F'}, {"0NU(1)", 'F'}, {"0NU(1O", 'F'}, {"0NU(E(", 'F'}, @@ -4733,7 +5036,6 @@ static const keyword_t sql_keywords[] = { {"0NUENU", 'F'}, {"0NUEOK", 'F'}, {"0NUEON", 'F'}, - {"0NUEOO", 'F'}, {"0NUES", 'F'}, {"0NUES&", 'F'}, {"0NUES(", 'F'}, @@ -4769,30 +5071,6 @@ static const keyword_t sql_keywords[] = { {"0NUF(S", 'F'}, {"0NUF(V", 'F'}, {"0NUK(E", 'F'}, - {"0NUN(1", 'F'}, - {"0NUN(F", 'F'}, - {"0NUN(S", 'F'}, - {"0NUN(V", 'F'}, - {"0NUN,(", 'F'}, - {"0NUN,F", 'F'}, - {"0NUN1(", 'F'}, - {"0NUN1,", 'F'}, - {"0NUN1O", 'F'}, - {"0NUNC", 'F'}, - {"0NUNE(", 'F'}, - {"0NUNE1", 'F'}, - {"0NUNEF", 'F'}, - {"0NUNEN", 'F'}, - {"0NUNES", 'F'}, - {"0NUNEV", 'F'}, - {"0NUNF(", 'F'}, - {"0NUNO(", 'F'}, - {"0NUNOF", 'F'}, - {"0NUNOS", 'F'}, - {"0NUNOV", 'F'}, - {"0NUNS(", 'F'}, - {"0NUNS,", 'F'}, - {"0NUNSO", 'F'}, {"0NUO(E", 'F'}, {"0NUON(", 'F'}, {"0NUON1", 'F'}, @@ -4810,110 +5088,15 @@ static const keyword_t sql_keywords[] = { {"0NUTN(", 'F'}, {"0NUTN1", 'F'}, {"0NUTNF", 'F'}, + {"0NUTNN", 'F'}, {"0NUTNS", 'F'}, + {"0NUTNV", 'F'}, {"0NUV,(", 'F'}, {"0NUV,F", 'F'}, {"0NUVC", 'F'}, {"0NUVO(", 'F'}, {"0NUVOF", 'F'}, {"0NUVOS", 'F'}, - {"0O(1)O", 'F'}, - {"0O(1)U", 'F'}, - {"0O(1O(", 'F'}, - {"0O(1OF", 'F'}, - {"0O(1OS", 'F'}, - {"0O(1OV", 'F'}, - {"0O(F()", 'F'}, - {"0O(F(1", 'F'}, - {"0O(F(F", 'F'}, - {"0O(F(N", 'F'}, - {"0O(F(S", 'F'}, - {"0O(F(V", 'F'}, - {"0O(N)O", 'F'}, - {"0O(N)U", 'F'}, - {"0O(NO(", 'F'}, - {"0O(NOF", 'F'}, - {"0O(NOS", 'F'}, - {"0O(NOV", 'F'}, - {"0O(S)O", 'F'}, - {"0O(S)U", 'F'}, - {"0O(SO(", 'F'}, - {"0O(SO1", 'F'}, - {"0O(SOF", 'F'}, - {"0O(SON", 'F'}, - {"0O(SOS", 'F'}, - {"0O(SOV", 'F'}, - {"0O(V)O", 'F'}, - {"0O(V)U", 'F'}, - {"0O(VO(", 'F'}, - {"0O(VOF", 'F'}, - {"0O(VOS", 'F'}, - {"0O1UE(", 'F'}, - {"0O1UE1", 'F'}, - {"0O1UEF", 'F'}, - {"0O1UEK", 'F'}, - {"0O1UEN", 'F'}, - {"0O1UES", 'F'}, - {"0O1UEV", 'F'}, - {"0OF()O", 'F'}, - {"0OF()U", 'F'}, - {"0OF(1)", 'F'}, - {"0OF(1O", 'F'}, - {"0OF(F(", 'F'}, - {"0OF(N)", 'F'}, - {"0OF(NO", 'F'}, - {"0OF(S)", 'F'}, - {"0OF(SO", 'F'}, - {"0OF(V)", 'F'}, - {"0OF(VO", 'F'}, - {"0ONUE(", 'F'}, - {"0ONUE1", 'F'}, - {"0ONUEF", 'F'}, - {"0ONUEK", 'F'}, - {"0ONUEN", 'F'}, - {"0ONUES", 'F'}, - {"0ONUEV", 'F'}, - {"0OSUE(", 'F'}, - {"0OSUE1", 'F'}, - {"0OSUEF", 'F'}, - {"0OSUEK", 'F'}, - {"0OSUEN", 'F'}, - {"0OSUES", 'F'}, - {"0OSUEV", 'F'}, - {"0OUE(1", 'F'}, - {"0OUE(F", 'F'}, - {"0OUE(N", 'F'}, - {"0OUE(S", 'F'}, - {"0OUE(V", 'F'}, - {"0OUE1,", 'F'}, - {"0OUE1O", 'F'}, - {"0OUEF(", 'F'}, - {"0OUEK(", 'F'}, - {"0OUEK1", 'F'}, - {"0OUEKF", 'F'}, - {"0OUEKN", 'F'}, - {"0OUEKS", 'F'}, - {"0OUEKV", 'F'}, - {"0OUEN,", 'F'}, - {"0OUENO", 'F'}, - {"0OUES,", 'F'}, - {"0OUESO", 'F'}, - {"0OUEV,", 'F'}, - {"0OUEVO", 'F'}, - {"0OVO(1", 'F'}, - {"0OVO(F", 'F'}, - {"0OVO(N", 'F'}, - {"0OVO(S", 'F'}, - {"0OVO(V", 'F'}, - {"0OVOF(", 'F'}, - {"0OVOSU", 'F'}, - {"0OVUE(", 'F'}, - {"0OVUE1", 'F'}, - {"0OVUEF", 'F'}, - {"0OVUEK", 'F'}, - {"0OVUEN", 'F'}, - {"0OVUES", 'F'}, - {"0OVUEV", 'F'}, {"0S&(1&", 'F'}, {"0S&(1)", 'F'}, {"0S&(1,", 'F'}, @@ -4972,7 +5155,6 @@ static const keyword_t sql_keywords[] = { {"0S&1KV", 'F'}, {"0S&1O(", 'F'}, {"0S&1OF", 'F'}, - {"0S&1OO", 'F'}, {"0S&1OS", 'F'}, {"0S&1OV", 'F'}, {"0S&1TN", 'F'}, @@ -5098,7 +5280,6 @@ static const keyword_t sql_keywords[] = { {"0S&S1", 'F'}, {"0S&S1;", 'F'}, {"0S&S1C", 'F'}, - {"0S&S1O", 'F'}, {"0S&S;", 'F'}, {"0S&S;C", 'F'}, {"0S&S;E", 'F'}, @@ -5123,7 +5304,6 @@ static const keyword_t sql_keywords[] = { {"0S&SO1", 'F'}, {"0S&SOF", 'F'}, {"0S&SON", 'F'}, - {"0S&SOO", 'F'}, {"0S&SOS", 'F'}, {"0S&SOV", 'F'}, {"0S&STN", 'F'}, @@ -5169,7 +5349,6 @@ static const keyword_t sql_keywords[] = { {"0S&VKV", 'F'}, {"0S&VO(", 'F'}, {"0S&VOF", 'F'}, - {"0S&VOO", 'F'}, {"0S&VOS", 'F'}, {"0S&VS", 'F'}, {"0S&VS;", 'F'}, @@ -5306,6 +5485,7 @@ static const keyword_t sql_keywords[] = { {"0S)ESO", 'F'}, {"0S)EVC", 'F'}, {"0S)EVO", 'F'}, + {"0S)F(F", 'F'}, {"0S)K(1", 'F'}, {"0S)K(F", 'F'}, {"0S)K(N", 'F'}, @@ -5419,22 +5599,6 @@ static const keyword_t sql_keywords[] = { {"0S1F(S", 'F'}, {"0S1F(V", 'F'}, {"0S1NC", 'F'}, - {"0S1O(1", 'F'}, - {"0S1O(F", 'F'}, - {"0S1O(N", 'F'}, - {"0S1O(S", 'F'}, - {"0S1O(V", 'F'}, - {"0S1OF(", 'F'}, - {"0S1OS(", 'F'}, - {"0S1OS1", 'F'}, - {"0S1OSF", 'F'}, - {"0S1OSU", 'F'}, - {"0S1OSV", 'F'}, - {"0S1OV(", 'F'}, - {"0S1OVF", 'F'}, - {"0S1OVO", 'F'}, - {"0S1OVS", 'F'}, - {"0S1OVU", 'F'}, {"0S1S;", 'F'}, {"0S1S;C", 'F'}, {"0S1SC", 'F'}, @@ -5495,6 +5659,7 @@ static const keyword_t sql_keywords[] = { {"0S;T(N", 'F'}, {"0S;T(S", 'F'}, {"0S;T(V", 'F'}, + {"0S;T1(", 'F'}, {"0S;T1,", 'F'}, {"0S;T1;", 'F'}, {"0S;T1C", 'F'}, @@ -5527,6 +5692,7 @@ static const keyword_t sql_keywords[] = { {"0S;TNT", 'F'}, {"0S;TNV", 'F'}, {"0S;TO(", 'F'}, + {"0S;TS(", 'F'}, {"0S;TS,", 'F'}, {"0S;TS;", 'F'}, {"0S;TSC", 'F'}, @@ -5534,12 +5700,8 @@ static const keyword_t sql_keywords[] = { {"0S;TSK", 'F'}, {"0S;TSO", 'F'}, {"0S;TST", 'F'}, - {"0S;TT(", 'F'}, - {"0S;TT1", 'F'}, - {"0S;TTF", 'F'}, {"0S;TTN", 'F'}, - {"0S;TTS", 'F'}, - {"0S;TTV", 'F'}, + {"0S;TV(", 'F'}, {"0S;TV,", 'F'}, {"0S;TV;", 'F'}, {"0S;TVC", 'F'}, @@ -5581,7 +5743,6 @@ static const keyword_t sql_keywords[] = { {"0SB(1)", 'F'}, {"0SB(1O", 'F'}, {"0SB(F(", 'F'}, - {"0SB(N)", 'F'}, {"0SB(NO", 'F'}, {"0SB(S)", 'F'}, {"0SB(SO", 'F'}, @@ -5730,11 +5891,18 @@ static const keyword_t sql_keywords[] = { {"0SE(SO", 'F'}, {"0SE(V)", 'F'}, {"0SE(VO", 'F'}, + {"0SE1;T", 'F'}, {"0SE1C", 'F'}, {"0SE1O(", 'F'}, {"0SE1OF", 'F'}, {"0SE1OS", 'F'}, {"0SE1OV", 'F'}, + {"0SE1T(", 'F'}, + {"0SE1T1", 'F'}, + {"0SE1TF", 'F'}, + {"0SE1TN", 'F'}, + {"0SE1TS", 'F'}, + {"0SE1TV", 'F'}, {"0SE1UE", 'F'}, {"0SEF()", 'F'}, {"0SEF(1", 'F'}, @@ -5748,35 +5916,50 @@ static const keyword_t sql_keywords[] = { {"0SEK(N", 'F'}, {"0SEK(S", 'F'}, {"0SEK(V", 'F'}, + {"0SEK1;", 'F'}, {"0SEK1C", 'F'}, {"0SEK1O", 'F'}, + {"0SEK1T", 'F'}, {"0SEK1U", 'F'}, {"0SEKF(", 'F'}, + {"0SEKN;", 'F'}, {"0SEKNC", 'F'}, {"0SEKNE", 'F'}, + {"0SEKNT", 'F'}, {"0SEKNU", 'F'}, {"0SEKOK", 'F'}, + {"0SEKS;", 'F'}, {"0SEKSC", 'F'}, {"0SEKSO", 'F'}, + {"0SEKST", 'F'}, {"0SEKSU", 'F'}, {"0SEKU(", 'F'}, {"0SEKU1", 'F'}, {"0SEKUE", 'F'}, {"0SEKUF", 'F'}, - {"0SEKUN", 'F'}, {"0SEKUS", 'F'}, {"0SEKUV", 'F'}, + {"0SEKV;", 'F'}, {"0SEKVC", 'F'}, {"0SEKVO", 'F'}, + {"0SEKVT", 'F'}, {"0SEKVU", 'F'}, + {"0SEN;T", 'F'}, {"0SENC", 'F'}, {"0SENEN", 'F'}, {"0SENO(", 'F'}, {"0SENOF", 'F'}, {"0SENOS", 'F'}, {"0SENOV", 'F'}, + {"0SENT(", 'F'}, + {"0SENT1", 'F'}, + {"0SENTF", 'F'}, + {"0SENTN", 'F'}, + {"0SENTS", 'F'}, + {"0SENTV", 'F'}, {"0SENUE", 'F'}, {"0SEOKN", 'F'}, + {"0SES;T", 'F'}, {"0SESC", 'F'}, {"0SESO(", 'F'}, {"0SESO1", 'F'}, @@ -5784,6 +5967,12 @@ static const keyword_t sql_keywords[] = { {"0SESON", 'F'}, {"0SESOS", 'F'}, {"0SESOV", 'F'}, + {"0SEST(", 'F'}, + {"0SEST1", 'F'}, + {"0SESTF", 'F'}, + {"0SESTN", 'F'}, + {"0SESTS", 'F'}, + {"0SESTV", 'F'}, {"0SESUE", 'F'}, {"0SEU(1", 'F'}, {"0SEU(F", 'F'}, @@ -5796,19 +5985,23 @@ static const keyword_t sql_keywords[] = { {"0SEUEF", 'F'}, {"0SEUEK", 'F'}, {"0SEUF(", 'F'}, - {"0SEUN,", 'F'}, - {"0SEUNC", 'F'}, - {"0SEUNO", 'F'}, {"0SEUS,", 'F'}, {"0SEUSC", 'F'}, {"0SEUSO", 'F'}, {"0SEUV,", 'F'}, {"0SEUVC", 'F'}, {"0SEUVO", 'F'}, + {"0SEV;T", 'F'}, {"0SEVC", 'F'}, {"0SEVO(", 'F'}, {"0SEVOF", 'F'}, {"0SEVOS", 'F'}, + {"0SEVT(", 'F'}, + {"0SEVT1", 'F'}, + {"0SEVTF", 'F'}, + {"0SEVTN", 'F'}, + {"0SEVTS", 'F'}, + {"0SEVTV", 'F'}, {"0SEVUE", 'F'}, {"0SF()1", 'F'}, {"0SF()F", 'F'}, @@ -5866,6 +6059,8 @@ static const keyword_t sql_keywords[] = { {"0SK)EN", 'F'}, {"0SK)ES", 'F'}, {"0SK)EV", 'F'}, + {"0SK)F(", 'F'}, + {"0SK)O(", 'F'}, {"0SK)OF", 'F'}, {"0SK)UE", 'F'}, {"0SK1", 'F'}, @@ -6011,6 +6206,7 @@ static const keyword_t sql_keywords[] = { {"0SO(EF", 'F'}, {"0SO(EK", 'F'}, {"0SO(EN", 'F'}, + {"0SO(EO", 'F'}, {"0SO(ES", 'F'}, {"0SO(EV", 'F'}, {"0SO(F(", 'F'}, @@ -6043,6 +6239,7 @@ static const keyword_t sql_keywords[] = { {"0SO1)B", 'F'}, {"0SO1)C", 'F'}, {"0SO1)E", 'F'}, + {"0SO1)F", 'F'}, {"0SO1)K", 'F'}, {"0SO1)O", 'F'}, {"0SO1)U", 'F'}, @@ -6089,12 +6286,17 @@ static const keyword_t sql_keywords[] = { {"0SO1N(", 'F'}, {"0SO1N,", 'F'}, {"0SO1NE", 'F'}, - {"0SO1NF", 'F'}, {"0SO1NU", 'F'}, - {"0SO1S(", 'F'}, - {"0SO1SF", 'F'}, {"0SO1SU", 'F'}, {"0SO1SV", 'F'}, + {"0SO1T(", 'F'}, + {"0SO1T1", 'F'}, + {"0SO1TE", 'F'}, + {"0SO1TF", 'F'}, + {"0SO1TN", 'F'}, + {"0SO1TS", 'F'}, + {"0SO1TT", 'F'}, + {"0SO1TV", 'F'}, {"0SO1U", 'F'}, {"0SO1U(", 'F'}, {"0SO1U1", 'F'}, @@ -6103,7 +6305,6 @@ static const keyword_t sql_keywords[] = { {"0SO1UE", 'F'}, {"0SO1UF", 'F'}, {"0SO1UK", 'F'}, - {"0SO1UN", 'F'}, {"0SO1UO", 'F'}, {"0SO1US", 'F'}, {"0SO1UT", 'F'}, @@ -6166,16 +6367,14 @@ static const keyword_t sql_keywords[] = { {"0SON)B", 'F'}, {"0SON)C", 'F'}, {"0SON)E", 'F'}, + {"0SON)F", 'F'}, {"0SON)K", 'F'}, {"0SON)O", 'F'}, {"0SON)U", 'F'}, {"0SON,(", 'F'}, {"0SON,F", 'F'}, {"0SON1(", 'F'}, - {"0SON1F", 'F'}, - {"0SON1N", 'F'}, {"0SON1O", 'F'}, - {"0SON1S", 'F'}, {"0SON1U", 'F'}, {"0SON1V", 'F'}, {"0SON;", 'F'}, @@ -6213,6 +6412,14 @@ static const keyword_t sql_keywords[] = { {"0SONKU", 'F'}, {"0SONKV", 'F'}, {"0SONSU", 'F'}, + {"0SONT(", 'F'}, + {"0SONT1", 'F'}, + {"0SONTE", 'F'}, + {"0SONTF", 'F'}, + {"0SONTN", 'F'}, + {"0SONTS", 'F'}, + {"0SONTT", 'F'}, + {"0SONTV", 'F'}, {"0SONU", 'F'}, {"0SONU(", 'F'}, {"0SONU1", 'F'}, @@ -6221,7 +6428,6 @@ static const keyword_t sql_keywords[] = { {"0SONUE", 'F'}, {"0SONUF", 'F'}, {"0SONUK", 'F'}, - {"0SONUN", 'F'}, {"0SONUO", 'F'}, {"0SONUS", 'F'}, {"0SONUT", 'F'}, @@ -6244,6 +6450,7 @@ static const keyword_t sql_keywords[] = { {"0SOS)B", 'F'}, {"0SOS)C", 'F'}, {"0SOS)E", 'F'}, + {"0SOS)F", 'F'}, {"0SOS)K", 'F'}, {"0SOS)O", 'F'}, {"0SOS)U", 'F'}, @@ -6252,7 +6459,6 @@ static const keyword_t sql_keywords[] = { {"0SOS1(", 'F'}, {"0SOS1F", 'F'}, {"0SOS1N", 'F'}, - {"0SOS1O", 'F'}, {"0SOS1S", 'F'}, {"0SOS1U", 'F'}, {"0SOS1V", 'F'}, @@ -6293,6 +6499,14 @@ static const keyword_t sql_keywords[] = { {"0SOSKS", 'F'}, {"0SOSKU", 'F'}, {"0SOSKV", 'F'}, + {"0SOST(", 'F'}, + {"0SOST1", 'F'}, + {"0SOSTE", 'F'}, + {"0SOSTF", 'F'}, + {"0SOSTN", 'F'}, + {"0SOSTS", 'F'}, + {"0SOSTT", 'F'}, + {"0SOSTV", 'F'}, {"0SOSU", 'F'}, {"0SOSU(", 'F'}, {"0SOSU1", 'F'}, @@ -6301,7 +6515,6 @@ static const keyword_t sql_keywords[] = { {"0SOSUE", 'F'}, {"0SOSUF", 'F'}, {"0SOSUK", 'F'}, - {"0SOSUN", 'F'}, {"0SOSUO", 'F'}, {"0SOSUS", 'F'}, {"0SOSUT", 'F'}, @@ -6332,6 +6545,7 @@ static const keyword_t sql_keywords[] = { {"0SOV)B", 'F'}, {"0SOV)C", 'F'}, {"0SOV)E", 'F'}, + {"0SOV)F", 'F'}, {"0SOV)K", 'F'}, {"0SOV)O", 'F'}, {"0SOV)U", 'F'}, @@ -6385,6 +6599,14 @@ static const keyword_t sql_keywords[] = { {"0SOVSO", 'F'}, {"0SOVSU", 'F'}, {"0SOVSV", 'F'}, + {"0SOVT(", 'F'}, + {"0SOVT1", 'F'}, + {"0SOVTE", 'F'}, + {"0SOVTF", 'F'}, + {"0SOVTN", 'F'}, + {"0SOVTS", 'F'}, + {"0SOVTT", 'F'}, + {"0SOVTV", 'F'}, {"0SOVU", 'F'}, {"0SOVU(", 'F'}, {"0SOVU1", 'F'}, @@ -6393,11 +6615,100 @@ static const keyword_t sql_keywords[] = { {"0SOVUE", 'F'}, {"0SOVUF", 'F'}, {"0SOVUK", 'F'}, - {"0SOVUN", 'F'}, {"0SOVUO", 'F'}, {"0SOVUS", 'F'}, {"0SOVUT", 'F'}, {"0SOVUV", 'F'}, + {"0ST(1)", 'F'}, + {"0ST(1O", 'F'}, + {"0ST(F(", 'F'}, + {"0ST(N)", 'F'}, + {"0ST(NO", 'F'}, + {"0ST(S)", 'F'}, + {"0ST(SO", 'F'}, + {"0ST(V)", 'F'}, + {"0ST(VO", 'F'}, + {"0ST1(F", 'F'}, + {"0ST1O(", 'F'}, + {"0ST1OF", 'F'}, + {"0ST1OS", 'F'}, + {"0ST1OV", 'F'}, + {"0STE(1", 'F'}, + {"0STE(F", 'F'}, + {"0STE(N", 'F'}, + {"0STE(S", 'F'}, + {"0STE(V", 'F'}, + {"0STE1N", 'F'}, + {"0STE1O", 'F'}, + {"0STEF(", 'F'}, + {"0STEK(", 'F'}, + {"0STEK1", 'F'}, + {"0STEKF", 'F'}, + {"0STEKN", 'F'}, + {"0STEKS", 'F'}, + {"0STEKV", 'F'}, + {"0STENN", 'F'}, + {"0STENO", 'F'}, + {"0STESN", 'F'}, + {"0STESO", 'F'}, + {"0STEVN", 'F'}, + {"0STEVO", 'F'}, + {"0STF()", 'F'}, + {"0STF(1", 'F'}, + {"0STF(F", 'F'}, + {"0STF(N", 'F'}, + {"0STF(S", 'F'}, + {"0STF(V", 'F'}, + {"0STN(1", 'F'}, + {"0STN(F", 'F'}, + {"0STN(S", 'F'}, + {"0STN(V", 'F'}, + {"0STN1C", 'F'}, + {"0STN1O", 'F'}, + {"0STN;E", 'F'}, + {"0STN;N", 'F'}, + {"0STN;T", 'F'}, + {"0STNE(", 'F'}, + {"0STNE1", 'F'}, + {"0STNEF", 'F'}, + {"0STNEN", 'F'}, + {"0STNES", 'F'}, + {"0STNEV", 'F'}, + {"0STNF(", 'F'}, + {"0STNKN", 'F'}, + {"0STNN:", 'F'}, + {"0STNNC", 'F'}, + {"0STNNO", 'F'}, + {"0STNO(", 'F'}, + {"0STNOF", 'F'}, + {"0STNOS", 'F'}, + {"0STNOV", 'F'}, + {"0STNSC", 'F'}, + {"0STNSO", 'F'}, + {"0STNT(", 'F'}, + {"0STNT1", 'F'}, + {"0STNTF", 'F'}, + {"0STNTN", 'F'}, + {"0STNTS", 'F'}, + {"0STNTV", 'F'}, + {"0STNVC", 'F'}, + {"0STNVO", 'F'}, + {"0STS(F", 'F'}, + {"0STSO(", 'F'}, + {"0STSO1", 'F'}, + {"0STSOF", 'F'}, + {"0STSON", 'F'}, + {"0STSOS", 'F'}, + {"0STSOV", 'F'}, + {"0STTNE", 'F'}, + {"0STTNK", 'F'}, + {"0STTNN", 'F'}, + {"0STTNT", 'F'}, + {"0STV(1", 'F'}, + {"0STV(F", 'F'}, + {"0STVO(", 'F'}, + {"0STVOF", 'F'}, + {"0STVOS", 'F'}, {"0SU(1)", 'F'}, {"0SU(1O", 'F'}, {"0SU(E(", 'F'}, @@ -6481,7 +6792,6 @@ static const keyword_t sql_keywords[] = { {"0SUENU", 'F'}, {"0SUEOK", 'F'}, {"0SUEON", 'F'}, - {"0SUEOO", 'F'}, {"0SUES", 'F'}, {"0SUES&", 'F'}, {"0SUES(", 'F'}, @@ -6517,30 +6827,6 @@ static const keyword_t sql_keywords[] = { {"0SUF(S", 'F'}, {"0SUF(V", 'F'}, {"0SUK(E", 'F'}, - {"0SUN(1", 'F'}, - {"0SUN(F", 'F'}, - {"0SUN(S", 'F'}, - {"0SUN(V", 'F'}, - {"0SUN,(", 'F'}, - {"0SUN,F", 'F'}, - {"0SUN1(", 'F'}, - {"0SUN1,", 'F'}, - {"0SUN1O", 'F'}, - {"0SUNC", 'F'}, - {"0SUNE(", 'F'}, - {"0SUNE1", 'F'}, - {"0SUNEF", 'F'}, - {"0SUNEN", 'F'}, - {"0SUNES", 'F'}, - {"0SUNEV", 'F'}, - {"0SUNF(", 'F'}, - {"0SUNO(", 'F'}, - {"0SUNOF", 'F'}, - {"0SUNOS", 'F'}, - {"0SUNOV", 'F'}, - {"0SUNS(", 'F'}, - {"0SUNS,", 'F'}, - {"0SUNSO", 'F'}, {"0SUO(E", 'F'}, {"0SUON(", 'F'}, {"0SUON1", 'F'}, @@ -6558,7 +6844,9 @@ static const keyword_t sql_keywords[] = { {"0SUTN(", 'F'}, {"0SUTN1", 'F'}, {"0SUTNF", 'F'}, + {"0SUTNN", 'F'}, {"0SUTNS", 'F'}, + {"0SUTNV", 'F'}, {"0SUV,(", 'F'}, {"0SUV,F", 'F'}, {"0SUVC", 'F'}, @@ -6582,7 +6870,6 @@ static const keyword_t sql_keywords[] = { {"0SVOSF", 'F'}, {"0SVOSU", 'F'}, {"0SVOSV", 'F'}, - {"0SVS", 'F'}, {"0SVS;", 'F'}, {"0SVS;C", 'F'}, {"0SVSC", 'F'}, @@ -6622,16 +6909,19 @@ static const keyword_t sql_keywords[] = { {"0T(N1)", 'F'}, {"0T(N1O", 'F'}, {"0T(NF(", 'F'}, + {"0T(NN)", 'F'}, + {"0T(NNO", 'F'}, {"0T(NO(", 'F'}, {"0T(NOF", 'F'}, {"0T(NOS", 'F'}, {"0T(NOV", 'F'}, {"0T(NS)", 'F'}, {"0T(NSO", 'F'}, + {"0T(NV)", 'F'}, + {"0T(NVO", 'F'}, {"0T(S)F", 'F'}, {"0T(S)O", 'F'}, {"0T(S1)", 'F'}, - {"0T(S1O", 'F'}, {"0T(SF(", 'F'}, {"0T(SN)", 'F'}, {"0T(SNO", 'F'}, @@ -6696,6 +6986,12 @@ static const keyword_t sql_keywords[] = { {"0TNF(N", 'F'}, {"0TNF(S", 'F'}, {"0TNF(V", 'F'}, + {"0TNN;", 'F'}, + {"0TNN;C", 'F'}, + {"0TNNO(", 'F'}, + {"0TNNOF", 'F'}, + {"0TNNOS", 'F'}, + {"0TNNOV", 'F'}, {"0TNO(1", 'F'}, {"0TNO(F", 'F'}, {"0TNO(N", 'F'}, @@ -6714,6 +7010,9 @@ static const keyword_t sql_keywords[] = { {"0TNSOS", 'F'}, {"0TNSOV", 'F'}, {"0TNV;", 'F'}, + {"0TNV;C", 'F'}, + {"0TNVO(", 'F'}, + {"0TNVOF", 'F'}, {"0TNVOS", 'F'}, {"0TSF(1", 'F'}, {"0TSF(F", 'F'}, @@ -6944,7 +7243,6 @@ static const keyword_t sql_keywords[] = { {"0V&1KV", 'F'}, {"0V&1O(", 'F'}, {"0V&1OF", 'F'}, - {"0V&1OO", 'F'}, {"0V&1OS", 'F'}, {"0V&1OV", 'F'}, {"0V&1TN", 'F'}, @@ -7070,7 +7368,6 @@ static const keyword_t sql_keywords[] = { {"0V&S1", 'F'}, {"0V&S1;", 'F'}, {"0V&S1C", 'F'}, - {"0V&S1O", 'F'}, {"0V&S;", 'F'}, {"0V&S;C", 'F'}, {"0V&S;E", 'F'}, @@ -7095,7 +7392,6 @@ static const keyword_t sql_keywords[] = { {"0V&SO1", 'F'}, {"0V&SOF", 'F'}, {"0V&SON", 'F'}, - {"0V&SOO", 'F'}, {"0V&SOS", 'F'}, {"0V&SOV", 'F'}, {"0V&STN", 'F'}, @@ -7141,7 +7437,6 @@ static const keyword_t sql_keywords[] = { {"0V&VKV", 'F'}, {"0V&VO(", 'F'}, {"0V&VOF", 'F'}, - {"0V&VOO", 'F'}, {"0V&VOS", 'F'}, {"0V&VS", 'F'}, {"0V&VS;", 'F'}, @@ -7278,6 +7573,7 @@ static const keyword_t sql_keywords[] = { {"0V)ESO", 'F'}, {"0V)EVC", 'F'}, {"0V)EVO", 'F'}, + {"0V)F(F", 'F'}, {"0V)K(1", 'F'}, {"0V)K(F", 'F'}, {"0V)K(N", 'F'}, @@ -7431,6 +7727,7 @@ static const keyword_t sql_keywords[] = { {"0V;T(N", 'F'}, {"0V;T(S", 'F'}, {"0V;T(V", 'F'}, + {"0V;T1(", 'F'}, {"0V;T1,", 'F'}, {"0V;T1;", 'F'}, {"0V;T1C", 'F'}, @@ -7463,6 +7760,7 @@ static const keyword_t sql_keywords[] = { {"0V;TNT", 'F'}, {"0V;TNV", 'F'}, {"0V;TO(", 'F'}, + {"0V;TS(", 'F'}, {"0V;TS,", 'F'}, {"0V;TS;", 'F'}, {"0V;TSC", 'F'}, @@ -7470,12 +7768,8 @@ static const keyword_t sql_keywords[] = { {"0V;TSK", 'F'}, {"0V;TSO", 'F'}, {"0V;TST", 'F'}, - {"0V;TT(", 'F'}, - {"0V;TT1", 'F'}, - {"0V;TTF", 'F'}, {"0V;TTN", 'F'}, - {"0V;TTS", 'F'}, - {"0V;TTV", 'F'}, + {"0V;TV(", 'F'}, {"0V;TV,", 'F'}, {"0V;TV;", 'F'}, {"0V;TVC", 'F'}, @@ -7517,7 +7811,6 @@ static const keyword_t sql_keywords[] = { {"0VB(1)", 'F'}, {"0VB(1O", 'F'}, {"0VB(F(", 'F'}, - {"0VB(N)", 'F'}, {"0VB(NO", 'F'}, {"0VB(S)", 'F'}, {"0VB(SO", 'F'}, @@ -7666,11 +7959,18 @@ static const keyword_t sql_keywords[] = { {"0VE(SO", 'F'}, {"0VE(V)", 'F'}, {"0VE(VO", 'F'}, + {"0VE1;T", 'F'}, {"0VE1C", 'F'}, {"0VE1O(", 'F'}, {"0VE1OF", 'F'}, {"0VE1OS", 'F'}, {"0VE1OV", 'F'}, + {"0VE1T(", 'F'}, + {"0VE1T1", 'F'}, + {"0VE1TF", 'F'}, + {"0VE1TN", 'F'}, + {"0VE1TS", 'F'}, + {"0VE1TV", 'F'}, {"0VE1UE", 'F'}, {"0VEF()", 'F'}, {"0VEF(1", 'F'}, @@ -7684,35 +7984,50 @@ static const keyword_t sql_keywords[] = { {"0VEK(N", 'F'}, {"0VEK(S", 'F'}, {"0VEK(V", 'F'}, + {"0VEK1;", 'F'}, {"0VEK1C", 'F'}, {"0VEK1O", 'F'}, + {"0VEK1T", 'F'}, {"0VEK1U", 'F'}, {"0VEKF(", 'F'}, + {"0VEKN;", 'F'}, {"0VEKNC", 'F'}, {"0VEKNE", 'F'}, + {"0VEKNT", 'F'}, {"0VEKNU", 'F'}, {"0VEKOK", 'F'}, + {"0VEKS;", 'F'}, {"0VEKSC", 'F'}, {"0VEKSO", 'F'}, + {"0VEKST", 'F'}, {"0VEKSU", 'F'}, {"0VEKU(", 'F'}, {"0VEKU1", 'F'}, {"0VEKUE", 'F'}, {"0VEKUF", 'F'}, - {"0VEKUN", 'F'}, {"0VEKUS", 'F'}, {"0VEKUV", 'F'}, + {"0VEKV;", 'F'}, {"0VEKVC", 'F'}, {"0VEKVO", 'F'}, + {"0VEKVT", 'F'}, {"0VEKVU", 'F'}, + {"0VEN;T", 'F'}, {"0VENC", 'F'}, {"0VENEN", 'F'}, {"0VENO(", 'F'}, {"0VENOF", 'F'}, {"0VENOS", 'F'}, {"0VENOV", 'F'}, + {"0VENT(", 'F'}, + {"0VENT1", 'F'}, + {"0VENTF", 'F'}, + {"0VENTN", 'F'}, + {"0VENTS", 'F'}, + {"0VENTV", 'F'}, {"0VENUE", 'F'}, {"0VEOKN", 'F'}, + {"0VES;T", 'F'}, {"0VESC", 'F'}, {"0VESO(", 'F'}, {"0VESO1", 'F'}, @@ -7720,6 +8035,12 @@ static const keyword_t sql_keywords[] = { {"0VESON", 'F'}, {"0VESOS", 'F'}, {"0VESOV", 'F'}, + {"0VEST(", 'F'}, + {"0VEST1", 'F'}, + {"0VESTF", 'F'}, + {"0VESTN", 'F'}, + {"0VESTS", 'F'}, + {"0VESTV", 'F'}, {"0VESUE", 'F'}, {"0VEU(1", 'F'}, {"0VEU(F", 'F'}, @@ -7732,19 +8053,23 @@ static const keyword_t sql_keywords[] = { {"0VEUEF", 'F'}, {"0VEUEK", 'F'}, {"0VEUF(", 'F'}, - {"0VEUN,", 'F'}, - {"0VEUNC", 'F'}, - {"0VEUNO", 'F'}, {"0VEUS,", 'F'}, {"0VEUSC", 'F'}, {"0VEUSO", 'F'}, {"0VEUV,", 'F'}, {"0VEUVC", 'F'}, {"0VEUVO", 'F'}, + {"0VEV;T", 'F'}, {"0VEVC", 'F'}, {"0VEVO(", 'F'}, {"0VEVOF", 'F'}, {"0VEVOS", 'F'}, + {"0VEVT(", 'F'}, + {"0VEVT1", 'F'}, + {"0VEVTF", 'F'}, + {"0VEVTN", 'F'}, + {"0VEVTS", 'F'}, + {"0VEVTV", 'F'}, {"0VEVUE", 'F'}, {"0VF()1", 'F'}, {"0VF()F", 'F'}, @@ -7802,6 +8127,8 @@ static const keyword_t sql_keywords[] = { {"0VK)EN", 'F'}, {"0VK)ES", 'F'}, {"0VK)EV", 'F'}, + {"0VK)F(", 'F'}, + {"0VK)O(", 'F'}, {"0VK)OF", 'F'}, {"0VK)UE", 'F'}, {"0VK1", 'F'}, @@ -7947,6 +8274,7 @@ static const keyword_t sql_keywords[] = { {"0VO(EF", 'F'}, {"0VO(EK", 'F'}, {"0VO(EN", 'F'}, + {"0VO(EO", 'F'}, {"0VO(ES", 'F'}, {"0VO(EV", 'F'}, {"0VO(F(", 'F'}, @@ -8012,6 +8340,7 @@ static const keyword_t sql_keywords[] = { {"0VOS)B", 'F'}, {"0VOS)C", 'F'}, {"0VOS)E", 'F'}, + {"0VOS)F", 'F'}, {"0VOS)K", 'F'}, {"0VOS)O", 'F'}, {"0VOS)U", 'F'}, @@ -8020,7 +8349,6 @@ static const keyword_t sql_keywords[] = { {"0VOS1(", 'F'}, {"0VOS1F", 'F'}, {"0VOS1N", 'F'}, - {"0VOS1O", 'F'}, {"0VOS1S", 'F'}, {"0VOS1U", 'F'}, {"0VOS1V", 'F'}, @@ -8061,6 +8389,14 @@ static const keyword_t sql_keywords[] = { {"0VOSKS", 'F'}, {"0VOSKU", 'F'}, {"0VOSKV", 'F'}, + {"0VOST(", 'F'}, + {"0VOST1", 'F'}, + {"0VOSTE", 'F'}, + {"0VOSTF", 'F'}, + {"0VOSTN", 'F'}, + {"0VOSTS", 'F'}, + {"0VOSTT", 'F'}, + {"0VOSTV", 'F'}, {"0VOSU", 'F'}, {"0VOSU(", 'F'}, {"0VOSU1", 'F'}, @@ -8069,7 +8405,6 @@ static const keyword_t sql_keywords[] = { {"0VOSUE", 'F'}, {"0VOSUF", 'F'}, {"0VOSUK", 'F'}, - {"0VOSUN", 'F'}, {"0VOSUO", 'F'}, {"0VOSUS", 'F'}, {"0VOSUT", 'F'}, @@ -8082,6 +8417,96 @@ static const keyword_t sql_keywords[] = { {"0VOU(E", 'F'}, {"0VOUEK", 'F'}, {"0VOUEN", 'F'}, + {"0VT(1)", 'F'}, + {"0VT(1O", 'F'}, + {"0VT(F(", 'F'}, + {"0VT(N)", 'F'}, + {"0VT(NO", 'F'}, + {"0VT(S)", 'F'}, + {"0VT(SO", 'F'}, + {"0VT(V)", 'F'}, + {"0VT(VO", 'F'}, + {"0VT1(F", 'F'}, + {"0VT1O(", 'F'}, + {"0VT1OF", 'F'}, + {"0VT1OS", 'F'}, + {"0VT1OV", 'F'}, + {"0VTE(1", 'F'}, + {"0VTE(F", 'F'}, + {"0VTE(N", 'F'}, + {"0VTE(S", 'F'}, + {"0VTE(V", 'F'}, + {"0VTE1N", 'F'}, + {"0VTE1O", 'F'}, + {"0VTEF(", 'F'}, + {"0VTEK(", 'F'}, + {"0VTEK1", 'F'}, + {"0VTEKF", 'F'}, + {"0VTEKN", 'F'}, + {"0VTEKS", 'F'}, + {"0VTEKV", 'F'}, + {"0VTENN", 'F'}, + {"0VTENO", 'F'}, + {"0VTESN", 'F'}, + {"0VTESO", 'F'}, + {"0VTEVN", 'F'}, + {"0VTEVO", 'F'}, + {"0VTF()", 'F'}, + {"0VTF(1", 'F'}, + {"0VTF(F", 'F'}, + {"0VTF(N", 'F'}, + {"0VTF(S", 'F'}, + {"0VTF(V", 'F'}, + {"0VTN(1", 'F'}, + {"0VTN(F", 'F'}, + {"0VTN(S", 'F'}, + {"0VTN(V", 'F'}, + {"0VTN1C", 'F'}, + {"0VTN1O", 'F'}, + {"0VTN;E", 'F'}, + {"0VTN;N", 'F'}, + {"0VTN;T", 'F'}, + {"0VTNE(", 'F'}, + {"0VTNE1", 'F'}, + {"0VTNEF", 'F'}, + {"0VTNEN", 'F'}, + {"0VTNES", 'F'}, + {"0VTNEV", 'F'}, + {"0VTNF(", 'F'}, + {"0VTNKN", 'F'}, + {"0VTNN:", 'F'}, + {"0VTNNC", 'F'}, + {"0VTNNO", 'F'}, + {"0VTNO(", 'F'}, + {"0VTNOF", 'F'}, + {"0VTNOS", 'F'}, + {"0VTNOV", 'F'}, + {"0VTNSC", 'F'}, + {"0VTNSO", 'F'}, + {"0VTNT(", 'F'}, + {"0VTNT1", 'F'}, + {"0VTNTF", 'F'}, + {"0VTNTN", 'F'}, + {"0VTNTS", 'F'}, + {"0VTNTV", 'F'}, + {"0VTNVC", 'F'}, + {"0VTNVO", 'F'}, + {"0VTS(F", 'F'}, + {"0VTSO(", 'F'}, + {"0VTSO1", 'F'}, + {"0VTSOF", 'F'}, + {"0VTSON", 'F'}, + {"0VTSOS", 'F'}, + {"0VTSOV", 'F'}, + {"0VTTNE", 'F'}, + {"0VTTNK", 'F'}, + {"0VTTNN", 'F'}, + {"0VTTNT", 'F'}, + {"0VTV(1", 'F'}, + {"0VTV(F", 'F'}, + {"0VTVO(", 'F'}, + {"0VTVOF", 'F'}, + {"0VTVOS", 'F'}, {"0VU", 'F'}, {"0VU(1)", 'F'}, {"0VU(1O", 'F'}, @@ -8166,7 +8591,6 @@ static const keyword_t sql_keywords[] = { {"0VUENU", 'F'}, {"0VUEOK", 'F'}, {"0VUEON", 'F'}, - {"0VUEOO", 'F'}, {"0VUES", 'F'}, {"0VUES&", 'F'}, {"0VUES(", 'F'}, @@ -8202,30 +8626,6 @@ static const keyword_t sql_keywords[] = { {"0VUF(S", 'F'}, {"0VUF(V", 'F'}, {"0VUK(E", 'F'}, - {"0VUN(1", 'F'}, - {"0VUN(F", 'F'}, - {"0VUN(S", 'F'}, - {"0VUN(V", 'F'}, - {"0VUN,(", 'F'}, - {"0VUN,F", 'F'}, - {"0VUN1(", 'F'}, - {"0VUN1,", 'F'}, - {"0VUN1O", 'F'}, - {"0VUNC", 'F'}, - {"0VUNE(", 'F'}, - {"0VUNE1", 'F'}, - {"0VUNEF", 'F'}, - {"0VUNEN", 'F'}, - {"0VUNES", 'F'}, - {"0VUNEV", 'F'}, - {"0VUNF(", 'F'}, - {"0VUNO(", 'F'}, - {"0VUNOF", 'F'}, - {"0VUNOS", 'F'}, - {"0VUNOV", 'F'}, - {"0VUNS(", 'F'}, - {"0VUNS,", 'F'}, - {"0VUNSO", 'F'}, {"0VUO(E", 'F'}, {"0VUON(", 'F'}, {"0VUON1", 'F'}, @@ -8243,7 +8643,9 @@ static const keyword_t sql_keywords[] = { {"0VUTN(", 'F'}, {"0VUTN1", 'F'}, {"0VUTNF", 'F'}, + {"0VUTNN", 'F'}, {"0VUTNS", 'F'}, + {"0VUTNV", 'F'}, {"0VUV,(", 'F'}, {"0VUV,F", 'F'}, {"0VUVC", 'F'}, @@ -8264,7 +8666,6 @@ static const keyword_t sql_keywords[] = { {"ABS", 'f'}, {"ACCESSIBLE", 'k'}, {"ACOS", 'f'}, - {"ADD", 'k'}, {"ADDDATE", 'f'}, {"ADDTIME", 'f'}, {"AES_DECRYPT", 'f'}, @@ -8310,6 +8711,10 @@ static const keyword_t sql_keywords[] = { {"AVG", 'f'}, {"BEFORE", 'k'}, {"BEGIN", 'T'}, + {"BEGIN DECLARE", 'T'}, + {"BEGIN GOTO", 'T'}, + {"BEGIN TRY", 'T'}, + {"BEGIN TRY DECLARE", 'T'}, {"BENCHMARK", 'f'}, {"BETWEEN", 'o'}, {"BIGINT", 't'}, @@ -8361,7 +8766,7 @@ static const keyword_t sql_keywords[] = { {"CHAR_LENGTH", 'f'}, {"CHDIR", 'f'}, {"CHDRIVE", 'f'}, - {"CHECK", 'k'}, + {"CHECK", 'n'}, {"CHECKSUM_AGG", 'f'}, {"CHOOSE", 'f'}, {"CHR", 'f'}, @@ -8544,6 +8949,8 @@ static const keyword_t sql_keywords[] = { {"FILEGROUP_NAME", 'f'}, {"FILELEN", 'f'}, {"FILEPROPERTY", 'f'}, + {"FILETOBLOB", 'f'}, + {"FILETOCLOB", 'f'}, {"FILE_ID", 'f'}, {"FILE_IDEX", 'f'}, {"FILE_NAME", 'f'}, @@ -8676,6 +9083,7 @@ static const keyword_t sql_keywords[] = { {"IS_USED_LOCK", 'f'}, {"ITERATE", 'k'}, {"JOIN", 'k'}, + {"JSON_KEYS", 'f'}, {"JULIANDAY", 'f'}, {"JUSTIFY_DAYS", 'f'}, {"JUSTIFY_HOURS", 'f'}, @@ -8694,7 +9102,7 @@ static const keyword_t sql_keywords[] = { {"LEADING", 'k'}, {"LEAST", 'f'}, {"LEAVE", 'k'}, - {"LEFT", 'n'}, + {"LEFT", 'f'}, {"LEFT JOIN", 'k'}, {"LEFT OUTER", 'k'}, {"LEFT OUTER JOIN", 'k'}, @@ -8818,7 +9226,7 @@ static const keyword_t sql_keywords[] = { {"ORDER BY", 'B'}, {"ORIGINAL_DB_NAME", 'f'}, {"ORIGINAL_LOGIN", 'f'}, - {"OUT", 'k'}, + {"OUT", 'n'}, {"OUTER", 'n'}, {"OUTFILE", 'k'}, {"OVERLAPS", 'f'}, @@ -9037,7 +9445,7 @@ static const keyword_t sql_keywords[] = { {"SYSTEM_USER", 'f'}, {"SYSUSERS", 'k'}, {"SYSUTCDATETME", 'f'}, - {"TABLE", 'k'}, + {"TABLE", 'n'}, {"TAN", 'f'}, {"TERMINATED", 'k'}, {"TERTIARY_WEIGHTS", 'f'}, @@ -9081,6 +9489,7 @@ static const keyword_t sql_keywords[] = { {"TRUE", '1'}, {"TRUNC", 'f'}, {"TRUNCATE", 'f'}, + {"TRY", 'T'}, {"TRY_CAST", 'f'}, {"TRY_CONVERT", 'f'}, {"TRY_PARSE", 'f'}, @@ -9217,5 +9626,5 @@ static const keyword_t sql_keywords[] = { {"||", '&'}, {"~*", 'o'}, }; -static const size_t sql_keywords_sz = 9049; +static const size_t sql_keywords_sz = 9330; #endif diff --git a/apache2/libinjection/libinjection_xss.c b/apache2/libinjection/libinjection_xss.c index 2807c22f08..e89b336ed9 100644 --- a/apache2/libinjection/libinjection_xss.c +++ b/apache2/libinjection/libinjection_xss.c @@ -6,13 +6,6 @@ #include <assert.h> #include <stdio.h> -#ifndef DEBUG -#include <stdio.h> -#define TRACE() printf("%s:%d\n", __FUNCTION__, __LINE__) -#else -#define TRACE() -#endif - typedef enum attribute { TYPE_NONE , TYPE_BLACK /* ban always */ @@ -37,109 +30,109 @@ typedef struct stringtype { static const int gsHexDecodeMap[256] = { - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, - 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256 + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, + 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256 }; static int html_decode_char_at(const char* src, size_t len, size_t* consumed) { - int val = 0; - size_t i; - int ch; - - if (len == 0 || src == NULL) { - *consumed = 0; - return -1; - } - - *consumed = 1; - if (*src != '&' || len < 2) { - return (unsigned char)(*src); - } - - - if (*(src+1) != '#') { - /* normally this would be for named entities - * but for this case we don't actually care - */ - return '&'; - } - - if (*(src+2) == 'x' || *(src+2) == 'X') { - ch = (unsigned char) (*(src+3)); - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - /* degenerate case '&#[?]' */ - return '&'; + int val = 0; + size_t i; + int ch; + + if (len == 0 || src == NULL) { + *consumed = 0; + return -1; } - val = ch; - i = 4; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - *consumed = i; - return val; - } - val = (val * 16) + ch; - if (val > 0x1000FF) { - return '&'; - } - ++i; + + *consumed = 1; + if (*src != '&' || len < 2) { + return (unsigned char)(*src); } - *consumed = i; - return val; - } else { - i = 2; - ch = (unsigned char) src[i]; - if (ch < '0' || ch > '9') { - return '&'; + + + if (*(src+1) != '#') { + /* normally this would be for named entities + * but for this case we don't actually care + */ + return '&'; } - val = ch - '0'; - i += 1; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - if (ch < '0' || ch > '9') { - *consumed = i; - return val; - } - val = (val * 10) + (ch - '0'); - if (val > 0x1000FF) { - return '&'; - } - ++i; + + if (*(src+2) == 'x' || *(src+2) == 'X') { + ch = (unsigned char) (*(src+3)); + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + /* degenerate case '&#[?]' */ + return '&'; + } + val = ch; + i = 4; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + *consumed = i; + return val; + } + val = (val * 16) + ch; + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } else { + i = 2; + ch = (unsigned char) src[i]; + if (ch < '0' || ch > '9') { + return '&'; + } + val = ch - '0'; + i += 1; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + if (ch < '0' || ch > '9') { + *consumed = i; + return val; + } + val = (val * 10) + (ch - '0'); + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; } - *consumed = i; - return val; - } } @@ -157,7 +150,7 @@ static stringtype_t BLACKATTR[] = { , { "DATASRC", TYPE_BLACK } /* IE */ , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */ - , { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */ + , { "FORMACTION", TYPE_ATTR_URL } /* HTML 5 */ , { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */ , { "FROM", TYPE_ATTR_URL } /* SVG */ , { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */ @@ -173,20 +166,20 @@ static stringtype_t BLACKATTR[] = { }; /* xmlns */ -/* xml-stylesheet > <eval>, <if expr=> */ +/* `xml-stylesheet` > <eval>, <if expr=> */ /* -static const char* BLACKATTR[] = { - "ATTRIBUTENAME", - "BACKGROUND", - "DATAFORMATAS", - "HREF", - "SCROLL", - "SRC", - "STYLE", - "SRCDOC", - NULL -}; + static const char* BLACKATTR[] = { + "ATTRIBUTENAME", + "BACKGROUND", + "DATAFORMATAS", + "HREF", + "SCROLL", + "SRC", + "STYLE", + "SRCDOC", + NULL + }; */ static const char* BLACKTAG[] = { @@ -220,36 +213,36 @@ static const char* BLACKTAG[] = { static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) { - char ca; - char cb; - /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ - while (n-- > 0) { - cb = *b++; - if (cb == '\0') continue; + char ca; + char cb; + /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ + while (n-- > 0) { + cb = *b++; + if (cb == '\0') continue; - ca = *a++; + ca = *a++; - if (cb >= 'a' && cb <= 'z') { - cb -= 0x20; - } - /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ - if (ca != cb) { - return 1; + if (cb >= 'a' && cb <= 'z') { + cb -= 0x20; + } + /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ + if (ca != cb) { + return 1; + } } - } - if (*a == 0) { - /* printf(" MATCH \n"); */ - return 0; - } else { - return 1; - } + if (*a == 0) { + /* printf(" MATCH \n"); */ + return 0; + } else { + return 1; + } } /* - * Does an HTML encoded binary string (const char*, lenght) start with - * a all uppercase c-string (null terminated), case insenstive! - * + * Does an HTML encoded binary string (const char*, length) start with + * a all uppercase c-string (null terminated), case insensitive! + * * also ignore any embedded nulls in the HTML string! * * return 1 if match / starts with @@ -257,47 +250,47 @@ static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) */ static int htmlencode_startswith(const char *a, const char *b, size_t n) { - size_t consumed; - int cb; - int first = 1; - /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ + size_t consumed; + int cb; + int first = 1; + /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ while (n > 0) { - if (*a == 0) { - /* printf("Match EOL!\n"); */ - return 1; - } - cb = html_decode_char_at(b, n, &consumed); - b += consumed; - n -= consumed; - - if (first && cb <= 32) { - /* ignore all leading whitespace and control characters */ - continue; - } - first = 0; + if (*a == 0) { + /* printf("Match EOL!\n"); */ + return 1; + } + cb = html_decode_char_at(b, n, &consumed); + b += consumed; + n -= consumed; + + if (first && cb <= 32) { + /* ignore all leading whitespace and control characters */ + continue; + } + first = 0; if (cb == 0) { - /* always ignore null characters in user input */ - continue; - } + /* always ignore null characters in user input */ + continue; + } if (cb == 10) { - /* always ignore vtab characters in user input */ - /* who allows this?? */ - continue; - } + /* always ignore vertical tab characters in user input */ + /* who allows this?? */ + continue; + } if (cb >= 'a' && cb <= 'z') { - /* upcase */ + /* upcase */ cb -= 0x20; } if (*a != (char) cb) { - /* printf(" %c != %c\n", *a, cb); */ - /* mismatch */ - return 0; + /* printf(" %c != %c\n", *a, cb); */ + /* mismatch */ + return 0; } - a++; + a++; } return (*a == 0) ? 1 : 0; @@ -313,8 +306,8 @@ static int is_black_tag(const char* s, size_t len) black = BLACKTAG; while (*black != NULL) { - if (cstrcasecmp_with_null(*black, s, len) == 0) { - /* printf("Got black tag %s\n", *black); */ + if (cstrcasecmp_with_null(*black, s, len) == 0) { + /* printf("Got black tag %s\n", *black); */ return 1; } black += 1; @@ -324,7 +317,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'v' || s[1] == 'V') && (s[2] == 'g' || s[2] == 'G')) { - /* printf("Got SVG tag \n"); */ + /* printf("Got SVG tag \n"); */ return 1; } @@ -332,7 +325,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 'x' || s[0] == 'X') && (s[1] == 's' || s[1] == 'S') && (s[2] == 'l' || s[2] == 'L')) { - /* printf("Got XSL tag\n"); */ + /* printf("Got XSL tag\n"); */ return 1; } @@ -347,9 +340,9 @@ static attribute_t is_black_attr(const char* s, size_t len) return TYPE_NONE; } - /* javascript on.* */ + /* JavaScript on.* */ if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { - /* printf("Got javascript on- attribute name\n"); */ + /* printf("Got JavaScript on- attribute name\n"); */ return TYPE_BLACK; } @@ -357,7 +350,7 @@ static attribute_t is_black_attr(const char* s, size_t len) if (len >= 5) { /* XMLNS can be used to create arbitrary tags */ if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) { - /* printf("Got XMLNS and XLINK tags\n"); */ + /* printf("Got XMLNS and XLINK tags\n"); */ return TYPE_BLACK; } } @@ -365,7 +358,7 @@ static attribute_t is_black_attr(const char* s, size_t len) black = BLACKATTR; while (black->name != NULL) { if (cstrcasecmp_with_null(black->name, s, len) == 0) { - /* printf("Got banned attribute name %s\n", black->name); */ + /* printf("Got banned attribute name %s\n", black->name); */ return black->atype; } black += 1; @@ -387,20 +380,18 @@ static int is_black_url(const char* s, size_t len) static const char* javascript_url = "JAVA"; /* skip whitespace */ - while (len > 0) { + while (len > 0 && (*s <= 32 || *s >= 127)) { /* * HEY: this is a signed character. * We are intentionally skipping high-bit characters too - * since they are not ascii, and Opera sometimes uses UTF8 whitespace + * since they are not ASCII, and Opera sometimes uses UTF-8 whitespace. + * + * Also in EUC-JP some of the high bytes are just ignored. */ - if (*s <= 32) { - ++s; - --len; - } - break; + ++s; + --len; } - if (htmlencode_startswith(data_url, s, len)) { return 1; } @@ -442,16 +433,16 @@ int libinjection_is_xss(const char* s, size_t len, int flags) /* * IE6,7,8 parsing works a bit differently so * a whole <script> or other black tag might be hiding - * inside an attribute value under HTML5 parsing + * inside an attribute value under HTML 5 parsing * See http://html5sec.org/#102 * to avoid doing a full reparse of the value, just * look for "<". This probably need adjusting to * handle escaped characters */ /* - if (memchr(h5.token_start, '<', h5.token_len) != NULL) { - return 1; - } + if (memchr(h5.token_start, '<', h5.token_len) != NULL) { + return 1; + } */ switch (attr) { @@ -473,13 +464,13 @@ int libinjection_is_xss(const char* s, size_t len, int flags) } break; /* - default: - assert(0); + default: + assert(0); */ } attr = TYPE_NONE; } else if (h5.token_type == TAG_COMMENT) { - /* IE uses a "`" as a tag ending char */ + /* IE uses a "`" as a tag ending char */ if (memchr(h5.token_start, '`', h5.token_len) != NULL) { return 1; } @@ -491,7 +482,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags) (h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) { return 1; } - if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') && + if ((h5.token_start[0] == 'x' || h5.token_start[0] == 'X') && (h5.token_start[1] == 'm' || h5.token_start[1] == 'M') && (h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) { return 1; @@ -499,7 +490,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags) } if (h5.token_len > 5) { - /* IE <?import pseudo-tag */ + /* IE <?import pseudo-tag */ if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) { return 1; } @@ -519,22 +510,22 @@ int libinjection_is_xss(const char* s, size_t len, int flags) * wrapper */ int libinjection_xss(const char* s, size_t len) -{ - if (libinjection_is_xss(s, len, DATA_STATE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) { - return 1; - } - - return 0; +{ + if (libinjection_is_xss(s, len, DATA_STATE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) { + return 1; + } + + return 0; } From d7383c39dd46cf5b5682e487eed1a3c48da8532d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 2 May 2017 11:09:10 -0300 Subject: [PATCH 099/477] Option to disable logging of dechunking --- CHANGES | 2 ++ apache2/msc_logging.c | 6 ++++++ configure.ac | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index b1a148e92d..4e47d3df9e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-dechunk-logging: Option to disable logging of + dechunking in audit log when log level < 9. * Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4 [ModSecurity team] * {dis|en}able-handler-logging: Option to disable logging of Apache handler diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 39fcdd719b..ac4f3d49f2 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1170,6 +1170,9 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ /* ENH Add info when request body was decompressed, dechunked too. */ +#ifdef LOG_NO_DECHUNK + if (msr->txcfg->debuglog_level >= 9) +#endif if (wrote_response_body) { yajl_kv_bool(g, "response_body_dechunked", 1); } @@ -2002,6 +2005,9 @@ void sec_audit_logger_native(modsec_rec *msr) { /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ /* ENH Add info when request body was decompressed, dechunked too. */ +#ifdef LOG_NO_DECHUNK + if (msr->txcfg->debuglog_level >= 9) +#endif if (wrote_response_body) { text = apr_psprintf(msr->mp, "Response-Body-Transformed: Dechunked\n"); sec_auditlog_write(msr, text, strlen(text)); diff --git a/configure.ac b/configure.ac index fb0fa5d9f6..4b1656a5a7 100644 --- a/configure.ac +++ b/configure.ac @@ -487,6 +487,21 @@ AC_ARG_ENABLE(handler-logging, log_handler='' ]) +# Disable logging of dechunking +AC_ARG_ENABLE(dechunk-logging, + AS_HELP_STRING([--enable-dechunk-logging], + [Enable logging of dechunking in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_dechunk= + else + log_dechunk="-DLOG_NO_DECHUNK" + fi +], +[ + log_dechunk='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -737,7 +752,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 41ae8db5715a14807328082c31d126acd11d9f79 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 2 May 2017 11:11:47 -0300 Subject: [PATCH 100/477] Fix configure help added in #1403 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4b1656a5a7..e9976b0d70 100644 --- a/configure.ac +++ b/configure.ac @@ -490,7 +490,7 @@ AC_ARG_ENABLE(handler-logging, # Disable logging of dechunking AC_ARG_ENABLE(dechunk-logging, AS_HELP_STRING([--enable-dechunk-logging], - [Enable logging of dechunking in audit log when log level < 9. This is the default]), + [Enable logging of dechunking even when log level is < 9. This is the default]), [ if test "$enableval" != "no"; then log_dechunk= From 7246998f099bb6b8b3815c27c55237f5071ec5aa Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 2 May 2017 17:11:11 -0300 Subject: [PATCH 101/477] Adds option to disable logging of stopwatches in audit log. --- CHANGES | 3 +++ apache2/msc_logging.c | 9 +++++++++ configure.ac | 17 ++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4e47d3df9e..9cfc64a166 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-stopwatch-logging: Option to disable logging of stopwatches + in audit log. + [Issue #1067 - Marc Stern] * {dis|en}able-dechunk-logging: Option to disable logging of dechunking in audit log when log level < 9. * Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4 diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index ac4f3d49f2..d90bc59abe 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1165,6 +1165,9 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Stopwatch2 */ +#ifdef DLOG_NO_STOPWATCH + if (msr->txcfg->debuglog_level >= 9) +#endif format_performance_variables_json(msr, g); /* Our response body does not contain chunks */ @@ -1989,6 +1992,9 @@ void sec_audit_logger_native(modsec_rec *msr) { } /* Stopwatch; left in for compatibility reasons */ +#ifdef DLOG_NO_STOPWATCH + if (msr->txcfg->debuglog_level >= 9) { +#endif text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", msr->request_time, (now - msr->request_time)); sec_auditlog_write(msr, text, strlen(text)); @@ -2001,6 +2007,9 @@ void sec_audit_logger_native(modsec_rec *msr) { "; %s\n", msr->request_time, (now - msr->request_time), perf_all); sec_auditlog_write(msr, text, strlen(text)); } +#ifdef DLOG_NO_STOPWATCH + } +#endif /* Our response body does not contain chunks */ /* ENH Only write this when the output was chunked. */ diff --git a/configure.ac b/configure.ac index e9976b0d70..abb0650138 100644 --- a/configure.ac +++ b/configure.ac @@ -502,6 +502,21 @@ AC_ARG_ENABLE(dechunk-logging, log_dechunk='' ]) +# Disable logging of stopwatches +AC_ARG_ENABLE(stopwatch-logging, + AS_HELP_STRING([--enable-stopwatch-logging], + [Enable logging of stopwatches in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_stopwatch= + else + log_stopwatch="-DLOG_NO_STOPWATCH" + fi +], +[ + log_stopwatch='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -752,7 +767,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 3e9e4b39cc7385db2ac98700c0a73697a3b36d55 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 2 May 2017 17:13:46 -0300 Subject: [PATCH 102/477] Cosmetics changes top of #1402 --- apache2/msc_logging.c | 4 ++-- configure.ac | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index d90bc59abe..81c85c3c7c 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1993,7 +1993,7 @@ void sec_audit_logger_native(modsec_rec *msr) { /* Stopwatch; left in for compatibility reasons */ #ifdef DLOG_NO_STOPWATCH - if (msr->txcfg->debuglog_level >= 9) { + if (msr->txcfg->debuglog_level >= 9) { #endif text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", msr->request_time, (now - msr->request_time)); @@ -2008,7 +2008,7 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write(msr, text, strlen(text)); } #ifdef DLOG_NO_STOPWATCH - } + } #endif /* Our response body does not contain chunks */ diff --git a/configure.ac b/configure.ac index abb0650138..4e7ffa5d89 100644 --- a/configure.ac +++ b/configure.ac @@ -505,7 +505,7 @@ AC_ARG_ENABLE(dechunk-logging, # Disable logging of stopwatches AC_ARG_ENABLE(stopwatch-logging, AS_HELP_STRING([--enable-stopwatch-logging], - [Enable logging of stopwatches in audit log when log level < 9. This is the default]), + [Enable logging of stopwatches even when log level is < 9. This is the default]), [ if test "$enableval" != "no"; then log_stopwatch= From 7f647e85ad343db2423b35836a7acae322b2eaa2 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 2 May 2017 21:45:42 -0300 Subject: [PATCH 103/477] Adds missing $log_handler in MODSEC_EXTRA_CFLAGS --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4e7ffa5d89..f4620f983c 100644 --- a/configure.ac +++ b/configure.ac @@ -767,7 +767,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 51f312736ab7e79d0ad66da97bb5cf6f1d0bdda1 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 27 Apr 2017 17:58:43 +0200 Subject: [PATCH 104/477] rule id is not logged in case rule has no msg --- apache2/re.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 46def9e4d5..51a4fea59a 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1889,11 +1889,12 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - if (rule->actionset != NULL && rule->actionset->msg != NULL) { - msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", rule->actionset->id, rule->actionset->msg); - } else { - msr_log(msr, 1, "Rule processing failed."); - } + const char *id = "", *msg = ""; + if (rule->actionset) { + if (rule->actionset->id) id = rule->actionset->id; + if (rule->actionset->msg) msg = rule->actionset->msg; + } + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); if (msr->txcfg->reqintercept_oe == 1) { apr_table_clear(msr->matched_vars); @@ -1923,11 +1924,12 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - if (rule->actionset != NULL && rule->actionset->msg != NULL) { - msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, rule->actionset->id, rule->actionset->msg); - } else { - msr_log(msr, 1, "Rule processing failed with unknown return code: %d", rc); - } + const char *id = "", *msg = ""; + if (rule->actionset) { + if (rule->actionset->id) id = rule->actionset->id; + if (rule->actionset->msg) msg = rule->actionset->msg; + } + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); apr_table_clear(msr->matched_vars); return -1; } From caadf97524a4861456be176a8cb91dcbb76b97e4 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 3 May 2017 09:33:35 -0300 Subject: [PATCH 105/477] Cosmetics: Fix 0x0bdda1 indentation issues --- apache2/re.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 51a4fea59a..83f4d59aae 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1889,12 +1889,17 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - const char *id = "", *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) id = rule->actionset->id; - if (rule->actionset->msg) msg = rule->actionset->msg; - } - msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); + const char *id = ""; + const char *msg = ""; + if (rule->actionset) { + if (rule->actionset->id) { + id = rule->actionset->id; + } + if (rule->actionset->msg) { + msg = rule->actionset->msg; + } + } + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); if (msr->txcfg->reqintercept_oe == 1) { apr_table_clear(msr->matched_vars); @@ -1924,12 +1929,17 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - const char *id = "", *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) id = rule->actionset->id; - if (rule->actionset->msg) msg = rule->actionset->msg; - } - msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); + const char *id = ""; + const char *msg = ""; + if (rule->actionset) { + if (rule->actionset->id) { + id = rule->actionset->id; + } + if (rule->actionset->msg) { + msg = rule->actionset->msg; + } + } + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); apr_table_clear(msr->matched_vars); return -1; } From f813365f7e02ab0a0c326e1f1ae039f8e0019c5d Mon Sep 17 00:00:00 2001 From: Sander Hoentjen <shoentjen@antagonist.nl> Date: Fri, 3 Mar 2017 08:52:38 +0100 Subject: [PATCH 106/477] Fix logging for Apache 2.4 --- apache2/mod_security2.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 93c2fbe492..7da0601935 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -25,6 +25,10 @@ #include "apr_optional.h" #include "mod_log_config.h" +#ifdef APLOG_USE_MODULE +APLOG_USE_MODULE(security2); +#endif + #include "msc_logging.h" #include "msc_util.h" @@ -1451,6 +1455,9 @@ static int hook_connection_early(conn_rec *conn) apr_cpystrn(ws_record->client, client_ip, sizeof(ws_record->client)); + ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, conn, + "ModSecurity: going to loop through %d servers with %d threads", + server_limit, thread_limit); for (i = 0; i < server_limit; ++i) { for (j = 0; j < thread_limit; ++j) { @@ -1485,6 +1492,10 @@ static int hook_connection_early(conn_rec *conn) } } + ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, conn, + "ModSecurity: threads in READ: %ld of %ld, WRITE: %ld of %ld, IP: %s", + ip_count_r, conn_read_state_limit, ip_count_w, conn_write_state_limit, client_ip); + if (conn_read_state_limit > 0 && ip_count_r > conn_read_state_limit) { if (conn_read_state_suspicious_list && @@ -1492,7 +1503,7 @@ static int hook_connection_early(conn_rec *conn) conn_read_state_suspicious_list, client_ip, NULL, &error_msg) <= 0)) { if (conn_limits_filter_state == MODSEC_DETECTION_ONLY) - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Too many threads [%ld] of %ld allowed " \ "in READ state from %s - There is a suspission list " \ "but that IP is not part of it, access granted", @@ -1502,7 +1513,7 @@ static int hook_connection_early(conn_rec *conn) conn_read_state_whitelist, client_ip, NULL, &error_msg) > 0) { if (conn_limits_filter_state == MODSEC_DETECTION_ONLY) - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Too many threads [%ld] of %ld allowed " \ "in READ state from %s - Ip is on whitelist, access " \ "granted", ip_count_r, conn_read_state_limit, @@ -1510,7 +1521,7 @@ static int hook_connection_early(conn_rec *conn) } else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Access denied with code 400. Too many " \ "threads [%ld] of %ld allowed in READ state from %s - " \ "Possible DoS Consumption Attack [Rejected]", ip_count_r, @@ -1528,7 +1539,7 @@ static int hook_connection_early(conn_rec *conn) conn_write_state_suspicious_list, client_ip, NULL, &error_msg) <= 0)) { if (conn_limits_filter_state == MODSEC_DETECTION_ONLY) - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Too many threads [%ld] of %ld allowed " \ "in WRITE state from %s - There is a suspission list " \ "but that IP is not part of it, access granted", @@ -1538,7 +1549,7 @@ static int hook_connection_early(conn_rec *conn) conn_write_state_whitelist, client_ip, NULL, &error_msg) > 0) { if (conn_limits_filter_state == MODSEC_DETECTION_ONLY) - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Too many threads [%ld] of %ld allowed " \ "in WRITE state from %s - Ip is on whitelist, " \ "access granted", ip_count_w, conn_read_state_limit, @@ -1546,7 +1557,7 @@ static int hook_connection_early(conn_rec *conn) } else { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: Access denied with code 400. Too many " \ "threads [%ld] of %ld allowed in WRITE state from %s - " \ "Possible DoS Consumption Attack [Rejected]", ip_count_w, From 8efece97f74799216c686d9c4f35e18279ea5c0c Mon Sep 17 00:00:00 2001 From: Sander Hoentjen <shoentjen@antagonist.nl> Date: Fri, 3 Mar 2017 09:44:48 +0100 Subject: [PATCH 107/477] don't use sb_handle on apache 2.4 --- apache2/mod_security2.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 7da0601935..ebaa6680b9 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -96,11 +96,6 @@ int (*modsecDropAction)(request_rec *r) = NULL; #endif static int server_limit, thread_limit; -typedef struct { - int child_num; - int thread_num; -} sb_handle; - /* -- Miscellaneous functions -- */ /** @@ -1435,21 +1430,25 @@ static void modsec_register_operator(const char *name, void *fn_init, void *fn_e */ static int hook_connection_early(conn_rec *conn) { - sb_handle *sb = conn->sbh; - int i, j; - unsigned long int ip_count_r = 0, ip_count_w = 0; - char *error_msg; - worker_score *ws_record = NULL; #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - ap_sb_handle_t *sbh = NULL; + ap_sb_handle_t *sbh = conn->sbh; char *client_ip = conn->client_ip; #else + sb_handle *sbh = conn->sbh; char *client_ip = conn->remote_ip; #endif + int i, j; + unsigned long int ip_count_r = 0, ip_count_w = 0; + char *error_msg; + worker_score *ws_record = NULL; - if (sb != NULL && (conn_read_state_limit > 0 || conn_write_state_limit > 0)) { + if (sbh != NULL && (conn_read_state_limit > 0 || conn_write_state_limit > 0)) { - ws_record = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num]; +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 + ws_record = ap_get_scoreboard_worker(sbh); +#else + ws_record = ap_get_scoreboard_worker(sbh->child_num, sbh->thread_num); +#endif if (ws_record == NULL) return DECLINED; @@ -1462,11 +1461,6 @@ static int hook_connection_early(conn_rec *conn) for (j = 0; j < thread_limit; ++j) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - sbh = conn->sbh; - if (sbh == NULL) { - return DECLINED; - } - ws_record = ap_get_scoreboard_worker(sbh); #else ws_record = ap_get_scoreboard_worker(i, j); From 53edb258bb0e2cee6402a6c5d04622de6be7a3d3 Mon Sep 17 00:00:00 2001 From: Sander Hoentjen <shoentjen@antagonist.nl> Date: Fri, 3 Mar 2017 09:51:04 +0100 Subject: [PATCH 108/477] get correct worker_score in loop --- apache2/mod_security2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index ebaa6680b9..9c69c5dfad 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1461,7 +1461,7 @@ static int hook_connection_early(conn_rec *conn) for (j = 0; j < thread_limit; ++j) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - ws_record = ap_get_scoreboard_worker(sbh); + ws_record = ap_get_scoreboard_worker_from_indexes(i, j); #else ws_record = ap_get_scoreboard_worker(i, j); #endif From a2eb4c8b048e81d87daba93f3ed077e2b75d31e2 Mon Sep 17 00:00:00 2001 From: Sander Hoentjen <shoentjen@antagonist.nl> Date: Fri, 3 Mar 2017 09:52:07 +0100 Subject: [PATCH 109/477] Don't update the scoreboard ourself (fixes #1337) This is unsafe, and messes up the scoreboard on Apache >= 2.4.25 with Event MPM --- apache2/mod_security2.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 9c69c5dfad..f813cf0f77 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1452,7 +1452,19 @@ static int hook_connection_early(conn_rec *conn) if (ws_record == NULL) return DECLINED; - apr_cpystrn(ws_record->client, client_ip, sizeof(ws_record->client)); + /* If ws_record does not have correct ip yet, we count it already */ + if (strcmp(client_ip, ws_record->client) != 0) { + switch (ws_record->status) { + case SERVER_BUSY_READ: + ip_count_r++; + break; + case SERVER_BUSY_WRITE: + ip_count_w++; + break; + default: + break; + } + } ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, conn, "ModSecurity: going to loop through %d servers with %d threads", From 0f59d4e044cd2256ed7b6ea1f40114c09768d64b Mon Sep 17 00:00:00 2001 From: Sander Hoentjen <shoentjen@antagonist.nl> Date: Fri, 3 Mar 2017 09:54:05 +0100 Subject: [PATCH 110/477] query MPM after all config is loaded (fixes #786) --- apache2/mod_security2.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index f813cf0f77..c6da606021 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -690,6 +690,11 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t change_server_signature(s); } + /* For connection level hook */ + ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); + ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); + + #if (!(defined(WIN32) || defined(NETWARE))) /* Internal chroot functionality */ @@ -1672,10 +1677,6 @@ static void register_hooks(apr_pool_t *mp) { APR_REGISTER_OPTIONAL_FN(modsec_register_reqbody_processor); #endif - /* For connection level hook */ - ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); - ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); - /* Main hooks */ ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_FIRST); ap_hook_post_config(hook_post_config, postconfig_beforeme_list, From 7bdb79a1a2e2382abf519173f8e794caf7b29654 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 4 May 2017 10:29:51 -0300 Subject: [PATCH 111/477] Adds information about pull request #1340 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 9cfc64a166..e3b7c777d9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix SecConn(Read|Write)StateLimit on Apache 2.4 + [Issue #1340, #1337, #786 - Sander Hoentjen] * {dis|en}able-stopwatch-logging: Option to disable logging of stopwatches in audit log. [Issue #1067 - Marc Stern] From b6293988fe9ec5c9310bd5ecc6f545f09ca7b745 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 4 May 2017 13:25:31 -0300 Subject: [PATCH 112/477] Adds ap_log_cerror_ to the standalone implementation --- standalone/server.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/standalone/server.c b/standalone/server.c index 05b3bf3ac4..eec9b31da1 100644 --- a/standalone/server.c +++ b/standalone/server.c @@ -285,6 +285,33 @@ AP_DECLARE(void) ap_log_error_(const char *file, int line, int module_index, modsecLogHook(modsecLogObj, level, errstr); } + +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 +AP_DECLARE(void) ap_log_cerror(const char *file, int line, int level, + apr_status_t status, const conn_rec *r, + const char *fmt, ...) +// __attribute__((format(printf,6,7))) +#else +AP_DECLARE(void) ap_log_cerror_(const char *file, int line, int module_index, + int level, apr_status_t status, + const conn_rec *c, const char *fmt, ...) +// __attribute__((format(printf,7,8))) +#endif +{ + va_list args; + char errstr[MAX_STRING_LEN]; + + va_start(args, fmt); + + apr_vsnprintf(errstr, MAX_STRING_LEN, fmt, args); + + va_end(args); + + if(modsecLogHook != NULL) + modsecLogHook(modsecLogObj, level, errstr); +} + + #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3 AP_DECLARE(void) ap_log_rerror(const char *file, int line, int level, apr_status_t status, const request_rec *r, From 019edfa1a9bff0e3fca5dd7806b3ab7781e465c9 Mon Sep 17 00:00:00 2001 From: Barry Pollard <barry_pollard@hotmail.com> Date: Sat, 21 Jan 2017 17:10:54 +0000 Subject: [PATCH 113/477] This is a fix for #992 to allow drop to work with mod_http2 --- apache2/mod_security2.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index c6da606021..2ca9314366 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -265,8 +265,18 @@ int perform_interception(modsec_rec *msr) { #if !defined(WIN32) && !defined(VERSION_NGINX) { extern module core_module; - apr_socket_t *csd = ap_get_module_config(msr->r->connection->conn_config, - &core_module); + apr_socket_t *csd; + + /* For mod_http2 used by HTTP/2 there is a virtual connection so must go through + * master to get the main connection or the drop request doesn't seem to do anything. + * For HTTP/1.1 master will not be defined so just go through normal connection. + * More details here: https://github.com/icing/mod_h2/issues/127 + */ + if (msr->r->connection->master) { + csd = ap_get_module_config(msr->r->connection->master->conn_config, &core_module); + } else { + csd = ap_get_module_config(msr->r->connection->conn_config, &core_module); + } if (csd) { if (apr_socket_close(csd) == APR_SUCCESS) { From 9b3c32bb54935b232b0a3bbf14625b8409b926d7 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 4 May 2017 22:43:38 -0300 Subject: [PATCH 114/477] Makes #1308 compatible to older versions of Apache --- apache2/mod_security2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 2ca9314366..9f4f968723 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -267,6 +267,7 @@ int perform_interception(modsec_rec *msr) { extern module core_module; apr_socket_t *csd; +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 && AP_SERVER_PATCHLEVEL_NUMBER > 17 /* For mod_http2 used by HTTP/2 there is a virtual connection so must go through * master to get the main connection or the drop request doesn't seem to do anything. * For HTTP/1.1 master will not be defined so just go through normal connection. @@ -277,7 +278,9 @@ int perform_interception(modsec_rec *msr) { } else { csd = ap_get_module_config(msr->r->connection->conn_config, &core_module); } - +#else + csd = ap_get_module_config(msr->r->connection->conn_config, &core_module); +#endif if (csd) { if (apr_socket_close(csd) == APR_SUCCESS) { status = HTTP_FORBIDDEN; From aa1a56f23fa22ae0f7ee74a1eb33702c16ef644f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 4 May 2017 23:51:27 -0300 Subject: [PATCH 115/477] Adds information about pull request #1308 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index e3b7c777d9..9398f2f9a0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Allow drop to work with mod_http2 + [Issue #1308, #992 - @bazzadp] * Fix SecConn(Read|Write)StateLimit on Apache 2.4 [Issue #1340, #1337, #786 - Sander Hoentjen] * {dis|en}able-stopwatch-logging: Option to disable logging of stopwatches From da995bb636eab4b0a0e51df53605dd56e3c8c1b5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 5 May 2017 07:13:16 -0300 Subject: [PATCH 116/477] Adds sb_handle structure to specific versions of apache Fix issue #1407 --- apache2/mod_security2.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 9f4f968723..f4db2ac835 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -25,9 +25,11 @@ #include "apr_optional.h" #include "mod_log_config.h" -#ifdef APLOG_USE_MODULE -APLOG_USE_MODULE(security2); -#endif +/* + * #ifdef APLOG_USE_MODULE + * APLOG_USE_MODULE(security2); + * #endif + */ #include "msc_logging.h" #include "msc_util.h" @@ -1437,6 +1439,14 @@ static void modsec_register_operator(const char *name, void *fn_init, void *fn_e } } +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 +#else +typedef struct { + int child_num; + int thread_num; +} sb_handle; +#endif + /** * \brief Connetion hook to limit the number of * connections in BUSY state @@ -1484,7 +1494,7 @@ static int hook_connection_early(conn_rec *conn) } } - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, conn, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: going to loop through %d servers with %d threads", server_limit, thread_limit); for (i = 0; i < server_limit; ++i) { @@ -1516,7 +1526,7 @@ static int hook_connection_early(conn_rec *conn) } } - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, conn, + ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, "ModSecurity: threads in READ: %ld of %ld, WRITE: %ld of %ld, IP: %s", ip_count_r, conn_read_state_limit, ip_count_w, conn_write_state_limit, client_ip); From 70322304f289645ca4e4dc95fc5adc310275e7d6 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 8 May 2017 15:36:58 -0300 Subject: [PATCH 117/477] {dis|en}able-server-context-logging: Option to disable logging of server info (log producer, sanitized objects, ...) in audit log. --- CHANGES | 3 +++ apache2/msc_logging.c | 14 +++++++++++++- configure.ac | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 9398f2f9a0..49be2a589f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * {dis|en}able-server-context-logging: Option to disable logging of + server info (log producer, sanitized objects, ...) in audit log. + [Issue #1069 - Marc Stern] * Allow drop to work with mod_http2 [Issue #1308, #992 - @bazzadp] * Fix SecConn(Read|Write)StateLimit on Apache 2.4 diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 81c85c3c7c..6b7ab27bf3 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1180,6 +1180,9 @@ void sec_audit_logger_json(modsec_rec *msr) { yajl_kv_bool(g, "response_body_dechunked", 1); } +#ifdef LOG_NO_SERVER_CONTEXT + if (msr->txcfg->debuglog_level >= 9) { +#endif sec_auditlog_write_producer_header_json(msr, g); /* Server */ @@ -1274,6 +1277,9 @@ void sec_audit_logger_json(modsec_rec *msr) { if (been_opened == 1) { yajl_gen_map_close(g); // sanitized args map is finished } +#ifdef LOG_NO_SERVER_CONTEXT + } +#endif /* Web application info. */ if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) @@ -2022,6 +2028,9 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write(msr, text, strlen(text)); } +#ifdef LOG_NO_SERVER_CONTEXT + if (msr->txcfg->debuglog_level >= 9) { +#endif sec_auditlog_write_producer_header(msr); /* Server */ @@ -2090,8 +2099,11 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write(msr, text, strlen(text)); } } +#ifdef LOG_NO_SERVER_CONTEXT + } +#endif - /* Web application info. */ + /* Web application info. */ if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) || (msr->sessionid != NULL) || (msr->userid != NULL)) { diff --git a/configure.ac b/configure.ac index f4620f983c..88d63565c7 100644 --- a/configure.ac +++ b/configure.ac @@ -517,6 +517,21 @@ AC_ARG_ENABLE(stopwatch-logging, log_stopwatch='' ]) +# Disable logging of server context +AC_ARG_ENABLE(server-context-logging, + AS_HELP_STRING([--enable-server-context-logging], + [Enable logging of server info (log producer, sanitized objects, ...) in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server_context= + else + log_server_context="-DLOG_NO_SERVER_CONTEXT" + fi +], +[ + log_server_context='' +]) + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -767,7 +782,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_contex" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From d6bd0badc5d66a6bdfd30125ca4cd90dd2539072 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 8 May 2017 16:01:37 -0300 Subject: [PATCH 118/477] Cosmetics: fix #1400 indentation and help message --- apache2/msc_logging.c | 6 +++--- configure.ac | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 6b7ab27bf3..c2274c7f57 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1278,7 +1278,7 @@ void sec_audit_logger_json(modsec_rec *msr) { yajl_gen_map_close(g); // sanitized args map is finished } #ifdef LOG_NO_SERVER_CONTEXT - } + } #endif /* Web application info. */ @@ -2100,10 +2100,10 @@ void sec_audit_logger_native(modsec_rec *msr) { } } #ifdef LOG_NO_SERVER_CONTEXT - } + } #endif - /* Web application info. */ + /* Web application info. */ if ( ((msr->txcfg->webappid != NULL)&&(strcmp(msr->txcfg->webappid, "default") != 0)) || (msr->sessionid != NULL) || (msr->userid != NULL)) { diff --git a/configure.ac b/configure.ac index 88d63565c7..7025f46026 100644 --- a/configure.ac +++ b/configure.ac @@ -520,7 +520,7 @@ AC_ARG_ENABLE(stopwatch-logging, # Disable logging of server context AC_ARG_ENABLE(server-context-logging, AS_HELP_STRING([--enable-server-context-logging], - [Enable logging of server info (log producer, sanitized objects, ...) in audit log when log level < 9. This is the default]), + [Enable logging of server info (log producer, sanitized objects, ...) in audit log even when log level < 9. This is the default]), [ if test "$enableval" != "no"; then log_server_context= From 10fb76ff16c693584cc703d5ef8d4340400a81b4 Mon Sep 17 00:00:00 2001 From: Coty Sutherland <csutherl@redhat.com> Date: Fri, 2 Dec 2016 15:22:48 -0500 Subject: [PATCH 119/477] Adding comments around odd looking code to prevent future scrutiny --- apache2/persist_dbm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 4e891cee84..175a5d0213 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -482,10 +482,12 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { } } + // Allocate blob_size for keys len = var->name_len + 1; if (len >= 65536) len = 65536; blob_size += len + 2; + // Allocate blob_size for values len = var->value_len + 1; if (len >= 65536) len = 65536; blob_size += len + 2; From cd4218bd403edbbf04475a9c4ccfc9c9a79f42a9 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 8 May 2017 21:09:51 -0300 Subject: [PATCH 120/477] Adds info about pull request #1279 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 49be2a589f..cd086eeeef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Cosmetics: added comments on odd looking code to prevent future + scrutiny + [Issue #1279 - Coty Sutherland] * {dis|en}able-server-context-logging: Option to disable logging of server info (log producer, sanitized objects, ...) in audit log. [Issue #1069 - Marc Stern] From 4f55b5d1a7ef203b1e918f6855d38072e0896672 Mon Sep 17 00:00:00 2001 From: Robert Bost <rbost@redhat.com> Date: Tue, 20 Dec 2016 17:55:13 -0500 Subject: [PATCH 121/477] Change from using rand() to thread-safe ap_random_pick. --- apache2/modsecurity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 5bda4cff82..7f6a7fb151 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -237,7 +237,7 @@ static void modsecurity_persist_data(modsec_rec *msr) { } /* Remove stale collections. */ - if (rand() < RAND_MAX/100) { + if (ap_random_pick(0, RAND_MAX) < RAND_MAX/100) { arr = apr_table_elts(msr->collections); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { From 4b5a6350afc8516a7cf702449ea180ece50585ed Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 8 May 2017 21:21:08 -0300 Subject: [PATCH 122/477] Adds info about pull request #1289 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index cd086eeeef..cf908dc386 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Change from using rand() to thread-safe ap_random_pick. + [Issue #1289 - Robert Bost] * Cosmetics: added comments on odd looking code to prevent future scrutiny [Issue #1279 - Coty Sutherland] From a5bbb8345f9bedb220c6a0682392a80734e352d0 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 10 May 2017 17:09:57 -0300 Subject: [PATCH 123/477] Fix compilation for 2.2.x and standalone after #1289 --- apache2/modsecurity.c | 4 ++++ standalone/server.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 7f6a7fb151..6652cdc1a6 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -237,7 +237,11 @@ static void modsecurity_persist_data(modsec_rec *msr) { } /* Remove stale collections. */ +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3 if (ap_random_pick(0, RAND_MAX) < RAND_MAX/100) { +#else + if (rand() < RAND_MAX/100) { +#endif arr = apr_table_elts(msr->collections); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { diff --git a/standalone/server.c b/standalone/server.c index eec9b31da1..31b12a6dbc 100644 --- a/standalone/server.c +++ b/standalone/server.c @@ -187,6 +187,11 @@ static char *http2env(apr_pool_t *a, const char *w) return res; } +AP_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max) +{ + return rand(); +} + AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc) { int i, j; From 63462668a9ffea0cdb07506bd1865fd066f41c1d Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Wed, 10 May 2017 20:11:04 -0500 Subject: [PATCH 124/477] Refactoring on the doxygen generation --- CHANGES | 2 + configure.ac | 15 +- doc/Makefile.am | 27 + ...{doxygen-apache.conf => doxygen-apache.in} | 541 +++++++++++------- doc/{doxygen-iis.conf => doxygen-iis.in} | 541 +++++++++++------- doc/{doxygen-nginx.conf => doxygen-nginx.in} | 541 +++++++++++------- ...-standalone.conf => doxygen-standalone.in} | 541 +++++++++++------- 7 files changed, 1359 insertions(+), 849 deletions(-) create mode 100644 doc/Makefile.am rename doc/{doxygen-apache.conf => doxygen-apache.in} (84%) rename doc/{doxygen-iis.conf => doxygen-iis.in} (84%) rename doc/{doxygen-nginx.conf => doxygen-nginx.in} (84%) rename doc/{doxygen-standalone.conf => doxygen-standalone.in} (84%) diff --git a/CHANGES b/CHANGES index cf908dc386..0fe5f6e74c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix --enable-docs adding missing Makefile, modifying autoconf and filenames + [Issue #1322 - @victorhora] * Change from using rand() to thread-safe ap_random_pick. [Issue #1289 - Robert Bost] * Cosmetics: added comments on odd looking code to prevent future diff --git a/configure.ac b/configure.ac index 7025f46026..d600edc4d8 100644 --- a/configure.ac +++ b/configure.ac @@ -288,7 +288,20 @@ AC_ARG_ENABLE(docs, ]) AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1]) if test "$build_docs" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS docs" + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS doc" + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + if test -z "$DOXYGEN"; then + AC_MSG_WARN([Doxygen not found - continue without Doxygen support]) + fi + if test "$build_apache2_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-apache]) + fi + if test "$build_standalone_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-nginx]) + AC_CONFIG_FILES([doc/doxygen-iis]) + AC_CONFIG_FILES([doc/doxygen-standalone]) + fi + AC_CONFIG_FILES([doc/Makefile]) fi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000000..4f4eaffb1e --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,27 @@ +apache: + $(DOXYGEN) doxygen-apache + touch apache.stamp + +iis: + $(DOXYGEN) doxygen-iis + touch iis.stamp + +nginx: + $(DOXYGEN) doxygen-nginx + touch nginx.stamp + +standalone: + $(DOXYGEN) doxygen-standalone + touch standalone.stamp + + +if BUILD_APACHE2_MODULE +all-local: apache +endif + +if BUILD_STANDALONE_MODULE +all-local: iis nginx standalone +endif + +clean-local: + rm -rf apache iis nginx standalone diff --git a/doc/doxygen-apache.conf b/doc/doxygen-apache.in similarity index 84% rename from doc/doxygen-apache.conf rename to doc/doxygen-apache.in index b59b47b390..b031ade5d3 100644 --- a/doc/doxygen-apache.conf +++ b/doc/doxygen-apache.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -38,7 +38,7 @@ PROJECT_NAME = "ModSecurity (Apache)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -46,21 +46,21 @@ PROJECT_NUMBER = PROJECT_BRIEF = "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis. With over 10,000 deployments world-wide, ModSecurity is the most widely deployed WAF in existence." -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. -PROJECT_LOGO = ./doc/doxygen-logo.png +PROJECT_LOGO = ./doxygen-logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc/apache +OUTPUT_DIRECTORY = apache -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = doc/apache CREATE_SUBDIRS = YES +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. @@ -85,14 +93,14 @@ CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -110,7 +118,7 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -153,7 +161,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -220,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -261,16 +269,19 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -282,10 +293,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -325,13 +345,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -390,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -400,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -453,21 +480,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -481,7 +508,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. @@ -490,12 +517,19 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -523,14 +557,14 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -575,27 +609,25 @@ SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -606,7 +638,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -620,8 +652,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -648,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -661,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -669,10 +701,9 @@ LAYOUT_FILE = # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -686,7 +717,7 @@ CITE_BIB_FILES = QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -694,7 +725,7 @@ QUIET = NO WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -711,12 +742,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -731,7 +768,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -740,10 +777,10 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = apache2 +INPUT = ../apache2 # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -756,14 +793,19 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -778,7 +820,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -794,7 +836,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -805,20 +847,20 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -831,7 +873,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -847,8 +889,12 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -856,11 +902,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -872,14 +922,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -920,7 +970,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -991,13 +1041,13 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1035,7 +1085,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1045,7 +1095,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1057,18 +1107,20 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1078,10 +1130,10 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1112,8 +1164,9 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES @@ -1206,31 +1259,32 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1257,7 +1311,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1282,7 +1336,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1290,21 +1344,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1343,7 +1397,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1371,7 +1425,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1400,7 +1454,7 @@ FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1437,7 +1491,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1445,7 +1499,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1470,11 +1524,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1486,7 +1540,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1499,13 +1553,13 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1521,7 +1575,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1531,13 +1585,13 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = YES @@ -1568,7 +1622,7 @@ LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1586,13 +1640,16 @@ COMPACT_LATEX = NO PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1602,22 +1659,35 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1625,7 +1695,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1636,8 +1706,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1678,11 +1748,19 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1697,7 +1775,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1725,20 +1803,30 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1762,6 +1850,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1775,7 +1870,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1789,19 +1884,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1814,7 +1897,7 @@ XML_PROGRAMLISTING = YES # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1828,14 +1911,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1844,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1852,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1860,9 +1952,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1876,20 +1968,20 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1905,7 +1997,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1917,7 +2009,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = "apache2" +INCLUDE_PATH = "../apache2" # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1925,7 +2017,7 @@ INCLUDE_PATH = "apache2" # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1935,7 +2027,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1944,12 +2036,12 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1969,32 +2061,33 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2011,7 +2104,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2027,16 +2120,16 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2049,7 +2142,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = YES +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2061,7 +2154,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2083,7 +2176,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2109,7 +2202,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2161,7 +2254,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2172,7 +2266,8 @@ CALL_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2195,11 +2290,15 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2221,26 +2320,44 @@ INTERACTIVE_SVG = YES # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2278,7 +2395,7 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2295,7 +2412,7 @@ DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/doc/doxygen-iis.conf b/doc/doxygen-iis.in similarity index 84% rename from doc/doxygen-iis.conf rename to doc/doxygen-iis.in index 5a6d9d3661..9b0d5d83ff 100644 --- a/doc/doxygen-iis.conf +++ b/doc/doxygen-iis.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -38,7 +38,7 @@ PROJECT_NAME = "ModSecurity (IIS)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -46,21 +46,21 @@ PROJECT_NUMBER = PROJECT_BRIEF = "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis. With over 10,000 deployments world-wide, ModSecurity is the most widely deployed WAF in existence." -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. -PROJECT_LOGO = ./doc/doxygen-logo.png +PROJECT_LOGO = ./doxygen-logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc/iis +OUTPUT_DIRECTORY = iis -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = doc/iis CREATE_SUBDIRS = YES +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. @@ -85,14 +93,14 @@ CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -110,7 +118,7 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -153,7 +161,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -220,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -261,16 +269,19 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -282,10 +293,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -325,13 +345,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -390,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -400,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -453,21 +480,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -481,7 +508,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. @@ -490,12 +517,19 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -523,14 +557,14 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -575,27 +609,25 @@ SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -606,7 +638,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -620,8 +652,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -648,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -661,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -669,10 +701,9 @@ LAYOUT_FILE = # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -686,7 +717,7 @@ CITE_BIB_FILES = QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -694,7 +725,7 @@ QUIET = NO WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -711,12 +742,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -731,7 +768,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -740,10 +777,10 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = iis +INPUT = ../iis # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -756,14 +793,19 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -778,7 +820,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -794,7 +836,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -805,20 +847,20 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -831,7 +873,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -847,8 +889,12 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -856,11 +902,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -872,14 +922,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -920,7 +970,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -991,13 +1041,13 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1035,7 +1085,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1045,7 +1095,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1057,18 +1107,20 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1078,10 +1130,10 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1112,8 +1164,9 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES @@ -1206,31 +1259,32 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1257,7 +1311,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1282,7 +1336,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1290,21 +1344,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1343,7 +1397,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1371,7 +1425,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1400,7 +1454,7 @@ FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1437,7 +1491,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1445,7 +1499,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1470,11 +1524,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1486,7 +1540,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1499,13 +1553,13 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1521,7 +1575,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1531,13 +1585,13 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = YES @@ -1568,7 +1622,7 @@ LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1586,13 +1640,16 @@ COMPACT_LATEX = NO PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1602,22 +1659,35 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1625,7 +1695,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1636,8 +1706,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1678,11 +1748,19 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1697,7 +1775,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1725,20 +1803,30 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1762,6 +1850,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1775,7 +1870,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1789,19 +1884,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1814,7 +1897,7 @@ XML_PROGRAMLISTING = YES # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1828,14 +1911,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1844,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1852,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1860,9 +1952,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1876,20 +1968,20 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1905,7 +1997,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1917,7 +2009,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = "apache2" +INCLUDE_PATH = "../apache2" # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1925,7 +2017,7 @@ INCLUDE_PATH = "apache2" # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1935,7 +2027,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1944,12 +2036,12 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1969,32 +2061,33 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2011,7 +2104,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2027,16 +2120,16 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2049,7 +2142,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = YES +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2061,7 +2154,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2083,7 +2176,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2109,7 +2202,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2161,7 +2254,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2172,7 +2266,8 @@ CALL_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2195,11 +2290,15 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2221,26 +2320,44 @@ INTERACTIVE_SVG = YES # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2278,7 +2395,7 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2295,7 +2412,7 @@ DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/doc/doxygen-nginx.conf b/doc/doxygen-nginx.in similarity index 84% rename from doc/doxygen-nginx.conf rename to doc/doxygen-nginx.in index 847c1e3df3..6a280f31e7 100644 --- a/doc/doxygen-nginx.conf +++ b/doc/doxygen-nginx.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -38,7 +38,7 @@ PROJECT_NAME = "ModSecurity (Nginx)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -46,21 +46,21 @@ PROJECT_NUMBER = PROJECT_BRIEF = "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis. With over 10,000 deployments world-wide, ModSecurity is the most widely deployed WAF in existence." -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. -PROJECT_LOGO = ./doc/doxygen-logo.png +PROJECT_LOGO = ./doxygen-logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc/nginx +OUTPUT_DIRECTORY = nginx -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = doc/nginx CREATE_SUBDIRS = YES +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. @@ -85,14 +93,14 @@ CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -110,7 +118,7 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -153,7 +161,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -220,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -261,16 +269,19 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -282,10 +293,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -325,13 +345,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -390,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -400,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -453,21 +480,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -481,7 +508,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. @@ -490,12 +517,19 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -523,14 +557,14 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -575,27 +609,25 @@ SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -606,7 +638,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -620,8 +652,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -648,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -661,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -669,10 +701,9 @@ LAYOUT_FILE = # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -686,7 +717,7 @@ CITE_BIB_FILES = QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -694,7 +725,7 @@ QUIET = NO WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -711,12 +742,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -731,7 +768,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -740,10 +777,10 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = nginx +INPUT = ../nginx # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -756,14 +793,19 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -778,7 +820,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -794,7 +836,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -805,20 +847,20 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -831,7 +873,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -847,8 +889,12 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -856,11 +902,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -872,14 +922,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -920,7 +970,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -991,13 +1041,13 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1035,7 +1085,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1045,7 +1095,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1057,18 +1107,20 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1078,10 +1130,10 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1112,8 +1164,9 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES @@ -1206,31 +1259,32 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1257,7 +1311,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1282,7 +1336,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1290,21 +1344,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1343,7 +1397,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1371,7 +1425,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1400,7 +1454,7 @@ FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1437,7 +1491,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1445,7 +1499,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1470,11 +1524,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1486,7 +1540,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1499,13 +1553,13 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1521,7 +1575,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1531,13 +1585,13 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = YES @@ -1568,7 +1622,7 @@ LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1586,13 +1640,16 @@ COMPACT_LATEX = NO PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1602,22 +1659,35 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1625,7 +1695,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1636,8 +1706,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1678,11 +1748,19 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1697,7 +1775,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1725,20 +1803,30 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1762,6 +1850,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1775,7 +1870,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1789,19 +1884,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1814,7 +1897,7 @@ XML_PROGRAMLISTING = YES # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1828,14 +1911,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1844,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1852,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1860,9 +1952,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1876,20 +1968,20 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1905,7 +1997,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1917,7 +2009,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = "apache2" +INCLUDE_PATH = "../apache2" # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1925,7 +2017,7 @@ INCLUDE_PATH = "apache2" # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1935,7 +2027,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1944,12 +2036,12 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1969,32 +2061,33 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2011,7 +2104,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2027,16 +2120,16 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2049,7 +2142,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = YES +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2061,7 +2154,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2083,7 +2176,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2109,7 +2202,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2161,7 +2254,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2172,7 +2266,8 @@ CALL_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2195,11 +2290,15 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2221,26 +2320,44 @@ INTERACTIVE_SVG = YES # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2278,7 +2395,7 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2295,7 +2412,7 @@ DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. diff --git a/doc/doxygen-standalone.conf b/doc/doxygen-standalone.in similarity index 84% rename from doc/doxygen-standalone.conf rename to doc/doxygen-standalone.in index 2bcf761881..bb3dfd7329 100644 --- a/doc/doxygen-standalone.conf +++ b/doc/doxygen-standalone.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.6 +# Doxyfile 1.8.13 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -38,7 +38,7 @@ PROJECT_NAME = "ModSecurity (Standalone)" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -46,21 +46,21 @@ PROJECT_NUMBER = PROJECT_BRIEF = "ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx that is developed by Trustwave's SpiderLabs. It has a robust event-based programming language which provides protection from a range of attacks against web applications and allows for HTTP traffic monitoring, logging and real-time analysis. With over 10,000 deployments world-wide, ModSecurity is the most widely deployed WAF in existence." -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. -PROJECT_LOGO = ./doc/doxygen-logo.png +PROJECT_LOGO = ./doxygen-logo.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = doc/standalone +OUTPUT_DIRECTORY = standalone -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where @@ -70,6 +70,14 @@ OUTPUT_DIRECTORY = doc/standalone CREATE_SUBDIRS = YES +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. @@ -85,14 +93,14 @@ CREATE_SUBDIRS = YES OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the @@ -110,7 +118,7 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -127,7 +135,7 @@ ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. @@ -144,7 +152,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -153,7 +161,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -197,9 +205,9 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO @@ -220,13 +228,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -261,16 +269,19 @@ OPTIMIZE_OUTPUT_VHDL = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. # -# Note For files without extension you can use no_extension as a placeholder. +# Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -282,10 +293,19 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 0. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 0 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES @@ -325,13 +345,20 @@ SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first +# tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -390,7 +417,7 @@ LOOKUP_CACHE_SIZE = 0 # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. @@ -400,35 +427,35 @@ LOOKUP_CACHE_SIZE = 0 EXTRACT_ALL = YES -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local methods, +# This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are +# included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. @@ -453,21 +480,21 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be +# (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these +# documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. @@ -481,7 +508,7 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also +# names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. @@ -490,12 +517,19 @@ INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the +# their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -523,14 +557,14 @@ INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. +# name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that +# name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. @@ -575,27 +609,25 @@ SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. @@ -606,7 +638,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -620,8 +652,8 @@ ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES @@ -648,7 +680,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -661,7 +693,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -669,10 +701,9 @@ LAYOUT_FILE = # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. +# search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -686,7 +717,7 @@ CITE_BIB_FILES = QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. @@ -694,7 +725,7 @@ QUIET = NO WARNINGS = YES -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. @@ -711,12 +742,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -731,7 +768,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -740,10 +777,10 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = standalone +INPUT = ../standalone # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -756,14 +793,19 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. -FILE_PATTERNS = +FILE_PATTERNS = # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -778,7 +820,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -794,7 +836,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -805,20 +847,20 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -831,7 +873,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -847,8 +889,12 @@ IMAGE_PATH = # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -856,11 +902,15 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for +# INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. @@ -872,14 +922,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -920,7 +970,7 @@ REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. @@ -991,13 +1041,13 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES @@ -1035,7 +1085,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1045,7 +1095,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1057,18 +1107,20 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1078,10 +1130,10 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to +# will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # http://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 @@ -1112,8 +1164,9 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES @@ -1206,31 +1259,32 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1257,7 +1311,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1282,7 +1336,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1290,21 +1344,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To @@ -1343,7 +1397,7 @@ DISABLE_INDEX = NO # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has @@ -1371,7 +1425,7 @@ ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1400,7 +1454,7 @@ FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. @@ -1437,7 +1491,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1445,7 +1499,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1470,11 +1524,11 @@ SEARCHENGINE = YES # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using Javascript. There -# are two flavours of web server based searching depending on the -# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for -# searching and an index file used by the script. When EXTERNAL_SEARCH is -# enabled the indexing and searching needs to be provided by external tools. See -# the section "External Indexing and Searching" for details. +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1486,7 +1540,7 @@ SERVER_BASED_SEARCH = NO # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). # @@ -1499,13 +1553,13 @@ EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # -# Doxygen ships with an example indexer ( doxyindexer) and search engine +# Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: http://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1521,7 +1575,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1531,13 +1585,13 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = YES @@ -1568,7 +1622,7 @@ LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1586,13 +1640,16 @@ COMPACT_LATEX = NO PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1602,22 +1659,35 @@ EXTRA_PACKAGES = # # Note: Only use a user-defined header if you know what you are doing! The # following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will -# replace them by respectively the title of the page, the current date and time, -# only the current date, the version number of doxygen, the project name (see -# PROJECT_NAME), or the project number (see PROJECT_NUMBER). +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empty +# string, for the replacement values of the other commands the user is referred +# to HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. # # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = + +# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# LaTeX style sheets that are included after the standard style sheets created +# by doxygen. Using this option one can overrule certain style aspects. Doxygen +# will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1625,7 +1695,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1636,8 +1706,8 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES, to get a # higher quality PDF documentation. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1678,11 +1748,19 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. @@ -1697,7 +1775,7 @@ GENERATE_RTF = NO RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. @@ -1725,20 +1803,30 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = + +# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code +# with syntax highlighting in the RTF output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. @@ -1762,6 +1850,13 @@ MAN_OUTPUT = man MAN_EXTENSION = .3 +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without @@ -1775,7 +1870,7 @@ MAN_LINKS = NO # Configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. @@ -1789,19 +1884,7 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify a XML DTD, which can be used by a -# validating XML parser to check the syntax of the XML files. -# This tag requires that the tag GENERATE_XML is set to YES. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. @@ -1814,7 +1897,7 @@ XML_PROGRAMLISTING = YES # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- -# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. @@ -1828,14 +1911,23 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook +# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen -# Definitions (see http://autogen.sf.net) file that captures the structure of -# the code including all documentation. Note that this feature is still -# experimental and incomplete at the moment. +# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an +# AutoGen Definitions (see http://autogen.sf.net) file that captures the +# structure of the code including all documentation. Note that this feature is +# still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -1844,7 +1936,7 @@ GENERATE_AUTOGEN_DEF = NO # Configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. @@ -1852,7 +1944,7 @@ GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. @@ -1860,9 +1952,9 @@ GENERATE_PERLMOD = NO PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to -# understand what is going on. On the other hand, if this tag is set to NO the +# understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. @@ -1876,20 +1968,20 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names -# in the source code. If set to NO only conditional compilation will be +# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names +# in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. @@ -1905,7 +1997,7 @@ MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1917,7 +2009,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = "apache2" +INCLUDE_PATH = "../apache2" # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1925,7 +2017,7 @@ INCLUDE_PATH = "apache2" # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1935,7 +2027,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -1944,12 +2036,12 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will -# remove all refrences to function-like macros that are alone on a line, have an -# all uppercase name, and do not end with a semicolon. Such function macros are -# typically used for boiler-plate code, and will confuse the parser if not +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. @@ -1969,32 +2061,33 @@ SKIP_FUNCTION_MACROS = YES # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. -# Note: Each tag file must have an unique name (where the name does NOT include +# Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external class will be listed in the -# class index. If set to NO only the inherited external classes will be listed. +# If the ALLEXTERNALS tag is set to YES, all external class will be listed in +# the class index. If set to NO, only the inherited external classes will be +# listed. # The default value is: NO. ALLEXTERNALS = NO -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in -# the modules index. If set to NO, only the current project's groups will be +# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES -# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. @@ -2011,7 +2104,7 @@ PERL_PATH = /usr/bin/perl # Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to # NO turns the diagrams off. Note that this option also works with HAVE_DOT # disabled, but it is recommended to install and use dot, since it yields more @@ -2027,16 +2120,16 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = -# If set to YES, the inheritance and collaboration graphs will hide inheritance +# If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2049,7 +2142,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = YES +HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of @@ -2061,7 +2154,7 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font n the dot files that doxygen +# When you want a differently looking font in the dot files that doxygen # generates you can specify the font name using DOT_FONTNAME. You need to make # sure dot is able to find the font, which can be done by putting it in a # standard location or by setting the DOTFONTPATH environment variable or by @@ -2083,7 +2176,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2109,7 +2202,7 @@ COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. @@ -2161,7 +2254,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2172,7 +2266,8 @@ CALL_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2195,11 +2290,15 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2221,26 +2320,44 @@ INTERACTIVE_SVG = YES # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. + +PLANTUML_JAR_PATH = + +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + +# When using plantuml, the specified paths are searched for files specified by +# the !include statement in a plantuml block. + +PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -2278,7 +2395,7 @@ MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. @@ -2295,7 +2412,7 @@ DOT_MULTI_TARGETS = YES GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot # files that are used to generate the various graphs. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. From 2de5175b9cf67ac91bd4a759cf29f91aba1ae09e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 18 May 2017 23:46:28 -0300 Subject: [PATCH 125/477] Fix collection naming problem As reported on #1274 we had a problem while merging the collections. Turns out that the collection name was wrong while passing the information to setvar. --- CHANGES | 2 ++ apache2/re_actions.c | 33 +++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 0fe5f6e74c..7b6955e5ac 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix collection naming problem while merging collections. + [Issue #1274 - Coty Sutherland and @zimmerle] * Fix --enable-docs adding missing Makefile, modifying autoconf and filenames [Issue #1322 - @victorhora] * Change from using rand() to thread-safe ap_random_pick. diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 504cc24053..2eb336a359 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1519,6 +1519,7 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, char *s = NULL; apr_table_t *target_col = NULL; int is_negated = 0; + char *real_col_name = NULL; msc_string *var = NULL; if (msr->txcfg->debuglog_level >= 9) { @@ -1561,19 +1562,26 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, var_name = s + 1; *s = '\0'; + if (strcasecmp(col_name,"USER") == 0 || strcasecmp(col_name,"SESSION") == 0 + || strcasecmp(col_name, "RESOURCE") == 0) { + real_col_name = apr_psprintf(mptmp, "%s_%s", msr->txcfg->webappid, col_name); + } + /* Locate the collection. */ if (strcasecmp(col_name, "tx") == 0) { /* Special case for TX variables. */ target_col = msr->tx_vars; } else { target_col = (apr_table_t *)apr_table_get(msr->collections, col_name); - if (target_col == NULL) { - if (msr->txcfg->debuglog_level >= 3) { - msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.", - log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); - } + } - return 0; + + if (target_col == NULL) { + if (msr->txcfg->debuglog_level >= 3) { + msr_log(msr, 3, "Could not set variable \"%s.%s\" as the collection does not exist.", + log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); } + + return 0; } if (is_negated) { @@ -1616,7 +1624,11 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, } /* Record the original value before we change it */ - collection_original_setvar(msr, col_name, rec); + if (real_col_name == NULL) { + collection_original_setvar(msr, col_name, rec); + } else { + collection_original_setvar(msr, real_col_name, rec); + } /* Expand values in value */ val->value = var_value; @@ -1651,6 +1663,7 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, var->value = apr_pstrdup(msr->mp, var_value); var->value_len = strlen(var->value); expand_macros(msr, var, rule, mptmp); + apr_table_setn(target_col, var->name, (void *)var); if (msr->txcfg->debuglog_level >= 9) { @@ -2048,7 +2061,11 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, /* Record the original counter value before we change it */ var = (msc_string *)apr_table_get(table, "UPDATE_COUNTER"); if (var != NULL) { - collection_original_setvar(msr, col_name, var); + if (real_col_name == NULL) { + collection_original_setvar(msr, col_name, var); + } else { + collection_original_setvar(msr, real_col_name, var); + } } /* Add the collection to the list. */ From 84d2f30cc87eb7f2747bfdf6b6ac90d3e36735d1 Mon Sep 17 00:00:00 2001 From: Mladen Turk <mturk@jboss.org> Date: Wed, 28 Sep 2016 18:34:32 +0200 Subject: [PATCH 126/477] Use global mutex instead sdbm file lock to fix issues with threaded mpm's --- apache2/modsecurity.c | 22 +++++++++++++++ apache2/modsecurity.h | 1 + apache2/persist_dbm.c | 66 +++++++++++++++++++++++++++++-------------- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 6652cdc1a6..69ba3bad2b 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -169,6 +169,22 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { return -1; } #endif /* SET_MUTEX_PERMS */ + + rc = apr_global_mutex_create(&msce->dbm_lock, NULL, APR_LOCK_DEFAULT, mp); + if (rc != APR_SUCCESS) { + return -1; + } + +#ifdef __SET_MUTEX_PERMS +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 + rc = ap_unixd_set_global_mutex_perms(msce->dbm_lock); +#else + rc = unixd_set_global_mutex_perms(msce->dbm_lock); +#endif + if (rc != APR_SUCCESS) { + return -1; + } +#endif /* SET_MUTEX_PERMS */ #endif return 1; @@ -195,6 +211,12 @@ void modsecurity_child_init(msc_engine *msce) { } } + if (msce->dbm_lock != NULL) { + apr_status_t rc = apr_global_mutex_child_init(&msce->dbm_lock, NULL, msce->mp); + if (rc != APR_SUCCESS) { + // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init dbm mutex"); + } + } } /** diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 228bea0b22..7bdc12de7a 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -657,6 +657,7 @@ struct msc_engine { apr_pool_t *mp; apr_global_mutex_t *auditlog_lock; apr_global_mutex_t *geo_lock; + apr_global_mutex_t *dbm_lock; msre_engine *msre; unsigned int processing_mode; }; diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 175a5d0213..942b589641 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -101,6 +101,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec int expired = 0; int i; + if (msr->txcfg->data_dir == NULL) { msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), @@ -119,10 +120,18 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec key.dsize = col_key_len + 1; if (existing_dbm == NULL) { + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { dbm = NULL; + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); goto cleanup; } } @@ -156,6 +165,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec /* Close after "value" used from fetch or memory may be overwritten. */ if (existing_dbm == NULL) { apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); dbm = NULL; } @@ -202,12 +212,19 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec */ if (apr_table_get(col, "KEY") == NULL) { if (existing_dbm == NULL) { + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); goto cleanup; } } @@ -230,6 +247,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (existing_dbm == NULL) { apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); dbm = NULL; } @@ -292,14 +310,16 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); } - + return col; cleanup: if ((existing_dbm == NULL) && dbm) { apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); } return NULL; @@ -412,6 +432,14 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { var->value_len = strlen(var->value); } + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } + /* ENH Make the expiration timestamp accessible in blob form so that * it is easier/faster to determine expiration without having to * convert back to table form @@ -420,19 +448,13 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; goto error; } - - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } + /* If there is an original value, then create a delta and * apply the delta to the current value */ @@ -497,8 +519,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { blob = apr_pcalloc(msr->mp, blob_size); if (blob == NULL) { if (dbm != NULL) { - apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); } return -1; @@ -555,16 +577,16 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, get_apr_error(msr->mp, rc)); if (dbm != NULL) { - apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); } return -1; } - apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); - + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", log_escape_ex(msr->mp, var_name->value, var_name->value_len), @@ -608,9 +630,17 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { log_escape(msr->mp, dbm_filename)); } + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; @@ -619,12 +649,6 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { /* First get a list of all keys. */ keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } /* No one can write to the file while doing this so * do it as fast as possible. @@ -637,7 +661,6 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } rc = apr_sdbm_nextkey(dbm, &key); } - apr_sdbm_unlock(dbm); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, @@ -706,13 +729,14 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } apr_sdbm_close(dbm); - + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); return 1; error: if (dbm) { apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); } return -1; From c6f6dffed2a43b6db8e085ae2ae3c54bbfa8a532 Mon Sep 17 00:00:00 2001 From: Mladen Turk <mturk@jboss.org> Date: Fri, 4 Nov 2016 10:06:33 +0100 Subject: [PATCH 127/477] Move locking before table update --- apache2/persist_dbm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 942b589641..01d39f347e 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -384,6 +384,14 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { log_escape(msr->mp, dbm_filename)); } + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } + /* Delete IS_NEW on store. */ apr_table_unset(col, "IS_NEW"); @@ -431,14 +439,6 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { var->value = apr_psprintf(msr->mp, "%d", counter + 1); var->value_len = strlen(var->value); } - - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } /* ENH Make the expiration timestamp accessible in blob form so that * it is easier/faster to determine expiration without having to From 112ba45e7abec511919cd600a125aebe5603ab30 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Sun, 21 May 2017 08:53:11 -0300 Subject: [PATCH 128/477] Makes global mutex for collections optional --- CHANGES | 2 ++ apache2/modsecurity.c | 5 +++ apache2/modsecurity.h | 2 ++ apache2/persist_dbm.c | 83 +++++++++++++++++++++++++++++++++++++------ configure.ac | 19 +++++++++- 5 files changed, 100 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 7b6955e5ac..4be4bc8fd2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Uses an optional global lock while manipulating collections. + [Issues #1224 - @mturk and @zimmerle] * Fix collection naming problem while merging collections. [Issue #1274 - Coty Sutherland and @zimmerle] * Fix --enable-docs adding missing Makefile, modifying autoconf and filenames diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 69ba3bad2b..dcdb48590c 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -170,6 +170,7 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { } #endif /* SET_MUTEX_PERMS */ +#ifdef GLOBAL_COLLECTION_LOCK rc = apr_global_mutex_create(&msce->dbm_lock, NULL, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { return -1; @@ -185,6 +186,7 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { return -1; } #endif /* SET_MUTEX_PERMS */ +#endif #endif return 1; @@ -211,12 +213,15 @@ void modsecurity_child_init(msc_engine *msce) { } } +#ifdef GLOBAL_COLLECTION_LOCK if (msce->dbm_lock != NULL) { apr_status_t rc = apr_global_mutex_child_init(&msce->dbm_lock, NULL, msce->mp); if (rc != APR_SUCCESS) { // ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init dbm mutex"); } } +#endif + } /** diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 7bdc12de7a..f170034c99 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -657,7 +657,9 @@ struct msc_engine { apr_pool_t *mp; apr_global_mutex_t *auditlog_lock; apr_global_mutex_t *geo_lock; +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_t *dbm_lock; +#endif msre_engine *msre; unsigned int processing_mode; }; diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 01d39f347e..597d5b8fc7 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -120,18 +120,21 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec key.dsize = col_key_len + 1; if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); if (rc != APR_SUCCESS) { msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", get_apr_error(msr->mp, rc)); goto cleanup; } - +#endif rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif goto cleanup; } } @@ -165,7 +168,9 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec /* Close after "value" used from fetch or memory may be overwritten. */ if (existing_dbm == NULL) { apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif dbm = NULL; } @@ -212,19 +217,23 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec */ if (apr_table_get(col, "KEY") == NULL) { if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); if (rc != APR_SUCCESS) { msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", get_apr_error(msr->mp, rc)); goto cleanup; - } + } +#endif rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif goto cleanup; } } @@ -247,7 +256,9 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (existing_dbm == NULL) { apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif dbm = NULL; } @@ -310,16 +321,20 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif } - + return col; cleanup: if ((existing_dbm == NULL) && dbm) { apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif } return NULL; @@ -384,6 +399,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { log_escape(msr->mp, dbm_filename)); } +#ifdef GLOBAL_COLLECTION_LOCK /* Need to lock to pull in the stored data again and apply deltas. */ rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); if (rc != APR_SUCCESS) { @@ -391,6 +407,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { get_apr_error(msr->mp, rc)); goto error; } +#endif /* Delete IS_NEW on store. */ apr_table_unset(col, "IS_NEW"); @@ -439,7 +456,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { var->value = apr_psprintf(msr->mp, "%d", counter + 1); var->value_len = strlen(var->value); } - + /* ENH Make the expiration timestamp accessible in blob form so that * it is easier/faster to determine expiration without having to * convert back to table form @@ -448,13 +465,24 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; goto error; } - + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif /* If there is an original value, then create a delta and * apply the delta to the current value */ @@ -519,8 +547,13 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { blob = apr_pcalloc(msr->mp, blob_size); if (blob == NULL) { if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif } return -1; @@ -577,16 +610,26 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, get_apr_error(msr->mp, rc)); if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif } return -1; } +#ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); apr_global_mutex_unlock(msr->modsecurity->dbm_lock); - +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", log_escape_ex(msr->mp, var_name->value, var_name->value_len), @@ -630,17 +673,21 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { log_escape(msr->mp, dbm_filename)); } +#ifdef GLOBAL_COLLECTION_LOCK rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); if (rc != APR_SUCCESS) { msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", get_apr_error(msr->mp, rc)); goto error; } - +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; @@ -650,6 +697,15 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { /* First get a list of all keys. */ keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + /* No one can write to the file while doing this so * do it as fast as possible. */ @@ -661,6 +717,9 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } rc = apr_sdbm_nextkey(dbm, &key); } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, @@ -729,14 +788,18 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif return 1; error: if (dbm) { apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif } return -1; diff --git a/configure.ac b/configure.ac index d600edc4d8..3180547cc5 100644 --- a/configure.ac +++ b/configure.ac @@ -545,6 +545,23 @@ AC_ARG_ENABLE(server-context-logging, log_server_context='' ]) + +# Enable collection's global lock +AC_ARG_ENABLE(collection-global-lock, + AS_HELP_STRING([--enable-collection-global-lock], + [Enable collection correctness by using a global lock. May reduce performance significatively. This is disabled by default]), +[ + if test "$enableval" != "yes"; then + collection_global_lock="" + else + collection_global_lock="-DGLOBAL_COLLECTION_LOCK" + fi +], +[ + collection_global_lock='' +]) + + # Ignore configure errors AC_ARG_ENABLE(errors, AS_HELP_STRING([--disable-errors], @@ -795,7 +812,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_contex" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_contex $collection_global_lock" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 9ac9ff8223c0a9d7723a312204659ff72c9cc685 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 22 May 2017 09:21:13 -0300 Subject: [PATCH 129/477] Adds a sanity check before use ctl:ruleRemoveTargetByTag This commit closes the issue #1353 --- CHANGES | 2 ++ apache2/re_actions.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 4be4bc8fd2..06834b6d3d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Adds a sanity check before use ctl:ruleRemoveTargetByTag. + [Issue #1353 - @LukeP21 and @zimmerle] * Uses an optional global lock while manipulating collections. [Issues #1224 - @mturk and @zimmerle] * Fix collection naming problem while merging collections. diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 2eb336a359..f81ddc87c7 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1253,6 +1253,10 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Ctl: ruleRemoveTargetByTag tag=%s targets=%s", p1, p2); } + if (p2 == NULL) { + msr_log(msr, 1, "ModSecurity: Missing target for tag \"%s\"", p1); + return -1; + } re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_TAG; From 72f632e9b6b2e63677cfba7e62a47efb87c90b48 Mon Sep 17 00:00:00 2001 From: Daniel Stelter-Gliese <daniel.stelter-gliese@innogames.de> Date: Wed, 2 Mar 2016 11:00:40 +0100 Subject: [PATCH 130/477] Avoid additional operator invokation if last transform of a multimatch doesn't modify the input Fixes #1086 --- CHANGES | 3 +++ apache2/re.c | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 06834b6d3d..db69765a6f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Avoid additional operator invokation if last transform of a multimatch + doesn't modify the input + [Issue #1086, #1087 - Daniel Stelter-Gliese] * Adds a sanity check before use ctl:ruleRemoveTargetByTag. [Issue #1353 - @LukeP21 and @zimmerle] * Uses an optional global lock while manipulating collections. diff --git a/apache2/re.c b/apache2/re.c index 83f4d59aae..abc6e4d5a5 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2872,7 +2872,10 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { arr = apr_table_elts(tartab); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { + /* Variable was modified by *any* transformation */ int changed; + /* Variable was modified by *last applied* transformation (needed by multimatch) */ + int tfnchanged; int usecache = 0; apr_table_t *cachetab = NULL; apr_time_t time_before_trans = 0; @@ -2995,8 +2998,8 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { apr_table_t *normtab; const char *lastvarval = NULL; apr_size_t lastvarlen = 0; - int tfnchanged = 0; + tfnchanged = 0; changed = 0; normtab = apr_table_make(mptmp, 10); if (normtab == NULL) return -1; @@ -3278,7 +3281,7 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { * or if it is and we need to process the result of the * last transformation. */ - if (!multi_match || changed) { + if (!multi_match || tfnchanged) { invocations++; #if defined(PERFORMANCE_MEASUREMENT) From a24957469261873d8596aac005677cac3d0abbd2 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 22 May 2017 18:42:37 -0300 Subject: [PATCH 131/477] Avoids to flush xml buffer while assembling the injected html Fix #742 --- CHANGES | 2 ++ apache2/msc_crypt.c | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index db69765a6f..c38ff6b8b7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Avoid to flush xml buffer while assembling the injected html. + [Issue #742 - @zimmerle] * Avoid additional operator invokation if last transform of a multimatch doesn't modify the input [Issue #1086, #1087 - Daniel Stelter-Gliese] diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index e7590b66a3..40d1791ced 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -1072,7 +1072,8 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { } htmlDocContentDumpFormatOutput(output_buf, msr->crypto_html_tree, NULL, 0); - xmlOutputBufferFlush(output_buf); + // Not necessary in 2.9.4+ + //xmlOutputBufferFlush(output_buf); #ifdef LIBXML2_NEW_BUFFER @@ -1082,6 +1083,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; + msr_log(msr, 4, "inject_hashed_response_body: NEW_BUFFER Output buffer is null."); return -1; } @@ -1096,6 +1098,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); + msr_log(msr, 4, "inject_hashed_response_body: NEW BUFFER Stream Output is null."); return -1; } @@ -1111,6 +1114,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; + msr_log(msr, 4, "inject_hashed_response_body: Conv is null."); return -1; } @@ -1123,6 +1127,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { msr->stream_output_data = (char *)malloc(msr->stream_output_length+1); if (msr->stream_output_data == NULL) { + msr_log(msr, 4, "inject_hashed_response_body: Stream Output data is NULL."); xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); return -1; @@ -1143,6 +1148,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { if(output_buf->buffer == NULL || output_buf->buffer->use == 0) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); + msr_log(msr, 4, "inject_hashed_response_body: Output buffer is null."); msr->of_stream_changed = 0; return -1; } @@ -1158,6 +1164,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); + msr_log(msr, 4, "inject_hashed_response_body: Stream Output is null."); return -1; } @@ -1174,6 +1181,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; + msr_log(msr, 4, "inject_hashed_response_body: Stream Output is null."); return -1; } @@ -1188,6 +1196,7 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); + msr_log(msr, 4, "inject_hashed_response_body: Stream Output Data is null."); return -1; } From 6f49bad748206ef2d46974cfcd3b6f393219b324 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 22 May 2017 18:46:07 -0300 Subject: [PATCH 132/477] Fix the hex digit size for SHA1 on msc_crypt implementation Fix #1354 --- CHANGES | 2 ++ apache2/msc_crypt.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index c38ff6b8b7..e0d07be370 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Fix the hex digit size for SHA1 on msc_crypt implementation. + [Issue #1354 - @zimmerle and @parthasarathi204] * Avoid to flush xml buffer while assembling the injected html. [Issue #742 - @zimmerle] * Avoid additional operator invokation if last transform of a multimatch diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 40d1791ced..3bcbdd7d69 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -189,7 +189,7 @@ char *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char hmac_ipad[HMAC_PAD_SIZE], hmac_opad[HMAC_PAD_SIZE]; unsigned char nkey[APR_SHA1_DIGESTSIZE]; unsigned char *hmac_key = (unsigned char *) key; - char hex_digest[APR_SHA1_DIGESTSIZE * 2], *hmac_digest; + char hex_digest[APR_SHA1_DIGESTSIZE * 2 + 1], *hmac_digest; const char hex[] = "0123456789abcdef"; int i; From 6473cf626d05a14a77285d3c0b5bebd736a770e2 Mon Sep 17 00:00:00 2001 From: Hideaki Hayashi <hihayash@gmail.com> Date: Fri, 5 Feb 2016 11:20:28 -0800 Subject: [PATCH 133/477] Make url path absolute for SecHashEngine only when it is relative in the first place. Fix #752 --- apache2/msc_crypt.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 3bcbdd7d69..cf6a4a7705 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -68,24 +68,30 @@ char *normalize_path(modsec_rec *msr, char *input) { char *Uri = NULL; int bytes = 0; /*int i;*/ - char *relative_link = NULL; + char *abs_link = NULL; char *filename = NULL; - char *relative_path = NULL; - char *relative_uri = NULL; + char *abs_path = NULL; + char *abs_uri = NULL; - filename = file_basename(msr->mp, msr->r->parsed_uri.path); + if (uri->path[0] != '/') { + /* uri->path is relative. make it absolute */ + filename = file_basename(msr->mp, msr->r->parsed_uri.path); - if(filename == NULL || (strlen(msr->r->parsed_uri.path) - strlen(filename) < 0)) - return NULL; + if(filename == NULL || (strlen(msr->r->parsed_uri.path) - strlen(filename) < 0)) + return NULL; - relative_path = apr_pstrndup(msr->mp, msr->r->parsed_uri.path, strlen(msr->r->parsed_uri.path) - strlen(filename)); - relative_uri = apr_pstrcat(msr->mp, relative_path, uri->path, NULL); + abs_path = apr_pstrndup(msr->mp, msr->r->parsed_uri.path, strlen(msr->r->parsed_uri.path) - strlen(filename)); + abs_uri = apr_pstrcat(msr->mp, abs_path, uri->path, NULL); - relative_link = apr_pstrdup(msr->mp, relative_uri); + abs_link = apr_pstrdup(msr->mp, abs_uri); + } + else { + abs_link = apr_pstrdup(msr->mp, uri->path); + } - xmlNormalizeURIPath(relative_link); + xmlNormalizeURIPath(abs_link); - Uri = apr_pstrdup(msr->mp, relative_link); + Uri = apr_pstrdup(msr->mp, abs_link); /* for(i = 0; i < (int)strlen(Uri); i++) { From 624bd2bf8221f27c406299250a7d3ea9d5e56de4 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 22 May 2017 18:59:20 -0300 Subject: [PATCH 134/477] Adds info about pull request #1071 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index e0d07be370..9278e5e234 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Make url path absolute for SecHashEngine only when it is relative + in the first place. + [Issue #752, #1071 - @hideaki] * Fix the hex digit size for SHA1 on msc_crypt implementation. [Issue #1354 - @zimmerle and @parthasarathi204] * Avoid to flush xml buffer while assembling the injected html. From 1684400eeea1b6c802bad8c6275aa2d5ce198202 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Mon, 29 May 2017 17:05:01 -0400 Subject: [PATCH 135/477] Fixes issue #1432 by not logging normal behavior to error.log and using APLOG_DEBUG instead --- apache2/mod_security2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index f4db2ac835..b6e98e9dcd 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1494,7 +1494,7 @@ static int hook_connection_early(conn_rec *conn) } } - ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn, "ModSecurity: going to loop through %d servers with %d threads", server_limit, thread_limit); for (i = 0; i < server_limit; ++i) { @@ -1526,7 +1526,7 @@ static int hook_connection_early(conn_rec *conn) } } - ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, conn, + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn, "ModSecurity: threads in READ: %ld of %ld, WRITE: %ld of %ld, IP: %s", ip_count_r, conn_read_state_limit, ip_count_w, conn_write_state_limit, client_ip); From e5dbe593367316a8320b958a6679b7e842be648a Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 30 May 2017 08:14:44 -0300 Subject: [PATCH 136/477] Adds info about pull request #1432 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 9278e5e234..1aca9063f1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Avoid log flood while using SecConnEngine + [Issue #1436 - @victorhora] * Make url path absolute for SecHashEngine only when it is relative in the first place. [Issue #752, #1071 - @hideaki] From 53571a860d172b01a17ce90d95f94ec1943ecc8b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 30 May 2017 10:43:10 -0300 Subject: [PATCH 137/477] Updates libinjection. This is not yet their v3.10.0. But I belive it is close to be. See #124 at client9/libinjection for further information. --- CHANGES | 2 + apache2/libinjection/libinjection_html5.c | 143 ++------ apache2/libinjection/libinjection_sqli.c | 132 ++++---- apache2/libinjection/libinjection_sqli.h | 7 +- apache2/libinjection/libinjection_sqli_data.h | 26 +- apache2/libinjection/libinjection_xss.c | 320 ++++-------------- 6 files changed, 175 insertions(+), 455 deletions(-) diff --git a/CHANGES b/CHANGES index 1aca9063f1..b297792ed6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Updates libinjection to: bf234eb2f385b969c4f803b35fda53cffdd93922 + [Issue #1412 - @zimmerle, @bjdijk] * Avoid log flood while using SecConnEngine [Issue #1436 - @victorhora] * Make url path absolute for SecHashEngine only when it is relative diff --git a/apache2/libinjection/libinjection_html5.c b/apache2/libinjection/libinjection_html5.c index 379bb9960d..65565101ba 100644 --- a/apache2/libinjection/libinjection_html5.c +++ b/apache2/libinjection/libinjection_html5.c @@ -12,7 +12,6 @@ #define CHAR_EOF -1 -#define CHAR_NULL 0 #define CHAR_BANG 33 #define CHAR_DOUBLE 34 #define CHAR_PERCENT 37 @@ -24,7 +23,6 @@ #define CHAR_GT 62 #define CHAR_QUESTION 63 #define CHAR_RIGHTB 93 -#define CHAR_TICK 96 /* prototypes */ @@ -43,7 +41,6 @@ static int h5_state_before_attribute_name(h5_state_t* hs); static int h5_state_before_attribute_value(h5_state_t* hs); static int h5_state_attribute_value_double_quote(h5_state_t* hs); static int h5_state_attribute_value_single_quote(h5_state_t* hs); -static int h5_state_attribute_value_back_quote(h5_state_t* hs); static int h5_state_attribute_value_no_quote(h5_state_t* hs); static int h5_state_after_attribute_value_quoted_state(h5_state_t* hs); static int h5_state_comment(h5_state_t* hs); @@ -63,28 +60,16 @@ static int h5_state_doctype(h5_state_t* hs); /** * public function */ -void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_flags flags) +void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, int flags) { memset(hs, 0, sizeof(h5_state_t)); hs->s = s; hs->len = len; - - switch (flags) { - case DATA_STATE: + hs->state = h5_state_data; + if (flags == 0) { hs->state = h5_state_data; - break; - case VALUE_NO_QUOTE: - hs->state = h5_state_before_attribute_name; - break; - case VALUE_SINGLE_QUOTE: - hs->state = h5_state_attribute_value_single_quote; - break; - case VALUE_DOUBLE_QUOTE: - hs->state = h5_state_attribute_value_double_quote; - break; - case VALUE_BACK_QUOTE: - hs->state = h5_state_attribute_value_back_quote; - break; + } else { + assert(0); } } @@ -100,18 +85,10 @@ int libinjection_h5_next(h5_state_t* hs) /** * Everything below here is private * - */ - +*/ static int h5_is_white(char ch) { - /* - * \t = horizontal tab = 0x09 - * \n = newline = 0x0A - * \v = vertical tab = 0x0B - * \f = form feed = 0x0C - * \r = cr = 0x0D - */ return strchr(" \t\n\v\f\r", ch) != NULL; } @@ -120,17 +97,9 @@ static int h5_skip_white(h5_state_t* hs) char ch; while (hs->pos < hs->len) { ch = hs->s[hs->pos]; - switch (ch) { - case 0x00: /* IE only */ - case 0x20: - case 0x09: - case 0x0A: - case 0x0B: /* IE only */ - case 0x0C: - case 0x0D: /* IE only */ + if (ch == ' ') { hs->pos += 1; - break; - default: + } else { return ch; } } @@ -198,9 +167,6 @@ static int h5_state_tag_open(h5_state_t* hs) return h5_state_bogus_comment2(hs); } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { return h5_state_tag_name(hs); - } else if (ch == CHAR_NULL) { - /* IE-ism NULL characters are ignored */ - return h5_state_tag_name(hs); } else { /* user input mistake in configuring state */ if (hs->pos == 0) { @@ -231,9 +197,7 @@ static int h5_state_end_tag_open(h5_state_t* hs) } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { return h5_state_tag_name(hs); } - - hs->is_close = 0; - return h5_state_bogus_comment(hs); + return h5_state_data(hs); } /* * @@ -267,12 +231,7 @@ static int h5_state_tag_name(h5_state_t* hs) pos = hs->pos; while (pos < hs->len) { ch = hs->s[pos]; - if (ch == 0) { - /* special non-standard case */ - /* allow nulls in tag name */ - /* some old browsers apparently allow and ignore them */ - pos += 1; - } else if (h5_is_white(ch)) { + if (h5_is_white(ch)) { hs->token_start = hs->s + hs->pos; hs->token_len = pos - hs->pos; hs->token_type = TAG_NAME_OPEN; @@ -340,7 +299,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs) default: { return h5_state_attribute_name(hs); } - } + } } static int h5_state_attribute_name(h5_state_t* hs) @@ -349,7 +308,7 @@ static int h5_state_attribute_name(h5_state_t* hs) size_t pos; TRACE(); - pos = hs->pos + 1; + pos = hs->pos; while (pos < hs->len) { ch = hs->s[pos]; if (h5_is_white(ch)) { @@ -399,19 +358,21 @@ static int h5_state_attribute_name(h5_state_t* hs) static int h5_state_after_attribute_name(h5_state_t* hs) { int c; + size_t pos; TRACE(); + pos = hs->pos; c = h5_skip_white(hs); switch (c) { case CHAR_EOF: { return 0; } case CHAR_SLASH: { - hs->pos += 1; + hs->pos = pos + 1; return h5_state_self_closing_start_tag(hs); } case CHAR_EQUALS: { - hs->pos += 1; + hs->pos = pos + 1; return h5_state_before_attribute_value(hs); } case CHAR_GT: { @@ -442,9 +403,6 @@ static int h5_state_before_attribute_value(h5_state_t* hs) return h5_state_attribute_value_double_quote(hs); } else if (c == CHAR_SINGLE) { return h5_state_attribute_value_single_quote(hs); - } else if (c == CHAR_TICK) { - /* NON STANDARD IE */ - return h5_state_attribute_value_back_quote(hs); } else { return h5_state_attribute_value_no_quote(hs); } @@ -457,16 +415,8 @@ static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar) TRACE(); - /* skip initial quote in normal case. - * don't do this "if (pos == 0)" since it means we have started - * in a non-data state. given an input of '><foo - * we want to make 0-length attribute name - */ - if (hs->pos > 0) { - hs->pos += 1; - } - - + /* skip quote */ + hs->pos += 1; idx = (const char*) memchr(hs->s + hs->pos, qchar, hs->len - hs->pos); if (idx == NULL) { hs->token_start = hs->s + hs->pos; @@ -497,13 +447,6 @@ int h5_state_attribute_value_single_quote(h5_state_t* hs) return h5_state_attribute_value_quote(hs, CHAR_SINGLE); } -static -int h5_state_attribute_value_back_quote(h5_state_t* hs) -{ - TRACE(); - return h5_state_attribute_value_quote(hs, CHAR_TICK); -} - static int h5_state_attribute_value_no_quote(h5_state_t* hs) { char ch; @@ -713,13 +656,10 @@ static int h5_state_comment(h5_state_t* hs) char ch; const char* idx; size_t pos; - size_t offset; - const char* end = hs->s + hs->len; TRACE(); pos = hs->pos; while (1) { - idx = (const char*) memchr(hs->s + pos, CHAR_DASH, hs->len - pos); /* did not find anything or has less than 3 chars left */ @@ -730,62 +670,21 @@ static int h5_state_comment(h5_state_t* hs) hs->token_type = TAG_COMMENT; return 1; } - offset = 1; - - /* skip all nulls */ - while (idx + offset < end && *(idx + offset) == 0) { - offset += 1; - } - if (idx + offset == end) { - hs->state = h5_state_eof; - hs->token_start = hs->s + hs->pos; - hs->token_len = hs->len - hs->pos; - hs->token_type = TAG_COMMENT; - return 1; - } - - ch = *(idx + offset); + ch = *(idx + 1); if (ch != CHAR_DASH && ch != CHAR_BANG) { pos = (size_t)(idx - hs->s) + 1; continue; } - - /* need to test */ -#if 0 - /* skip all nulls */ - while (idx + offset < end && *(idx + offset) == 0) { - offset += 1; - } - if (idx + offset == end) { - hs->state = h5_state_eof; - hs->token_start = hs->s + hs->pos; - hs->token_len = hs->len - hs->pos; - hs->token_type = TAG_COMMENT; - return 1; - } -#endif - - offset += 1; - if (idx + offset == end) { - hs->state = h5_state_eof; - hs->token_start = hs->s + hs->pos; - hs->token_len = hs->len - hs->pos; - hs->token_type = TAG_COMMENT; - return 1; - } - - - ch = *(idx + offset); + ch = *(idx + 2); if (ch != CHAR_GT) { pos = (size_t)(idx - hs->s) + 1; continue; } - offset += 1; /* ends in --> or -!> */ hs->token_start = hs->s + hs->pos; hs->token_len = (size_t)(idx - hs->s) - hs->pos; - hs->pos = (size_t)(idx + offset - hs->s); + hs->pos = (size_t)(idx - hs->s) + 3; hs->state = h5_state_data; hs->token_type = TAG_COMMENT; return 1; diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index ed506c651e..0b67c5cc49 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -1,5 +1,5 @@ /** - * Copyright 2012,2016 Nick Galbreath + * Copyright 2012,2013 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -112,11 +112,15 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) } while (cur < last) { - /* safe since cur < len - 1 always */ - if (cur[0] == c0 && cur[1] == c1) { - return cur; + if (cur[0] == c0) { + if (cur[1] == c1) { + return cur; + } else { + cur += 2; /* (c0 == c1) ? 1 : 2; */ + } + } else { + cur += 1; } - cur += 1; } return NULL; @@ -187,11 +191,11 @@ static int char_is_white(char ch) { /* ' ' space is 0x32 '\t 0x09 \011 horizontal tab '\n' 0x0a \012 new line - '\v' 0x0b \013 vertical tab + '\v' 0x0b \013 verical tab '\f' 0x0c \014 new page '\r' 0x0d \015 carriage return 0x00 \000 null (oracle) - 0xa0 \240 is Latin-1 + 0xa0 \240 is latin1 */ return strchr(" \t\n\v\f\r\240\000", ch) != NULL; } @@ -290,7 +294,7 @@ static void st_clear(stoken_t * st) static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len, const char value) { - /* done to eliminate unused warning */ + /* done to elimiate unused warning */ (void)len; st->type = (char) stype; st->pos = pos; @@ -398,7 +402,7 @@ static size_t parse_eol_comment(struct libinjection_sqli_state * sf) } } -/** In ANSI mode, hash is an operator +/** In Ansi mode, hash is an operator * In MYSQL mode, it's a EOL comment like '--' */ static size_t parse_hash(struct libinjection_sqli_state * sf) @@ -838,7 +842,7 @@ static size_t parse_bstring(struct libinjection_sqli_state *sf) /* * hex literal string - * re: [xX]'[0123456789abcdefABCDEF]*' + * re: [XX]'[0123456789abcdefABCDEF]*' * mysql has requirement of having EVEN number of chars, * but pgsql does not */ @@ -1068,7 +1072,7 @@ static size_t parse_money(struct libinjection_sqli_state *sf) /* we have $foobar$ ... find it again */ strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); - if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { + if (strend == NULL) { /* fell off edge */ st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); sf->current->str_open = '$'; @@ -1100,6 +1104,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; + int have_dot = 0; int have_e = 0; int have_exp = 0; @@ -1131,6 +1136,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } if (pos < slen && cs[pos] == '.') { + have_dot = 1; pos += 1; while (pos < slen && ISDIGIT(cs[pos])) { pos += 1; @@ -1179,7 +1185,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } } - if (have_e == 1 && have_exp == 0) { + if (have_dot == 1 && have_e == 1 && have_exp == 0) { /* very special form of * "1234.e" * "10.10E" @@ -1236,13 +1242,29 @@ int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) const unsigned char ch = (unsigned char) (s[*pos]); /* - * look up the parser, and call it - * - * Porting Note: this is mapping of char to function - * charparsers[ch]() + * if not ascii, then continue... + * actually probably need to just assuming + * it's a string */ - fnptr = char_parse_map[ch]; + if (ch > 127) { + /* 160 or 0xA0 or octal 240 is "latin1 non-breaking space" + * but is treated as a space in mysql. + */ + if (ch == 160) { + fnptr = parse_white; + } else { + fnptr = parse_word; + } + } else { + /* + * look up the parser, and call it + * + * Porting Note: this is mapping of char to function + * charparsers[ch]() + */ + fnptr = char_parse_map[ch]; + } *pos = (*fnptr) (sf); /* @@ -1327,22 +1349,16 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, a->type == TYPE_UNION || a->type == TYPE_FUNCTION || a->type == TYPE_EXPRESSION || - a->type == TYPE_TSQL || a->type == TYPE_SQLTYPE)) { - return FALSE; + return CHAR_NULL; } - if (! - (b->type == TYPE_KEYWORD || - b->type == TYPE_BAREWORD || - b->type == TYPE_OPERATOR || - b->type == TYPE_UNION || - b->type == TYPE_FUNCTION || - b->type == TYPE_EXPRESSION || - b->type == TYPE_TSQL || - b->type == TYPE_SQLTYPE || - b->type == TYPE_LOGIC_OPERATOR)) { - return FALSE; + if (b->type != TYPE_KEYWORD && b->type != TYPE_BAREWORD && + b->type != TYPE_OPERATOR && b->type != TYPE_SQLTYPE && + b->type != TYPE_LOGIC_OPERATOR && + b->type != TYPE_FUNCTION && + b->type != TYPE_UNION && b->type != TYPE_EXPRESSION) { + return CHAR_NULL; } sz1 = a->len; @@ -1358,6 +1374,7 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, tmp[sz1] = ' '; memcpy(tmp + sz1 + 1, b->val, sz2); tmp[sz3] = CHAR_NULL; + ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3); if (ch != CHAR_NULL) { @@ -1433,13 +1450,6 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) sf->tokenvec[2].type == TYPE_COMMA && sf->tokenvec[3].type == TYPE_LEFTPARENS && sf->tokenvec[4].type == TYPE_NUMBER - ) || - ( - sf->tokenvec[0].type == TYPE_BAREWORD && - sf->tokenvec[1].type == TYPE_RIGHTPARENS && - sf->tokenvec[2].type == TYPE_OPERATOR && - sf->tokenvec[3].type == TYPE_LEFTPARENS && - sf->tokenvec[4].type == TYPE_BAREWORD ) ) { @@ -1531,7 +1541,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) continue; } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) && sf->tokenvec[left+1].type == TYPE_LEFTPARENS && ( - /* TSQL functions but common enough to be column names */ + /* TSQL functions but common enough to be collumn names */ cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || @@ -1554,7 +1564,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) /* pos is the same * other conversions need to go here... for instance - * password CAN be a function, coalesce CAN be a function + * password CAN be a function, coalese CAN be a function */ sf->tokenvec[left].type = TYPE_FUNCTION; continue; @@ -1818,7 +1828,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) * 1,-sin(1) --> 1 (1) * Here, just do * 1,-sin(1) --> 1,sin(1) - * just remove unary operator + * just remove unary opartor */ st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); pos -= 1; @@ -1842,21 +1852,9 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; left = 0; continue; - } else if ((sf->tokenvec[left].type == TYPE_FUNCTION) && - (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) && - (sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) { - /* - * whats going on here - * Some SQL functions like USER() have 0 args - * if we get User(foo), then User is not a function - * This should be expanded since it eliminated a lot of false - * positives. - */ - if (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) { - sf->tokenvec[left].type = TYPE_BAREWORD; - } } + /* no folding -- assume left-most token is is good, now use the existing 2 tokens -- do not get another @@ -2021,7 +2019,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state) } /* - * return TRUE if SQLi, false is benign + * return TRUE if sqli, false is benign */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) { @@ -2035,10 +2033,10 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { /* - * if ending comment is contains 'sp_password' then it's SQLi! + * if ending comment is contains 'sp_password' then it's sqli! * MS Audit log apparently ignores anything with - * 'sp_password' in it. Unable to find primary reference to - * this "feature" of SQL Server but seems to be known SQLi + * 'sp_password' in it. Unable to find primary refernece to + * this "feature" of SQL Server but seems to be known sqli * technique */ if (my_memmem(sql_state->s, sql_state->slen, @@ -2057,7 +2055,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->fingerprint[1] == TYPE_UNION) { if (sql_state->stats_tokens == 2) { - /* not sure why but 1U comes up in SQLi attack + /* not sure why but 1U comes up in Sqli attack * likely part of parameter splitting/etc. * lots of reasons why "1 union" might be normal * input, so beep only if other SQLi things are present @@ -2082,7 +2080,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) /* * for fingerprint like 'nc', only comments of /x are treated - * as SQL... ending comments of "--" and "#" are not SQLi + * as SQL... ending comments of "--" and "#" are not sqli */ if (sql_state->tokenvec[0].type == TYPE_BAREWORD && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2092,7 +2090,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * if '1c' ends with '/x' then it's SQLi + * if '1c' ends with '/x' then it's sqli */ if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2115,13 +2113,13 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT) { if (sql_state->stats_tokens > 2) { - /* we have some folding going on, highly likely SQLi */ + /* we have some folding going on, highly likely sqli */ sql_state->reason = __LINE__; return TRUE; } /* * we check that next character after the number is either whitespace, - * or '/' or a '-' ==> SQLi. + * or '/' or a '-' ==> sqli. */ ch = sql_state->s[sql_state->tokenvec[0].len]; if ( ch <= 32 ) { @@ -2143,7 +2141,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * detect obvious SQLi scans.. many people put '--' in plain text + * detect obvious sqli scans.. many people put '--' in plain text * so only detect if input ends with '--', e.g. 1-- but not 1-- foo */ if ((sql_state->tokenvec[1].len > 2) @@ -2179,7 +2177,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * not SQLi + * not sqli */ sql_state->reason = __LINE__; return FALSE; @@ -2188,8 +2186,8 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) streq(sql_state->fingerprint, "1&1") || streq(sql_state->fingerprint, "1&v") || streq(sql_state->fingerprint, "1&s")) { - /* 'sexy and 17' not SQLi - * 'sexy and 17<18' SQLi + /* 'sexy and 17' not sqli + * 'sexy and 17<18' sqli */ if (sql_state->stats_tokens == 3) { sql_state->reason = __LINE__; @@ -2245,7 +2243,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) size_t slen = sql_state->slen; /* - * no input? not SQLi + * no input? not sqli */ if (slen == 0) { return FALSE; diff --git a/apache2/libinjection/libinjection_sqli.h b/apache2/libinjection/libinjection_sqli.h index 749f7a44a3..b9746555a7 100644 --- a/apache2/libinjection/libinjection_sqli.h +++ b/apache2/libinjection/libinjection_sqli.h @@ -40,10 +40,6 @@ struct libinjection_sqli_token { #ifdef SWIG %immutable; #endif - char type; - char str_open; - char str_close; - /* * position and length of token * in original string @@ -57,6 +53,9 @@ struct libinjection_sqli_token { */ int count; + char type; + char str_open; + char str_close; char val[32]; }; diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h index 14b969e3de..f5e1454143 100644 --- a/apache2/libinjection/libinjection_sqli_data.h +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -445,6 +445,8 @@ static const keyword_t sql_keywords[] = { {"0&VUEN", 'F'}, {"0&VUES", 'F'}, {"0&VUEV", 'F'}, + {"0)&(EK", 'F'}, + {"0)&(EN", 'F'}, {"0)UE(1", 'F'}, {"0)UE(F", 'F'}, {"0)UE(N", 'F'}, @@ -585,6 +587,7 @@ static const keyword_t sql_keywords[] = { {"01&K(S", 'F'}, {"01&K(V", 'F'}, {"01&K1O", 'F'}, + {"01&KC", 'F'}, {"01&KF(", 'F'}, {"01&KNK", 'F'}, {"01&KO(", 'F'}, @@ -876,6 +879,7 @@ static const keyword_t sql_keywords[] = { {"01)KN&", 'F'}, {"01)KN;", 'F'}, {"01)KNB", 'F'}, + {"01)KNC", 'F'}, {"01)KNE", 'F'}, {"01)KNK", 'F'}, {"01)KNU", 'F'}, @@ -1002,6 +1006,7 @@ static const keyword_t sql_keywords[] = { {"01;EVT", 'F'}, {"01;N:T", 'F'}, {"01;T(1", 'F'}, + {"01;T(C", 'F'}, {"01;T(E", 'F'}, {"01;T(F", 'F'}, {"01;T(N", 'F'}, @@ -2105,6 +2110,8 @@ static const keyword_t sql_keywords[] = { {"01VUE;", 'F'}, {"01VUEC", 'F'}, {"01VUEK", 'F'}, + {"0;T(EF", 'F'}, + {"0;T(EK", 'F'}, {"0;TKNC", 'F'}, {"0E(1&(", 'F'}, {"0E(1&1", 'F'}, @@ -3691,6 +3698,7 @@ static const keyword_t sql_keywords[] = { {"0N&K(S", 'F'}, {"0N&K(V", 'F'}, {"0N&K1O", 'F'}, + {"0N&KC", 'F'}, {"0N&KF(", 'F'}, {"0N&KNK", 'F'}, {"0N&KO(", 'F'}, @@ -3968,6 +3976,7 @@ static const keyword_t sql_keywords[] = { {"0N)KN&", 'F'}, {"0N)KN;", 'F'}, {"0N)KNB", 'F'}, + {"0N)KNC", 'F'}, {"0N)KNE", 'F'}, {"0N)KNK", 'F'}, {"0N)KNU", 'F'}, @@ -4121,6 +4130,7 @@ static const keyword_t sql_keywords[] = { {"0N;EVT", 'F'}, {"0N;N:T", 'F'}, {"0N;T(1", 'F'}, + {"0N;T(C", 'F'}, {"0N;T(E", 'F'}, {"0N;T(F", 'F'}, {"0N;T(N", 'F'}, @@ -4206,12 +4216,16 @@ static const keyword_t sql_keywords[] = { {"0NAVOF", 'F'}, {"0NAVOS", 'F'}, {"0NAVUE", 'F'}, + {"0NB(1&", 'F'}, {"0NB(1)", 'F'}, {"0NB(1O", 'F'}, {"0NB(F(", 'F'}, + {"0NB(N&", 'F'}, {"0NB(NO", 'F'}, + {"0NB(S&", 'F'}, {"0NB(S)", 'F'}, {"0NB(SO", 'F'}, + {"0NB(V&", 'F'}, {"0NB(V)", 'F'}, {"0NB(VO", 'F'}, {"0NB1", 'F'}, @@ -5215,6 +5229,7 @@ static const keyword_t sql_keywords[] = { {"0S&K(S", 'F'}, {"0S&K(V", 'F'}, {"0S&K1O", 'F'}, + {"0S&KC", 'F'}, {"0S&KF(", 'F'}, {"0S&KNK", 'F'}, {"0S&KO(", 'F'}, @@ -5507,6 +5522,7 @@ static const keyword_t sql_keywords[] = { {"0S)KN&", 'F'}, {"0S)KN;", 'F'}, {"0S)KNB", 'F'}, + {"0S)KNC", 'F'}, {"0S)KNE", 'F'}, {"0S)KNK", 'F'}, {"0S)KNU", 'F'}, @@ -5654,6 +5670,7 @@ static const keyword_t sql_keywords[] = { {"0S;EVT", 'F'}, {"0S;N:T", 'F'}, {"0S;T(1", 'F'}, + {"0S;T(C", 'F'}, {"0S;T(E", 'F'}, {"0S;T(F", 'F'}, {"0S;T(N", 'F'}, @@ -7303,6 +7320,7 @@ static const keyword_t sql_keywords[] = { {"0V&K(S", 'F'}, {"0V&K(V", 'F'}, {"0V&K1O", 'F'}, + {"0V&KC", 'F'}, {"0V&KF(", 'F'}, {"0V&KNK", 'F'}, {"0V&KO(", 'F'}, @@ -7595,6 +7613,7 @@ static const keyword_t sql_keywords[] = { {"0V)KN&", 'F'}, {"0V)KN;", 'F'}, {"0V)KNB", 'F'}, + {"0V)KNC", 'F'}, {"0V)KNE", 'F'}, {"0V)KNK", 'F'}, {"0V)KNU", 'F'}, @@ -7722,6 +7741,7 @@ static const keyword_t sql_keywords[] = { {"0V;EVT", 'F'}, {"0V;N:T", 'F'}, {"0V;T(1", 'F'}, + {"0V;T(C", 'F'}, {"0V;T(E", 'F'}, {"0V;T(F", 'F'}, {"0V;T(N", 'F'}, @@ -8871,6 +8891,7 @@ static const keyword_t sql_keywords[] = { {"DAY_SECOND", 'k'}, {"DBMS_LOCK.SLEEP", 'f'}, {"DBMS_PIPE.RECEIVE_MESSAGE", 'f'}, + {"DBMS_UTILITY.SQLID_TO_SQLHASH", 'f'}, {"DB_ID", 'f'}, {"DB_NAME", 'f'}, {"DCOUNT", 'f'}, @@ -9018,7 +9039,7 @@ static const keyword_t sql_keywords[] = { {"IDENT_SEED", 'f'}, {"IF", 'f'}, {"IF EXISTS", 'f'}, - {"IF NOT", 'n'}, + {"IF NOT", 'f'}, {"IF NOT EXISTS", 'f'}, {"IFF", 'f'}, {"IFNULL", 'f'}, @@ -9395,6 +9416,7 @@ static const keyword_t sql_keywords[] = { {"SPLIT_PART", 'f'}, {"SQL", 'k'}, {"SQLEXCEPTION", 'k'}, + {"SQLITE_VERSION", 'f'}, {"SQLSTATE", 'k'}, {"SQLWARNING", 'k'}, {"SQL_BIG_RESULT", 'k'}, @@ -9626,5 +9648,5 @@ static const keyword_t sql_keywords[] = { {"||", '&'}, {"~*", 'o'}, }; -static const size_t sql_keywords_sz = 9330; +static const size_t sql_keywords_sz = 9352; #endif diff --git a/apache2/libinjection/libinjection_xss.c b/apache2/libinjection/libinjection_xss.c index e89b336ed9..9aac0e451f 100644 --- a/apache2/libinjection/libinjection_xss.c +++ b/apache2/libinjection/libinjection_xss.c @@ -1,11 +1,15 @@ - -#include "libinjection.h" #include "libinjection_xss.h" #include "libinjection_html5.h" #include <assert.h> #include <stdio.h> +/* + * HEY THIS ISN'T DONE + * AND MISSING A KEY INGREDIENT!! + * + */ + typedef enum attribute { TYPE_NONE , TYPE_BLACK /* ban always */ @@ -14,128 +18,11 @@ typedef enum attribute { , TYPE_ATTR_INDIRECT /* attribute *name* is given in *value* */ } attribute_t; - -static attribute_t is_black_attr(const char* s, size_t len); -static int is_black_tag(const char* s, size_t len); -static int is_black_url(const char* s, size_t len); -static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); -static int html_decode_char_at(const char* src, size_t len, size_t* consumed); -static int htmlencode_startswith(const char* prefix, const char *src, size_t n); - - typedef struct stringtype { const char* name; attribute_t atype; } stringtype_t; - -static const int gsHexDecodeMap[256] = { - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, - 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256 -}; - -static int html_decode_char_at(const char* src, size_t len, size_t* consumed) -{ - int val = 0; - size_t i; - int ch; - - if (len == 0 || src == NULL) { - *consumed = 0; - return -1; - } - - *consumed = 1; - if (*src != '&' || len < 2) { - return (unsigned char)(*src); - } - - - if (*(src+1) != '#') { - /* normally this would be for named entities - * but for this case we don't actually care - */ - return '&'; - } - - if (*(src+2) == 'x' || *(src+2) == 'X') { - ch = (unsigned char) (*(src+3)); - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - /* degenerate case '&#[?]' */ - return '&'; - } - val = ch; - i = 4; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - *consumed = i; - return val; - } - val = (val * 16) + ch; - if (val > 0x1000FF) { - return '&'; - } - ++i; - } - *consumed = i; - return val; - } else { - i = 2; - ch = (unsigned char) src[i]; - if (ch < '0' || ch > '9') { - return '&'; - } - val = ch - '0'; - i += 1; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - if (ch < '0' || ch > '9') { - *consumed = i; - return val; - } - val = (val * 10) + (ch - '0'); - if (val > 0x1000FF) { - return '&'; - } - ++i; - } - *consumed = i; - return val; - } -} - - /* * view-source: * data: @@ -150,7 +37,7 @@ static stringtype_t BLACKATTR[] = { , { "DATASRC", TYPE_BLACK } /* IE */ , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */ - , { "FORMACTION", TYPE_ATTR_URL } /* HTML 5 */ + , { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */ , { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */ , { "FROM", TYPE_ATTR_URL } /* SVG */ , { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */ @@ -166,27 +53,26 @@ static stringtype_t BLACKATTR[] = { }; /* xmlns */ -/* `xml-stylesheet` > <eval>, <if expr=> */ +/* xml-stylesheet > <eval>, <if expr=> */ /* - static const char* BLACKATTR[] = { - "ATTRIBUTENAME", - "BACKGROUND", - "DATAFORMATAS", - "HREF", - "SCROLL", - "SRC", - "STYLE", - "SRCDOC", - NULL - }; +static const char* BLACKATTR[] = { + "ATTRIBUTENAME", + "BACKGROUND", + "DATAFORMATAS", + "HREF", + "SCROLL", + "SRC", + "STYLE", + "SRCDOC", + NULL +}; */ static const char* BLACKTAG[] = { "APPLET" /* , "AUDIO" */ , "BASE" - , "COMMENT" /* IE http://html5sec.org/#38 */ , "EMBED" /* , "FORM" */ , "FRAME" @@ -206,94 +92,33 @@ static const char* BLACKTAG[] = { /* , "VIDEO" */ , "VMLFRAME" , "XML" - , "XSS" , NULL }; +static int is_black_tag(const char* s, size_t len); +static attribute_t is_black_attr(const char* s, size_t len); +static int is_black_url(const char* s, size_t len); +static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) { - char ca; char cb; - /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ - while (n-- > 0) { - cb = *b++; - if (cb == '\0') continue; - - ca = *a++; - - if (cb >= 'a' && cb <= 'z') { - cb -= 0x20; - } - /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ - if (ca != cb) { - return 1; - } - } - - if (*a == 0) { - /* printf(" MATCH \n"); */ - return 0; - } else { - return 1; - } -} - -/* - * Does an HTML encoded binary string (const char*, length) start with - * a all uppercase c-string (null terminated), case insensitive! - * - * also ignore any embedded nulls in the HTML string! - * - * return 1 if match / starts with - * return 0 if not - */ -static int htmlencode_startswith(const char *a, const char *b, size_t n) -{ - size_t consumed; - int cb; - int first = 1; - /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ - while (n > 0) { - if (*a == 0) { - /* printf("Match EOL!\n"); */ - return 1; - } - cb = html_decode_char_at(b, n, &consumed); - b += consumed; - n -= consumed; - if (first && cb <= 32) { - /* ignore all leading whitespace and control characters */ - continue; - } - first = 0; - - if (cb == 0) { - /* always ignore null characters in user input */ - continue; - } - - if (cb == 10) { - /* always ignore vertical tab characters in user input */ - /* who allows this?? */ - continue; - } + for (; n > 0; a++, b++, n--) { + cb = *b; + if (cb == '\0') continue; if (cb >= 'a' && cb <= 'z') { - /* upcase */ cb -= 0x20; } - - if (*a != (char) cb) { - /* printf(" %c != %c\n", *a, cb); */ - /* mismatch */ - return 0; + if (*a != cb) { + return *a - cb; + } else if (*a == '\0') { + return -1; } - a++; } - return (*a == 0) ? 1 : 0; + return (*a == 0) ? 0 : 1; } static int is_black_tag(const char* s, size_t len) @@ -307,7 +132,6 @@ static int is_black_tag(const char* s, size_t len) black = BLACKTAG; while (*black != NULL) { if (cstrcasecmp_with_null(*black, s, len) == 0) { - /* printf("Got black tag %s\n", *black); */ return 1; } black += 1; @@ -317,7 +141,6 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'v' || s[1] == 'V') && (s[2] == 'g' || s[2] == 'G')) { - /* printf("Got SVG tag \n"); */ return 1; } @@ -325,7 +148,6 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 'x' || s[0] == 'X') && (s[1] == 's' || s[1] == 'S') && (s[2] == 'l' || s[2] == 'L')) { - /* printf("Got XSL tag\n"); */ return 1; } @@ -340,9 +162,8 @@ static attribute_t is_black_attr(const char* s, size_t len) return TYPE_NONE; } - /* JavaScript on.* */ + /* javascript on.* */ if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { - /* printf("Got JavaScript on- attribute name\n"); */ return TYPE_BLACK; } @@ -350,7 +171,6 @@ static attribute_t is_black_attr(const char* s, size_t len) if (len >= 5) { /* XMLNS can be used to create arbitrary tags */ if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) { - /* printf("Got XMLNS and XLINK tags\n"); */ return TYPE_BLACK; } } @@ -358,7 +178,6 @@ static attribute_t is_black_attr(const char* s, size_t len) black = BLACKATTR; while (black->name != NULL) { if (cstrcasecmp_with_null(black->name, s, len) == 0) { - /* printf("Got banned attribute name %s\n", black->name); */ return black->atype; } black += 1; @@ -379,43 +198,49 @@ static int is_black_url(const char* s, size_t len) /* covers JAVA, JAVASCRIPT, + colon */ static const char* javascript_url = "JAVA"; + size_t tokenlen; + /* skip whitespace */ - while (len > 0 && (*s <= 32 || *s >= 127)) { + while (len > 0) { /* * HEY: this is a signed character. * We are intentionally skipping high-bit characters too - * since they are not ASCII, and Opera sometimes uses UTF-8 whitespace. - * - * Also in EUC-JP some of the high bytes are just ignored. + * since they are not ascii, and Opera sometimes uses UTF8 whitespace */ - ++s; - --len; + if (*s <= 32) { + ++s; + --len; + } + break; } - if (htmlencode_startswith(data_url, s, len)) { + tokenlen = strlen(data_url); + if (len > tokenlen && cstrcasecmp_with_null(data_url, s, tokenlen) == 0) { return 1; } - - if (htmlencode_startswith(viewsource_url, s, len)) { + tokenlen = strlen(viewsource_url); + if (len > tokenlen && cstrcasecmp_with_null(viewsource_url, s, tokenlen) == 0) { return 1; } - if (htmlencode_startswith(javascript_url, s, len)) { + tokenlen = strlen(javascript_url); + if (len > tokenlen && cstrcasecmp_with_null(javascript_url, s, tokenlen) == 0) { return 1; } - if (htmlencode_startswith(vbscript_url, s, len)) { + tokenlen = strlen(vbscript_url); + if (len > tokenlen && cstrcasecmp_with_null(vbscript_url, s, tokenlen) == 0) { return 1; } return 0; } -int libinjection_is_xss(const char* s, size_t len, int flags) +int libinjection_is_xss(const char* s, size_t len) { h5_state_t h5; attribute_t attr = TYPE_NONE; - libinjection_h5_init(&h5, s, len, (enum html5_flags) flags); + libinjection_h5_init(&h5, s, len, 0); while (libinjection_h5_next(&h5)) { if (h5.token_type != ATTR_VALUE) { attr = TYPE_NONE; @@ -433,16 +258,16 @@ int libinjection_is_xss(const char* s, size_t len, int flags) /* * IE6,7,8 parsing works a bit differently so * a whole <script> or other black tag might be hiding - * inside an attribute value under HTML 5 parsing + * inside an attribute value under HTML5 parsing * See http://html5sec.org/#102 * to avoid doing a full reparse of the value, just * look for "<". This probably need adjusting to * handle escaped characters */ /* - if (memchr(h5.token_start, '<', h5.token_len) != NULL) { - return 1; - } + if (memchr(h5.token_start, '<', h5.token_len) != NULL) { + return 1; + } */ switch (attr) { @@ -464,13 +289,13 @@ int libinjection_is_xss(const char* s, size_t len, int flags) } break; /* - default: - assert(0); + default: + assert(0); */ } attr = TYPE_NONE; } else if (h5.token_type == TAG_COMMENT) { - /* IE uses a "`" as a tag ending char */ + /* IE uses a "`" as a tag ending char */ if (memchr(h5.token_start, '`', h5.token_len) != NULL) { return 1; } @@ -482,7 +307,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags) (h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) { return 1; } - if ((h5.token_start[0] == 'x' || h5.token_start[0] == 'X') && + if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') && (h5.token_start[1] == 'm' || h5.token_start[1] == 'M') && (h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) { return 1; @@ -490,7 +315,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags) } if (h5.token_len > 5) { - /* IE <?import pseudo-tag */ + /* IE <?import pseudo-tag */ if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) { return 1; } @@ -504,28 +329,3 @@ int libinjection_is_xss(const char* s, size_t len, int flags) } return 0; } - - -/* - * wrapper - */ -int libinjection_xss(const char* s, size_t len) -{ - if (libinjection_is_xss(s, len, DATA_STATE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) { - return 1; - } - if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) { - return 1; - } - - return 0; -} From 9c0229ce1f563e09d9c0de3503f9d6b8a8d9a678 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 31 May 2017 21:04:55 -0300 Subject: [PATCH 138/477] Updates libinjection to v3.10.0 --- CHANGES | 4 +- apache2/libinjection/libinjection_html5.c | 146 ++++++++-- apache2/libinjection/libinjection_sqli.c | 157 ++++++----- apache2/libinjection/libinjection_xss.c | 329 +++++++++++++++++----- 4 files changed, 473 insertions(+), 163 deletions(-) diff --git a/CHANGES b/CHANGES index b297792ed6..74682793fd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ - * Updates libinjection to: bf234eb2f385b969c4f803b35fda53cffdd93922 - [Issue #1412 - @zimmerle, @bjdijk] + * Updates libinjection to v3.10.0 + [Issue #1412 - @client9, @zimmerle and @bjdijk] * Avoid log flood while using SecConnEngine [Issue #1436 - @victorhora] * Make url path absolute for SecHashEngine only when it is relative diff --git a/apache2/libinjection/libinjection_html5.c b/apache2/libinjection/libinjection_html5.c index 65565101ba..a380ca0ad6 100644 --- a/apache2/libinjection/libinjection_html5.c +++ b/apache2/libinjection/libinjection_html5.c @@ -12,6 +12,7 @@ #define CHAR_EOF -1 +#define CHAR_NULL 0 #define CHAR_BANG 33 #define CHAR_DOUBLE 34 #define CHAR_PERCENT 37 @@ -23,6 +24,7 @@ #define CHAR_GT 62 #define CHAR_QUESTION 63 #define CHAR_RIGHTB 93 +#define CHAR_TICK 96 /* prototypes */ @@ -41,6 +43,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs); static int h5_state_before_attribute_value(h5_state_t* hs); static int h5_state_attribute_value_double_quote(h5_state_t* hs); static int h5_state_attribute_value_single_quote(h5_state_t* hs); +static int h5_state_attribute_value_back_quote(h5_state_t* hs); static int h5_state_attribute_value_no_quote(h5_state_t* hs); static int h5_state_after_attribute_value_quoted_state(h5_state_t* hs); static int h5_state_comment(h5_state_t* hs); @@ -60,16 +63,28 @@ static int h5_state_doctype(h5_state_t* hs); /** * public function */ -void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, int flags) +void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_flags flags) { memset(hs, 0, sizeof(h5_state_t)); hs->s = s; hs->len = len; - hs->state = h5_state_data; - if (flags == 0) { + + switch (flags) { + case DATA_STATE: hs->state = h5_state_data; - } else { - assert(0); + break; + case VALUE_NO_QUOTE: + hs->state = h5_state_before_attribute_name; + break; + case VALUE_SINGLE_QUOTE: + hs->state = h5_state_attribute_value_single_quote; + break; + case VALUE_DOUBLE_QUOTE: + hs->state = h5_state_attribute_value_double_quote; + break; + case VALUE_BACK_QUOTE: + hs->state = h5_state_attribute_value_back_quote; + break; } } @@ -85,10 +100,18 @@ int libinjection_h5_next(h5_state_t* hs) /** * Everything below here is private * -*/ + */ + static int h5_is_white(char ch) { + /* + * \t = horizontal tab = 0x09 + * \n = newline = 0x0A + * \v = vertical tab = 0x0B + * \f = form feed = 0x0C + * \r = cr = 0x0D + */ return strchr(" \t\n\v\f\r", ch) != NULL; } @@ -97,9 +120,17 @@ static int h5_skip_white(h5_state_t* hs) char ch; while (hs->pos < hs->len) { ch = hs->s[hs->pos]; - if (ch == ' ') { + switch (ch) { + case 0x00: /* IE only */ + case 0x20: + case 0x09: + case 0x0A: + case 0x0B: /* IE only */ + case 0x0C: + case 0x0D: /* IE only */ hs->pos += 1; - } else { + break; + default: return ch; } } @@ -149,6 +180,9 @@ static int h5_state_tag_open(h5_state_t* hs) char ch; TRACE(); + if (hs->pos >= hs->len) { + return 0; + } ch = hs->s[hs->pos]; if (ch == CHAR_BANG) { hs->pos += 1; @@ -167,6 +201,9 @@ static int h5_state_tag_open(h5_state_t* hs) return h5_state_bogus_comment2(hs); } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { return h5_state_tag_name(hs); + } else if (ch == CHAR_NULL) { + /* IE-ism NULL characters are ignored */ + return h5_state_tag_name(hs); } else { /* user input mistake in configuring state */ if (hs->pos == 0) { @@ -197,7 +234,9 @@ static int h5_state_end_tag_open(h5_state_t* hs) } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { return h5_state_tag_name(hs); } - return h5_state_data(hs); + + hs->is_close = 0; + return h5_state_bogus_comment(hs); } /* * @@ -231,7 +270,12 @@ static int h5_state_tag_name(h5_state_t* hs) pos = hs->pos; while (pos < hs->len) { ch = hs->s[pos]; - if (h5_is_white(ch)) { + if (ch == 0) { + /* special non-standard case */ + /* allow nulls in tag name */ + /* some old browsers apparently allow and ignore them */ + pos += 1; + } else if (h5_is_white(ch)) { hs->token_start = hs->s + hs->pos; hs->token_len = pos - hs->pos; hs->token_type = TAG_NAME_OPEN; @@ -299,7 +343,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs) default: { return h5_state_attribute_name(hs); } - } + } } static int h5_state_attribute_name(h5_state_t* hs) @@ -308,7 +352,7 @@ static int h5_state_attribute_name(h5_state_t* hs) size_t pos; TRACE(); - pos = hs->pos; + pos = hs->pos + 1; while (pos < hs->len) { ch = hs->s[pos]; if (h5_is_white(ch)) { @@ -358,21 +402,19 @@ static int h5_state_attribute_name(h5_state_t* hs) static int h5_state_after_attribute_name(h5_state_t* hs) { int c; - size_t pos; TRACE(); - pos = hs->pos; c = h5_skip_white(hs); switch (c) { case CHAR_EOF: { return 0; } case CHAR_SLASH: { - hs->pos = pos + 1; + hs->pos += 1; return h5_state_self_closing_start_tag(hs); } case CHAR_EQUALS: { - hs->pos = pos + 1; + hs->pos += 1; return h5_state_before_attribute_value(hs); } case CHAR_GT: { @@ -403,6 +445,9 @@ static int h5_state_before_attribute_value(h5_state_t* hs) return h5_state_attribute_value_double_quote(hs); } else if (c == CHAR_SINGLE) { return h5_state_attribute_value_single_quote(hs); + } else if (c == CHAR_TICK) { + /* NON STANDARD IE */ + return h5_state_attribute_value_back_quote(hs); } else { return h5_state_attribute_value_no_quote(hs); } @@ -415,8 +460,16 @@ static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar) TRACE(); - /* skip quote */ - hs->pos += 1; + /* skip initial quote in normal case. + * don't do this "if (pos == 0)" since it means we have started + * in a non-data state. given an input of '><foo + * we want to make 0-length attribute name + */ + if (hs->pos > 0) { + hs->pos += 1; + } + + idx = (const char*) memchr(hs->s + hs->pos, qchar, hs->len - hs->pos); if (idx == NULL) { hs->token_start = hs->s + hs->pos; @@ -447,6 +500,13 @@ int h5_state_attribute_value_single_quote(h5_state_t* hs) return h5_state_attribute_value_quote(hs, CHAR_SINGLE); } +static +int h5_state_attribute_value_back_quote(h5_state_t* hs) +{ + TRACE(); + return h5_state_attribute_value_quote(hs, CHAR_TICK); +} + static int h5_state_attribute_value_no_quote(h5_state_t* hs) { char ch; @@ -656,10 +716,13 @@ static int h5_state_comment(h5_state_t* hs) char ch; const char* idx; size_t pos; + size_t offset; + const char* end = hs->s + hs->len; TRACE(); pos = hs->pos; while (1) { + idx = (const char*) memchr(hs->s + pos, CHAR_DASH, hs->len - pos); /* did not find anything or has less than 3 chars left */ @@ -670,21 +733,62 @@ static int h5_state_comment(h5_state_t* hs) hs->token_type = TAG_COMMENT; return 1; } - ch = *(idx + 1); + offset = 1; + + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + ch = *(idx + offset); if (ch != CHAR_DASH && ch != CHAR_BANG) { pos = (size_t)(idx - hs->s) + 1; continue; } - ch = *(idx + 2); + + /* need to test */ +#if 0 + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } +#endif + + offset += 1; + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + + ch = *(idx + offset); if (ch != CHAR_GT) { pos = (size_t)(idx - hs->s) + 1; continue; } + offset += 1; /* ends in --> or -!> */ hs->token_start = hs->s + hs->pos; hs->token_len = (size_t)(idx - hs->s) - hs->pos; - hs->pos = (size_t)(idx - hs->s) + 3; + hs->pos = (size_t)(idx + offset - hs->s); hs->state = h5_state_data; hs->token_type = TAG_COMMENT; return 1; diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index 0b67c5cc49..cecbbea3fb 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -1,5 +1,5 @@ /** - * Copyright 2012,2013 Nick Galbreath + * Copyright 2012,2016 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -18,7 +18,7 @@ #include "libinjection_sqli.h" #include "libinjection_sqli_data.h" -#define LIBINJECTION_VERSION "3.9.1" +#define LIBINJECTION_VERSION "3.9.2" #define LIBINJECTION_SQLI_TOKEN_SIZE sizeof(((stoken_t*)(0))->val) #define LIBINJECTION_SQLI_MAX_TOKENS 5 @@ -112,15 +112,11 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) } while (cur < last) { - if (cur[0] == c0) { - if (cur[1] == c1) { - return cur; - } else { - cur += 2; /* (c0 == c1) ? 1 : 2; */ - } - } else { - cur += 1; + /* safe since cur < len - 1 always */ + if (cur[0] == c0 && cur[1] == c1) { + return cur; } + cur += 1; } return NULL; @@ -191,11 +187,11 @@ static int char_is_white(char ch) { /* ' ' space is 0x32 '\t 0x09 \011 horizontal tab '\n' 0x0a \012 new line - '\v' 0x0b \013 verical tab + '\v' 0x0b \013 vertical tab '\f' 0x0c \014 new page '\r' 0x0d \015 carriage return 0x00 \000 null (oracle) - 0xa0 \240 is latin1 + 0xa0 \240 is Latin-1 */ return strchr(" \t\n\v\f\r\240\000", ch) != NULL; } @@ -294,7 +290,7 @@ static void st_clear(stoken_t * st) static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len, const char value) { - /* done to elimiate unused warning */ + /* done to eliminate unused warning */ (void)len; st->type = (char) stype; st->pos = pos; @@ -402,7 +398,7 @@ static size_t parse_eol_comment(struct libinjection_sqli_state * sf) } } -/** In Ansi mode, hash is an operator +/** In ANSI mode, hash is an operator * In MYSQL mode, it's a EOL comment like '--' */ static size_t parse_hash(struct libinjection_sqli_state * sf) @@ -842,7 +838,7 @@ static size_t parse_bstring(struct libinjection_sqli_state *sf) /* * hex literal string - * re: [XX]'[0123456789abcdefABCDEF]*' + * re: [xX]'[0123456789abcdefABCDEF]*' * mysql has requirement of having EVEN number of chars, * but pgsql does not */ @@ -1072,7 +1068,7 @@ static size_t parse_money(struct libinjection_sqli_state *sf) /* we have $foobar$ ... find it again */ strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); - if (strend == NULL) { + if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { /* fell off edge */ st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); sf->current->str_open = '$'; @@ -1104,7 +1100,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; - int have_dot = 0; int have_e = 0; int have_exp = 0; @@ -1136,7 +1131,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } if (pos < slen && cs[pos] == '.') { - have_dot = 1; pos += 1; while (pos < slen && ISDIGIT(cs[pos])) { pos += 1; @@ -1185,7 +1179,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } } - if (have_dot == 1 && have_e == 1 && have_exp == 0) { + if (have_e == 1 && have_exp == 0) { /* very special form of * "1234.e" * "10.10E" @@ -1242,29 +1236,13 @@ int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) const unsigned char ch = (unsigned char) (s[*pos]); /* - * if not ascii, then continue... - * actually probably need to just assuming - * it's a string + * look up the parser, and call it + * + * Porting Note: this is mapping of char to function + * charparsers[ch]() */ - if (ch > 127) { + fnptr = char_parse_map[ch]; - /* 160 or 0xA0 or octal 240 is "latin1 non-breaking space" - * but is treated as a space in mysql. - */ - if (ch == 160) { - fnptr = parse_white; - } else { - fnptr = parse_word; - } - } else { - /* - * look up the parser, and call it - * - * Porting Note: this is mapping of char to function - * charparsers[ch]() - */ - fnptr = char_parse_map[ch]; - } *pos = (*fnptr) (sf); /* @@ -1349,16 +1327,22 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, a->type == TYPE_UNION || a->type == TYPE_FUNCTION || a->type == TYPE_EXPRESSION || + a->type == TYPE_TSQL || a->type == TYPE_SQLTYPE)) { - return CHAR_NULL; + return FALSE; } - if (b->type != TYPE_KEYWORD && b->type != TYPE_BAREWORD && - b->type != TYPE_OPERATOR && b->type != TYPE_SQLTYPE && - b->type != TYPE_LOGIC_OPERATOR && - b->type != TYPE_FUNCTION && - b->type != TYPE_UNION && b->type != TYPE_EXPRESSION) { - return CHAR_NULL; + if (! + (b->type == TYPE_KEYWORD || + b->type == TYPE_BAREWORD || + b->type == TYPE_OPERATOR || + b->type == TYPE_UNION || + b->type == TYPE_FUNCTION || + b->type == TYPE_EXPRESSION || + b->type == TYPE_TSQL || + b->type == TYPE_SQLTYPE || + b->type == TYPE_LOGIC_OPERATOR)) { + return FALSE; } sz1 = a->len; @@ -1374,7 +1358,6 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, tmp[sz1] = ' '; memcpy(tmp + sz1 + 1, b->val, sz2); tmp[sz3] = CHAR_NULL; - ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3); if (ch != CHAR_NULL) { @@ -1450,6 +1433,13 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) sf->tokenvec[2].type == TYPE_COMMA && sf->tokenvec[3].type == TYPE_LEFTPARENS && sf->tokenvec[4].type == TYPE_NUMBER + ) || + ( + sf->tokenvec[0].type == TYPE_BAREWORD && + sf->tokenvec[1].type == TYPE_RIGHTPARENS && + sf->tokenvec[2].type == TYPE_OPERATOR && + sf->tokenvec[3].type == TYPE_LEFTPARENS && + sf->tokenvec[4].type == TYPE_BAREWORD ) ) { @@ -1506,16 +1496,6 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; sf->stats_folds += 1; continue; - } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && - sf->tokenvec[left+1].type == TYPE_FUNCTION && - cstrcasecmp("IF", sf->tokenvec[left+1].val, sf->tokenvec[left+1].len) == 0) { - /* IF is normally a function, except in Transact-SQL where it can be used as a - * standalone control flow operator, e.g. ; IF 1=1 ... - * if found after a semicolon, convert from 'f' type to 'T' type - */ - sf->tokenvec[left+1].type = TYPE_TSQL; - left += 2; - continue; /* reparse everything, but we probably can advance left, and pos */ } else if ((sf->tokenvec[left].type == TYPE_OPERATOR || sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR) && (st_is_unary_op(&sf->tokenvec[left+1]) || @@ -1539,9 +1519,22 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) left -= 1; } continue; + } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && + sf->tokenvec[left+1].type == TYPE_FUNCTION && + (sf->tokenvec[left+1].val[0] == 'I' || + sf->tokenvec[left+1].val[0] == 'i' ) && + (sf->tokenvec[left+1].val[1] == 'F' || + sf->tokenvec[left+1].val[1] == 'f' )) { + /* IF is normally a function, except in Transact-SQL where it can be used as a + * standalone control flow operator, e.g. ; IF 1=1 ... + * if found after a semicolon, convert from 'f' type to 'T' type + */ + sf->tokenvec[left+1].type = TYPE_TSQL; + /* left += 2; */ + continue; /* reparse everything, but we probably can advance left, and pos */ } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) && sf->tokenvec[left+1].type == TYPE_LEFTPARENS && ( - /* TSQL functions but common enough to be collumn names */ + /* TSQL functions but common enough to be column names */ cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || @@ -1564,7 +1557,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) /* pos is the same * other conversions need to go here... for instance - * password CAN be a function, coalese CAN be a function + * password CAN be a function, coalesce CAN be a function */ sf->tokenvec[left].type = TYPE_FUNCTION; continue; @@ -1828,7 +1821,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) * 1,-sin(1) --> 1 (1) * Here, just do * 1,-sin(1) --> 1,sin(1) - * just remove unary opartor + * just remove unary operator */ st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); pos -= 1; @@ -1852,9 +1845,21 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; left = 0; continue; + } else if ((sf->tokenvec[left].type == TYPE_FUNCTION) && + (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) && + (sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) { + /* + * whats going on here + * Some SQL functions like USER() have 0 args + * if we get User(foo), then User is not a function + * This should be expanded since it eliminated a lot of false + * positives. + */ + if (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) { + sf->tokenvec[left].type = TYPE_BAREWORD; + } } - /* no folding -- assume left-most token is is good, now use the existing 2 tokens -- do not get another @@ -2019,7 +2024,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state) } /* - * return TRUE if sqli, false is benign + * return TRUE if SQLi, false is benign */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) { @@ -2033,10 +2038,10 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { /* - * if ending comment is contains 'sp_password' then it's sqli! + * if ending comment is contains 'sp_password' then it's SQLi! * MS Audit log apparently ignores anything with - * 'sp_password' in it. Unable to find primary refernece to - * this "feature" of SQL Server but seems to be known sqli + * 'sp_password' in it. Unable to find primary reference to + * this "feature" of SQL Server but seems to be known SQLi * technique */ if (my_memmem(sql_state->s, sql_state->slen, @@ -2055,7 +2060,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->fingerprint[1] == TYPE_UNION) { if (sql_state->stats_tokens == 2) { - /* not sure why but 1U comes up in Sqli attack + /* not sure why but 1U comes up in SQLi attack * likely part of parameter splitting/etc. * lots of reasons why "1 union" might be normal * input, so beep only if other SQLi things are present @@ -2080,7 +2085,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) /* * for fingerprint like 'nc', only comments of /x are treated - * as SQL... ending comments of "--" and "#" are not sqli + * as SQL... ending comments of "--" and "#" are not SQLi */ if (sql_state->tokenvec[0].type == TYPE_BAREWORD && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2090,7 +2095,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * if '1c' ends with '/x' then it's sqli + * if '1c' ends with '/x' then it's SQLi */ if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2113,13 +2118,13 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT) { if (sql_state->stats_tokens > 2) { - /* we have some folding going on, highly likely sqli */ + /* we have some folding going on, highly likely SQLi */ sql_state->reason = __LINE__; return TRUE; } /* * we check that next character after the number is either whitespace, - * or '/' or a '-' ==> sqli. + * or '/' or a '-' ==> SQLi. */ ch = sql_state->s[sql_state->tokenvec[0].len]; if ( ch <= 32 ) { @@ -2141,7 +2146,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * detect obvious sqli scans.. many people put '--' in plain text + * detect obvious SQLi scans.. many people put '--' in plain text * so only detect if input ends with '--', e.g. 1-- but not 1-- foo */ if ((sql_state->tokenvec[1].len > 2) @@ -2177,7 +2182,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * not sqli + * not SQLi */ sql_state->reason = __LINE__; return FALSE; @@ -2186,8 +2191,8 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) streq(sql_state->fingerprint, "1&1") || streq(sql_state->fingerprint, "1&v") || streq(sql_state->fingerprint, "1&s")) { - /* 'sexy and 17' not sqli - * 'sexy and 17<18' sqli + /* 'sexy and 17' not SQLi + * 'sexy and 17<18' SQLi */ if (sql_state->stats_tokens == 3) { sql_state->reason = __LINE__; @@ -2243,7 +2248,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) size_t slen = sql_state->slen; /* - * no input? not sqli + * no input? not SQLi */ if (slen == 0) { return FALSE; diff --git a/apache2/libinjection/libinjection_xss.c b/apache2/libinjection/libinjection_xss.c index 9aac0e451f..f0df4d84ac 100644 --- a/apache2/libinjection/libinjection_xss.c +++ b/apache2/libinjection/libinjection_xss.c @@ -1,15 +1,11 @@ + +#include "libinjection.h" #include "libinjection_xss.h" #include "libinjection_html5.h" #include <assert.h> #include <stdio.h> -/* - * HEY THIS ISN'T DONE - * AND MISSING A KEY INGREDIENT!! - * - */ - typedef enum attribute { TYPE_NONE , TYPE_BLACK /* ban always */ @@ -18,11 +14,128 @@ typedef enum attribute { , TYPE_ATTR_INDIRECT /* attribute *name* is given in *value* */ } attribute_t; + +static attribute_t is_black_attr(const char* s, size_t len); +static int is_black_tag(const char* s, size_t len); +static int is_black_url(const char* s, size_t len); +static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); +static int html_decode_char_at(const char* src, size_t len, size_t* consumed); +static int htmlencode_startswith(const char* prefix, const char *src, size_t n); + + typedef struct stringtype { const char* name; attribute_t atype; } stringtype_t; + +static const int gsHexDecodeMap[256] = { + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, + 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256 +}; + +static int html_decode_char_at(const char* src, size_t len, size_t* consumed) +{ + int val = 0; + size_t i; + int ch; + + if (len == 0 || src == NULL) { + *consumed = 0; + return -1; + } + + *consumed = 1; + if (*src != '&' || len < 2) { + return (unsigned char)(*src); + } + + + if (*(src+1) != '#') { + /* normally this would be for named entities + * but for this case we don't actually care + */ + return '&'; + } + + if (*(src+2) == 'x' || *(src+2) == 'X') { + ch = (unsigned char) (*(src+3)); + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + /* degenerate case '&#[?]' */ + return '&'; + } + val = ch; + i = 4; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + *consumed = i; + return val; + } + val = (val * 16) + ch; + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } else { + i = 2; + ch = (unsigned char) src[i]; + if (ch < '0' || ch > '9') { + return '&'; + } + val = ch - '0'; + i += 1; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + if (ch < '0' || ch > '9') { + *consumed = i; + return val; + } + val = (val * 10) + (ch - '0'); + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } +} + + /* * view-source: * data: @@ -37,7 +150,7 @@ static stringtype_t BLACKATTR[] = { , { "DATASRC", TYPE_BLACK } /* IE */ , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */ - , { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */ + , { "FORMACTION", TYPE_ATTR_URL } /* HTML 5 */ , { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */ , { "FROM", TYPE_ATTR_URL } /* SVG */ , { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */ @@ -53,26 +166,27 @@ static stringtype_t BLACKATTR[] = { }; /* xmlns */ -/* xml-stylesheet > <eval>, <if expr=> */ +/* `xml-stylesheet` > <eval>, <if expr=> */ /* -static const char* BLACKATTR[] = { - "ATTRIBUTENAME", - "BACKGROUND", - "DATAFORMATAS", - "HREF", - "SCROLL", - "SRC", - "STYLE", - "SRCDOC", - NULL -}; + static const char* BLACKATTR[] = { + "ATTRIBUTENAME", + "BACKGROUND", + "DATAFORMATAS", + "HREF", + "SCROLL", + "SRC", + "STYLE", + "SRCDOC", + NULL + }; */ static const char* BLACKTAG[] = { "APPLET" /* , "AUDIO" */ , "BASE" + , "COMMENT" /* IE http://html5sec.org/#38 */ , "EMBED" /* , "FORM" */ , "FRAME" @@ -92,33 +206,94 @@ static const char* BLACKTAG[] = { /* , "VIDEO" */ , "VMLFRAME" , "XML" + , "XSS" , NULL }; -static int is_black_tag(const char* s, size_t len); -static attribute_t is_black_attr(const char* s, size_t len); -static int is_black_url(const char* s, size_t len); -static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) { + char ca; char cb; - - for (; n > 0; a++, b++, n--) { - cb = *b; + /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ + while (n-- > 0) { + cb = *b++; if (cb == '\0') continue; + ca = *a++; + + if (cb >= 'a' && cb <= 'z') { + cb -= 0x20; + } + /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ + if (ca != cb) { + return 1; + } + } + + if (*a == 0) { + /* printf(" MATCH \n"); */ + return 0; + } else { + return 1; + } +} + +/* + * Does an HTML encoded binary string (const char*, length) start with + * a all uppercase c-string (null terminated), case insensitive! + * + * also ignore any embedded nulls in the HTML string! + * + * return 1 if match / starts with + * return 0 if not + */ +static int htmlencode_startswith(const char *a, const char *b, size_t n) +{ + size_t consumed; + int cb; + int first = 1; + /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ + while (n > 0) { + if (*a == 0) { + /* printf("Match EOL!\n"); */ + return 1; + } + cb = html_decode_char_at(b, n, &consumed); + b += consumed; + n -= consumed; + + if (first && cb <= 32) { + /* ignore all leading whitespace and control characters */ + continue; + } + first = 0; + + if (cb == 0) { + /* always ignore null characters in user input */ + continue; + } + + if (cb == 10) { + /* always ignore vertical tab characters in user input */ + /* who allows this?? */ + continue; + } + if (cb >= 'a' && cb <= 'z') { + /* upcase */ cb -= 0x20; } - if (*a != cb) { - return *a - cb; - } else if (*a == '\0') { - return -1; + + if (*a != (char) cb) { + /* printf(" %c != %c\n", *a, cb); */ + /* mismatch */ + return 0; } + a++; } - return (*a == 0) ? 0 : 1; + return (*a == 0) ? 1 : 0; } static int is_black_tag(const char* s, size_t len) @@ -132,6 +307,7 @@ static int is_black_tag(const char* s, size_t len) black = BLACKTAG; while (*black != NULL) { if (cstrcasecmp_with_null(*black, s, len) == 0) { + /* printf("Got black tag %s\n", *black); */ return 1; } black += 1; @@ -141,6 +317,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'v' || s[1] == 'V') && (s[2] == 'g' || s[2] == 'G')) { + /* printf("Got SVG tag \n"); */ return 1; } @@ -148,6 +325,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 'x' || s[0] == 'X') && (s[1] == 's' || s[1] == 'S') && (s[2] == 'l' || s[2] == 'L')) { + /* printf("Got XSL tag\n"); */ return 1; } @@ -162,15 +340,18 @@ static attribute_t is_black_attr(const char* s, size_t len) return TYPE_NONE; } - /* javascript on.* */ - if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { - return TYPE_BLACK; - } + if (len >= 5) { + /* JavaScript on.* */ + if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { + /* printf("Got JavaScript on- attribute name\n"); */ + return TYPE_BLACK; + } + - if (len >= 5) { /* XMLNS can be used to create arbitrary tags */ if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) { + /* printf("Got XMLNS and XLINK tags\n"); */ return TYPE_BLACK; } } @@ -178,6 +359,7 @@ static attribute_t is_black_attr(const char* s, size_t len) black = BLACKATTR; while (black->name != NULL) { if (cstrcasecmp_with_null(black->name, s, len) == 0) { + /* printf("Got banned attribute name %s\n", black->name); */ return black->atype; } black += 1; @@ -198,49 +380,43 @@ static int is_black_url(const char* s, size_t len) /* covers JAVA, JAVASCRIPT, + colon */ static const char* javascript_url = "JAVA"; - size_t tokenlen; - /* skip whitespace */ - while (len > 0) { + while (len > 0 && (*s <= 32 || *s >= 127)) { /* * HEY: this is a signed character. * We are intentionally skipping high-bit characters too - * since they are not ascii, and Opera sometimes uses UTF8 whitespace + * since they are not ASCII, and Opera sometimes uses UTF-8 whitespace. + * + * Also in EUC-JP some of the high bytes are just ignored. */ - if (*s <= 32) { - ++s; - --len; - } - break; + ++s; + --len; } - tokenlen = strlen(data_url); - if (len > tokenlen && cstrcasecmp_with_null(data_url, s, tokenlen) == 0) { + if (htmlencode_startswith(data_url, s, len)) { return 1; } - tokenlen = strlen(viewsource_url); - if (len > tokenlen && cstrcasecmp_with_null(viewsource_url, s, tokenlen) == 0) { + + if (htmlencode_startswith(viewsource_url, s, len)) { return 1; } - tokenlen = strlen(javascript_url); - if (len > tokenlen && cstrcasecmp_with_null(javascript_url, s, tokenlen) == 0) { + if (htmlencode_startswith(javascript_url, s, len)) { return 1; } - tokenlen = strlen(vbscript_url); - if (len > tokenlen && cstrcasecmp_with_null(vbscript_url, s, tokenlen) == 0) { + if (htmlencode_startswith(vbscript_url, s, len)) { return 1; } return 0; } -int libinjection_is_xss(const char* s, size_t len) +int libinjection_is_xss(const char* s, size_t len, int flags) { h5_state_t h5; attribute_t attr = TYPE_NONE; - libinjection_h5_init(&h5, s, len, 0); + libinjection_h5_init(&h5, s, len, (enum html5_flags) flags); while (libinjection_h5_next(&h5)) { if (h5.token_type != ATTR_VALUE) { attr = TYPE_NONE; @@ -258,16 +434,16 @@ int libinjection_is_xss(const char* s, size_t len) /* * IE6,7,8 parsing works a bit differently so * a whole <script> or other black tag might be hiding - * inside an attribute value under HTML5 parsing + * inside an attribute value under HTML 5 parsing * See http://html5sec.org/#102 * to avoid doing a full reparse of the value, just * look for "<". This probably need adjusting to * handle escaped characters */ /* - if (memchr(h5.token_start, '<', h5.token_len) != NULL) { - return 1; - } + if (memchr(h5.token_start, '<', h5.token_len) != NULL) { + return 1; + } */ switch (attr) { @@ -289,13 +465,13 @@ int libinjection_is_xss(const char* s, size_t len) } break; /* - default: - assert(0); + default: + assert(0); */ } attr = TYPE_NONE; } else if (h5.token_type == TAG_COMMENT) { - /* IE uses a "`" as a tag ending char */ + /* IE uses a "`" as a tag ending char */ if (memchr(h5.token_start, '`', h5.token_len) != NULL) { return 1; } @@ -307,7 +483,7 @@ int libinjection_is_xss(const char* s, size_t len) (h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) { return 1; } - if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') && + if ((h5.token_start[0] == 'x' || h5.token_start[0] == 'X') && (h5.token_start[1] == 'm' || h5.token_start[1] == 'M') && (h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) { return 1; @@ -315,7 +491,7 @@ int libinjection_is_xss(const char* s, size_t len) } if (h5.token_len > 5) { - /* IE <?import pseudo-tag */ + /* IE <?import pseudo-tag */ if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) { return 1; } @@ -329,3 +505,28 @@ int libinjection_is_xss(const char* s, size_t len) } return 0; } + + +/* + * wrapper + */ +int libinjection_xss(const char* s, size_t len) +{ + if (libinjection_is_xss(s, len, DATA_STATE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) { + return 1; + } + if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) { + return 1; + } + + return 0; +} From 5335587b95c275ad68b3c4b4b00dd9a80fbdbf2b Mon Sep 17 00:00:00 2001 From: Andrei Belov <defanator@gmail.com> Date: Thu, 15 May 2014 15:56:44 +0400 Subject: [PATCH 139/477] Obtain port from r->connection->local_sockaddr. This eliminates segfaults caused by unset (NULL) r->port_start and non-NULL r->port_end. In fact, r->port_start is always NULL, so it is useless to rely on this pointer. --- nginx/modsecurity/ngx_http_modsecurity.c | 34 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/nginx/modsecurity/ngx_http_modsecurity.c b/nginx/modsecurity/ngx_http_modsecurity.c index 367b2b8de3..d68cda312b 100644 --- a/nginx/modsecurity/ngx_http_modsecurity.c +++ b/nginx/modsecurity/ngx_http_modsecurity.c @@ -207,9 +207,13 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; - ngx_str_t str; size_t root; ngx_str_t path; + ngx_uint_t port; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; @@ -252,10 +256,30 @@ ngx_http_modsecurity_load_request(ngx_http_request_t *r) req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; - str.data = r->port_start; - str.len = r->port_end - r->port_start; - req->parsed_uri.port = ngx_atoi(str.data, str.len); - req->parsed_uri.port_str = (char *)ngx_pstrdup0(r->pool, &str); + switch (r->connection->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif + +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + port = 0; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->local_sockaddr; + port = ntohs(sin->sin_port); + break; + } + + req->parsed_uri.port = port; + req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535")); + (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0'); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; From 13b32aacdf5613cac8543a645ec0438e3217f5fc Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 1 Jun 2017 08:49:34 -0300 Subject: [PATCH 140/477] Updates CHANGES to mention commit: 551314 --- CHANGES | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 74682793fd..c51479a650 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ - + + * nginx: Obtain port from r->connection->local_sockaddr. + [Commit 51314 - @defanator] * Updates libinjection to v3.10.0 [Issue #1412 - @client9, @zimmerle and @bjdijk] * Avoid log flood while using SecConnEngine From 04e4a6f9b8b435b07f6a788f462c3950a14fbd57 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Fri, 16 Jun 2017 16:56:38 -0700 Subject: [PATCH 141/477] Initialize msre_var pointers --- apache2/re_variables.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index c69085feef..4007386151 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -2158,6 +2158,11 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_ msre_var *rvar = apr_palloc(mptmp, sizeof(msre_var)); + rvar->param = NULL; + rvar->param_data = NULL; + rvar->metadata = NULL; + rvar->param_regex = NULL; + rvar->value = apr_pstrndup(mptmp, str->name, strlen(str->name)); rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "%s", @@ -2218,6 +2223,11 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule * msre_var *rvar = apr_palloc(mptmp, sizeof(msre_var)); + rvar->param = NULL; + rvar->param_data = NULL; + rvar->metadata = NULL; + rvar->param_regex = NULL; + rvar->value = apr_pstrndup(mptmp, str->value, str->value_len); rvar->value_len = str->value_len; rvar->name = apr_psprintf(mptmp, "%s", From cb6dc9ea277f43014e659ba6e9877a0cde64fa66 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 23 Jun 2017 16:18:54 -0300 Subject: [PATCH 142/477] Updates CHANGES to mention commit: fbd57 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c51479a650..1bf23a3877 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.2 - To be released ------------------------------------ + * Best practice: Initialize msre_var pointers + [Commit fbd57 - Allan Boll] * nginx: Obtain port from r->connection->local_sockaddr. [Commit 51314 - @defanator] * Updates libinjection to v3.10.0 From 9f92321afb0037653d3eab0a5b35d429689836e3 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 14 Jul 2017 10:37:58 -0300 Subject: [PATCH 143/477] Fix test case to match new version of curl. Error message was changed --- tests/regression/misc/50-ipmatchfromfile-external.t.in | 2 +- tests/regression/misc/60-pmfromfile-external.t.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/misc/50-ipmatchfromfile-external.t.in b/tests/regression/misc/50-ipmatchfromfile-external.t.in index effe97bf32..6b674cabd0 100644 --- a/tests/regression/misc/50-ipmatchfromfile-external.t.in +++ b/tests/regression/misc/50-ipmatchfromfile-external.t.in @@ -65,7 +65,7 @@ SecRule REMOTE_ADDR "\@ipMatchFromFile https://status.modsecurity.org/modsecurity-regression-test-huge-ip-list.txt" "id:10500,pass" ), match_log => { - error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/status.modsecurity.org\/modsecurity-regression-test-huge-ip-list.txt\" error: SSL peer certificate or SSH remote key was not OK./, 1], + error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/status.modsecurity.org\/modsecurity-regression-test-huge-ip-list.txt\" error: [SSL peer certificate or SSH remote key was not OK.|Couldn't connect to server.]/, 1], }, }, diff --git a/tests/regression/misc/60-pmfromfile-external.t.in b/tests/regression/misc/60-pmfromfile-external.t.in index bfa4038a4a..2910ed11b9 100644 --- a/tests/regression/misc/60-pmfromfile-external.t.in +++ b/tests/regression/misc/60-pmfromfile-external.t.in @@ -67,7 +67,7 @@ ), match_log => { - error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/status.modsecurity.org\/modsecurity-regression-test.txt\" error: SSL peer certificate or SSH remote key was not OK./, 1], + error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/status.modsecurity.org\/modsecurity-regression-test.txt\" error: [SSL peer certificate or SSH remote key was not OK.|Couldn't connect to server.]/, 1], }, match_response => { status => qr/^404$/, From 61bce8d9a9611fe72235a64cb8840ae195a302a0 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 14 Jul 2017 13:22:46 -0300 Subject: [PATCH 144/477] Cosmetics: moving declaration to the too of the block --- apache2/msc_multipart.c | 6 +++--- apache2/msc_reqbody.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 9bf327d2bc..45c18e3444 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -1327,14 +1327,14 @@ apr_status_t multipart_cleanup(modsec_rec *msr) { } else { /* Move file to the upload dir. */ if (parts[i]->tmp_file_name != NULL) { + const char *new_filename = NULL; + const char *new_basename = NULL; + if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { msr_log(msr, 4, "Not moving part to identical location"); continue; } - const char *new_filename = NULL; - const char *new_basename = NULL; - /* make sure it is closed first */ if (parts[i]->tmp_file_fd > 0) { close(parts[i]->tmp_file_fd); diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index a8411fa04d..dc8404725c 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -884,15 +884,15 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { if (msr->msc_reqbody_filename != NULL) { if (keep_body) { + /* Move request body (which is a file) to the storage area. */ + const char *put_filename = NULL; + const char *put_basename = NULL; + if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { msr_log(msr, 4, "Not moving file to identical location."); goto nullify; } - /* Move request body (which is a file) to the storage area. */ - const char *put_filename = NULL; - const char *put_basename = NULL; - /* Construct the new filename. */ put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename); if (put_basename == NULL) { From 1e8b4669eb2d8825d8fdf86fdd638b807942b123 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Mon, 17 Jul 2017 08:43:20 -0300 Subject: [PATCH 145/477] Refactoring of IIS build scripts --- iis/build_dependencies.bat | 43 ++++++++++------ iis/build_modsecurity.bat | 4 +- iis/dependencies/build_cmake.bat | 20 ++++++++ iis/dependencies/build_pcre.bat | 65 ++++++++++++++---------- iis/dependencies/build_yajl.bat | 8 +-- iis/dependencies/howto.txt | 86 +++++++++++++++++--------------- iis/download_files.bat | 41 +++++++++++++++ 7 files changed, 181 insertions(+), 86 deletions(-) create mode 100644 iis/dependencies/build_cmake.bat create mode 100644 iis/download_files.bat diff --git a/iis/build_dependencies.bat b/iis/build_dependencies.bat index fc0d6095d6..1ae2a607a1 100644 --- a/iis/build_dependencies.bat +++ b/iis/build_dependencies.bat @@ -1,4 +1,4 @@ -:: Those variable should be edited as needed. +:: Those variables should be edited as needed. :: Use full paths. :: General paths @@ -6,20 +6,25 @@ @set OUTPUT_DIR=%cd%\dependencies\release_files @set SOURCE_DIR=%USERPROFILE%\Downloads +:: Dependencies +@set CMAKE=cmake-3.8.2-win32-x86.zip +@set PCRE=pcre-8.40.zip +@set ZLIB=zlib-1.2.11.tar.gz +@set LIBXML2=libxml2-2.9.4.tar.gz +@set LUA=lua-5.3.4.tar.gz +@set CURL=curl-7.54.1.zip +@set APACHE_SRC=httpd-2.4.27.tar.gz +@set APACHE_BIN32=httpd-2.4.27-win32-VC11.zip +@set APACHE_BIN64=httpd-2.4.27-win64-VC11.zip +@set YAJL=yajl-2.1.0.zip +@set SSDEEP=ssdeep-2.13.tar.gz +@set SSDEEP_BIN=ssdeep-2.13.zip + +@set CMAKE_DIR=%WORK_DIR%\%CMAKE:~0,-4%\bin + :: Aditional paths. -@set PATH=%PATH%;c:\work\cmake-2.8.7-win32-x86\bin;"c:\program files\7-zip" - -@set PCRE=pcre-8.33.zip -@set ZLIB=zlib-1.2.8.tar.gz -@set LIBXML2=libxml2-2.9.1.tar.gz -@set LUA=lua-5.1.5.tar.gz -@set CURL=curl-7.39.0.zip -@set APACHE_SRC=httpd-2.4.6.tar.gz -@set APACHE_BIN32=httpd-2.4.6-win32-VC11.zip -@set APACHE_BIN64=httpd-2.4.6-win64-VC11.zip -@set YAJL=lloyd-yajl-f4b2b1a.zip -@set SSDEEP=ssdeep-2.10.tar.gz -@set SSDEEP_BIN=ssdeep-2.10.zip +@set PATH=%PATH%;%CMAKE_DIR%;"c:\program files\7-zip" + :: @set VCARGS32="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat" :: @set VCARGS64="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat" @@ -45,6 +50,12 @@ call cl 2>&1 | findstr /C:"x64" @if (%ERRORLEVEL%) == (0) set APACHE_BIN=%APACHE_BIN64% @echo Starting with the depdendencies... +@echo # CMake. - %CMAKE% +@call dependencies/build_cmake.bat +@if NOT (%ERRORLEVEL%) == (0) goto build_failed_cmake +@cd "%CURRENT_DIR%" + + @echo # Apache - %HTTPD%/%APACHE24_ZIP% @call dependencies/build_apache.bat @if NOT (%ERRORLEVEL%) == (0) goto build_failed_apache @@ -129,6 +140,10 @@ call cl 2>&1 | findstr /C:"x64" @echo Failed to setup %SSDEEP%... @goto failed +:build_failed_cmake +@echo Failed to setup %CMAKE%... +@goto failed + :failed @cd %CURRENT_DIR% @exit /B 1 diff --git a/iis/build_modsecurity.bat b/iis/build_modsecurity.bat index 680c05e8fb..76f6fd2508 100644 --- a/iis/build_modsecurity.bat +++ b/iis/build_modsecurity.bat @@ -15,7 +15,7 @@ set CURRENT_DIR=%cd% cd ..\apache2 del *.obj *.dll *.lib del libinjection\*.obj libinjection\*.dll libinjection\*.lib -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.0.1 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR% SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes @if NOT (%ERRORLEVEL%) == (0) goto build_failed @echo mlogc... @@ -29,7 +29,7 @@ nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEP cd ..\iis del *.obj *.dll *.lib nmake -f Makefile.win clean -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.0.1 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR% SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl @if NOT (%ERRORLEVEL%) == (0) goto build_failed cd %CURRENT_DIR% diff --git a/iis/dependencies/build_cmake.bat b/iis/dependencies/build_cmake.bat new file mode 100644 index 0000000000..f76847153a --- /dev/null +++ b/iis/dependencies/build_cmake.bat @@ -0,0 +1,20 @@ +@cd "%WORK_DIR%" + +@if NOT EXIST "%SOURCE_DIR%\%CMAKE%" goto file_not_found + + +@7z.exe x "%SOURCE_DIR%\%CMAKE%" +@if NOT (%ERRORLEVEL%) == (0) goto something_went_wrong + +@exit /B 0 + +:file_not_found +@echo File not found: %SOURCE_DIR%\%CMAKE% +@goto failed + +:something_went_wrong +@echo Something went wrong while unzip CMake files. +@goto failed + +:failed +@exit /B 1 \ No newline at end of file diff --git a/iis/dependencies/build_pcre.bat b/iis/dependencies/build_pcre.bat index 9d728a4042..b7841b2549 100644 --- a/iis/dependencies/build_pcre.bat +++ b/iis/dependencies/build_pcre.bat @@ -1,32 +1,43 @@ -cd "%WORK_DIR%" - -@if NOT EXIST "%SOURCE_DIR%\%APACHE_BIN%" goto file_not_found_bin - -7z.exe x "%SOURCE_DIR%\%PCRE%" -set PCRE_DIR=%PCRE:~0,-4% - +::@if NOT (%ERRORLEVEL%) == (1) Echo "Patch successfull... For more info on patch see: https://vcs.pcre.org/pcre/code/trunk/CMakeLists.txt?r1=1659&r2=1677&view=patch" + +cd "%WORK_DIR%" + +@if NOT EXIST "%SOURCE_DIR%\%APACHE_BIN%" goto file_not_found_bin + +7z.exe x "%SOURCE_DIR%\%PCRE%" +set PCRE_DIR=%PCRE:~0,-4% + move "%PCRE_DIR%" "pcre" - + +@if "%PCRE_DIR%" == "pcre-8.40" ( + Echo. && Echo "PCRE 8.40 found... patching with patch-pcre-8.40.vbs..." + cscript /B /Nologo ../patch-pcre-8.40.vbs +) + cd "pcre" -CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True -@if NOT (%ERRORLEVEL%) == (0) goto build_failed -NMAKE -@if NOT (%ERRORLEVEL%) == (0) goto build_failed -cd "%WORK%" - +cat CMakeLists.txt | sed "s/PCRE_STATIC_RUNTIME OFF CACHE BOOL/PCRE_STATIC_RUNTIME/g" > CMakeLists.txt.ops +move CMakeLists.txt CMakeLists.txt.old +move CMakeLists.txt.ops CMakeLists.txt +CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True +@if NOT (%ERRORLEVEL%) == (0) goto build_failed +NMAKE +@if NOT (%ERRORLEVEL%) == (0) goto build_failed +cd "%WORK%" + copy /y "%WORK_DIR%\pcre\pcre.dll" "%OUTPUT_DIR%" copy /y "%WORK_DIR%\pcre\pcre.pdb" "%OUTPUT_DIR%" copy /y "%WORK_DIR%\pcre\pcre.lib" "%OUTPUT_DIR%" -echo "a" -@exit /B 0 - -:file_not_found_bin -@echo File not found: "%SOURCE_DIR%\%PCRE%" -@goto failed - -:build_failed -@echo Problems during the building phase -@goto failed - -:failed -@exit /B 1 +copy /y "%WORK_DIR%\pcre\pcre.h.generic" "%WORK_DIR%\pcre\pcre.h" +echo "a" +@exit /B 0 + +:file_not_found_bin +@echo File not found: "%SOURCE_DIR%\%PCRE%" +@goto failed + +:build_failed +@echo Problems during the building phase +@goto failed + +:failed +@exit /B 1 diff --git a/iis/dependencies/build_yajl.bat b/iis/dependencies/build_yajl.bat index 33ebc234ac..f53e885a35 100644 --- a/iis/dependencies/build_yajl.bat +++ b/iis/dependencies/build_yajl.bat @@ -20,10 +20,10 @@ nmake cd "%WORK%" -copy /y "%WORK_DIR%\yajl\build\yajl-2.0.1\lib\yajl.dll" "%OUTPUT_DIR%" -copy /y "%WORK_DIR%\yajl\build\yajl-2.0.1\lib\yajl.pdb" "%OUTPUT_DIR%" -copy /y "%WORK_DIR%\yajl\build\yajl-2.0.1\lib\yajl.lib" "%OUTPUT_DIR%" -copy /y "%WORK_DIR%\yajl\build\yajl-2.0.1\lib\yajl_s.lib" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.dll" "%OUTPUT_DIR%" +:: copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.pdb" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.lib" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl_s.lib" "%OUTPUT_DIR%" @exit /B 0 diff --git a/iis/dependencies/howto.txt b/iis/dependencies/howto.txt index 1505a5f95d..55f9184bf4 100644 --- a/iis/dependencies/howto.txt +++ b/iis/dependencies/howto.txt @@ -1,44 +1,52 @@ -WARNING! +The build process for ModSecurityIIS for Windows was a relatively complicated process. Understanding it required advanced knowledge of Windows and Unix environments. +So the build process was refactored to make it easier for users to create their own builds with the automated batch scripts. -Building ModSecurityIIS on Windows is a relatively complicated process. Understanding it requires advanced knowledge of Windows and Unix environments. -Using the same versions of libraries as listed below is strongly recommended. +* build_release.bat -> The main build script that calls all the others to have a working release +* build_msi.bat -> Creates the MSI self-installer for easy deploy / removal / distribution +* build_dependencies.bat -> Sets (and downloads if needed) all required dependencies +* build_modsecurity.bat -> Builds ModSecurity (requires all depenedencies being set) + +* download_files.bat -> Downloads all required dependencies to the default Downloads folder +** This script is disabled by default. If you want to enable it, uncomment the "@call download_files.bat" line on build_dependencies.bat + +The dependencies folder also includes a set o batch scripts which sets each dependency +on its own. These scripts are called by the build_dependencies.bat script. + +Using the same versions of libraries as listed below is recommended. -------------------------------------- -Tested on: - -Windows 7 x64 -Vistual Studio 2010 Ultimate SP1 -IIS enabled/installed - -cmake 2.8.7 -curl 7.24.0 -apache 2.2.22 or apache 2.4.3 -libxml2 2.7.7 -lua 5.1.5 -pcre 8.30 -zlib 1.2.7 -7-Zip +Compilation Prerequisites: + +* Windows 7 x86_x64 (Should work on newer versions of Windows too) +* Vistual Studio 2013 Express (Other versions should work, but you need to set the correct path for vcvars.bat scripts) +* IIS enabled/installed +* 7-Zip + -------------------------------------- -1. Create working directory c:\work and drop directory c:\drop -2. Sync SVN ModSecurity branch to c:\work\mod_security -3. Copy files from c:\work\mod_security\iis\winbuild to c:\work -4. Download and install cmake (unpack to c:\work\cmake-2.8.7-win32-x86) -5. Download and install 7-Zip -6. Adjust paths in c:\work\init.bat accordingly if needed -7. Download curl, apache, libxml2, lua, pcre and zlib, place them in zip files in c:\work - -curl-7.24.0.zip -httpd-2.2.22-win32-src.zip or (httpd-2.4.3.zip (source) and httpd-2.4.3-win32.zip + httpd-2.4.3-win64.zip (binaries)) -libxml2-2.7.7.zip -lua-5.1.5.zip -pcre-8.30.zip -zlib-1.2.7.zip - -Modify c:\work\build.bat accordingly (if other versions were used) - -8. Open cmd.exe window, go to c:\work and run buildall.bat -9. When done, the binaries, lib and pdb files should appear under c:\drop\x86 (32-bit) and c:\drop\amd64 (64-bit) -10. Open the VS ModSecurity IIS installer project -11. Copy new binaries to the installer's x86 and amd64 directories -12. Build installer from within VS +The latest versions of ModSecurity dependencies known to work well are the following: + +cmake-3.8.2-win32-x86 +pcre-8.40 (patch required and included on file "patch-pcre-8.40.vbs") +zlib-1.2.11 +libxml2-2.9.4 +lua-5.3.4 +curl-7.54.1 +httpd-2.4.27 (bin-VC11) +yajl-2.1.0 +ssdeep-2.13 + +-------------------------------------- + +1. Create working directory (e.g. c:\work) and drop the latest clone from ModSecurity's 2.x Github (https://github.com/SpiderLabs/ModSecurity/archive/v2/master.zip) +2. Make sure the prerequisites mentioned above are all set +3. If you haven't download the dependency files before, uncomment the "@call download_files.bat" line on build_dependencies.bat to have them downloaded prior +4. Open a command prompt (cmd.exe) and head to the "iis" folder inside ModSecurity tree working directory (e.g. cd c:\work\ModSecurity\iis) +5. If you need to modify anything (e.g. paths, versions etc), carefully edit the batch files. +6. Run build_release.bat +7. When done, the binaries, lib and pdb files should appear under c:\work\ModSecurity\iis\release\x86 (32-bit) and c:\work\ModSecurity\iis\release\amd64 (64-bit) +* At this point, if you had a previous installation of ModSecurity and would like to test you can place the x86 files to "C:\Windows\SysWOW64\inetsrv" and x64 files to "C:\Windows\System32\inetsrv" + +8. If all went well, you can build the MSI installer by running the build_msi.bat script. + +* The built installable package places the files to the correct folders, automatically configures the ModSecurity IIS native module and configures web.config to enable ModSecurity for all IIS sites. diff --git a/iis/download_files.bat b/iis/download_files.bat new file mode 100644 index 0000000000..f0db400e13 --- /dev/null +++ b/iis/download_files.bat @@ -0,0 +1,41 @@ + +::@set CMAKE=cmake-3.8.2-win32-x86.zip +::@set PCRE=pcre-8.40.zip +::@set ZLIB=zlib-1.2.11.tar.gz +::@set LIBXML2=libxml2-2.9.4.tar.gz +::@set LUA=lua-5.3.4.tar.gz +::@set CURL=curl-7.54.1.zip +::@set APACHE_SRC=httpd-2.4.27.tar.gz +::@set APACHE_BIN32=httpd-2.4.27-win32-VC11.zip +::@set APACHE_BIN64=httpd-2.4.27-win64-VC11.zip +::@set YAJL=yajl-2.1.0.zip +::@set SSDEEP=ssdeep-2.13.tar.gz +::@set SSDEEP_BIN=ssdeep-2.13.zip + +:: BITSAdmin refuses to download YAJL from GitHub URL +:: @set YAJL_URL=https://github.com/lloyd/yajl/archive/%YAJL:~-9% +@set YAJL_URL=http://http.debian.net/debian/pool/main/y/yajl/yajl_2.1.0.orig.tar.gz + +@set CMAKE_URL=https://cmake.org/files/v3.8/%CMAKE% +@set PCRE_URL=https://ftp.pcre.org/pub/pcre/%PCRE% +@set ZLIB_URL=https://zlib.net/%ZLIB% +@set LIBXML2_URL=http://xmlsoft.org/sources/%LIBXML2% +@set LUA_URL=https://www.lua.org/ftp/%LUA% +@set CURL_URL=http://curl.askapache.com/download/%CURL% +@set APACHE_SRC_URL=https://www.apache.org/dist/httpd/%APACHE_SRC% +@set APACHE_BIN_URL=https://www.apachelounge.com/download/VC11/binaries +@set SSDEEP_URL=https://downloads.sourceforge.net/project/ssdeep/ssdeep-2.13 + +bitsadmin.exe /transfer "Downloading dependencies..." %CMAKE_URL% %SOURCE_DIR%\%CMAKE% %PCRE_URL% %SOURCE_DIR%\%PCRE% %ZLIB_URL% %SOURCE_DIR%\%ZLIB% %LIBXML2_URL% %SOURCE_DIR%\%LIBXML2% %LUA_URL% %SOURCE_DIR%\%LUA% %CURL_URL% %SOURCE_DIR%\%CURL% %APACHE_SRC_URL% %SOURCE_DIR%\%APACHE_SRC% %APACHE_BIN_URL%/%APACHE_BIN32% %SOURCE_DIR%\%APACHE_BIN32% %APACHE_BIN_URL%/%APACHE_BIN64% %SOURCE_DIR%\%APACHE_BIN64% %YAJL_URL% %SOURCE_DIR%\%YAJL% %SSDEEP_URL%/%SSDEEP% %SOURCE_DIR%\%SSDEEP% %SSDEEP_URL%/%SSDEEP_BIN% %SOURCE_DIR%\%SSDEEP_BIN% + + +@if NOT (%ERRORLEVEL%) == (0) goto :failed_to_download +@exit /B 0 + +:failed_to_download +@echo. && echo Failed to download dependency files... Try again or manually download the files to %SOURCE_DIR% and comment "@call download_files.bat" from build_dependencies.bat +@goto failed + +:failed +@exit /B 1 + From b878ece6c6afb9483e4a80280801e07a7bd7d06f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 27 Jun 2017 10:01:49 -0300 Subject: [PATCH 146/477] Version 2.9.2 Increasing version to 2.9.2 (final) --- CHANGES | 18 +++++++++++++++--- apache2/msc_release.h | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 1bf23a3877..715dc1a11c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ -DD MMM YYYY - 2.9.2 - To be released ------------------------------------- - +18 Jul 2017 - 2.9.2 +------------------- + + * IIS build refactoring and dependencies update + [Issue #1487 - @victorhora] * Best practice: Initialize msre_var pointers [Commit fbd57 - Allan Boll] * nginx: Obtain port from r->connection->local_sockaddr. @@ -44,6 +46,7 @@ DD MMM YYYY - 2.9.2 - To be released [Issue #1067 - Marc Stern] * {dis|en}able-dechunk-logging: Option to disable logging of dechunking in audit log when log level < 9. + [Issue #1068 - Marc Stern] * Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4 [ModSecurity team] * {dis|en}able-handler-logging: Option to disable logging of Apache handler @@ -92,6 +95,15 @@ DD MMM YYYY - 2.9.2 - To be released * Treat APR_INCOMPLETE as APR_EOF while receiving the request body. [Issue #1060, #334 - Alexey Sintsov] + +Security issues + + * Allan Boll reported an uninitialized variable that may lead to a crash on + Windows platform. + * Brian Adeloye reported an infinite loop on the version of libinjection used + on ModSecurity 2.9.1. + + 09 Mar 2016 - 2.9.1 ------------------- diff --git a/apache2/msc_release.h b/apache2/msc_release.h index f2fe898d5d..dcfde11c89 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "1" +#define MODSEC_VERSION_MAINT "2" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From 7ead7f4d23ee6bb2f491842826071624f06cba32 Mon Sep 17 00:00:00 2001 From: David Carlier <dcarlier@afilias.info> Date: Mon, 12 Jun 2017 11:55:47 +0100 Subject: [PATCH 147/477] Few missing headers, in the <arpa/inet.h> inclusions ones mainly due to the fact APR_HAVE* constants are simply into apr.h --- apache2/msc_status_engine.c | 3 +++ apache2/msc_tree.c | 1 + apache2/msc_util.c | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 834ecc3ed9..3ee6c686c1 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -19,6 +19,9 @@ #ifdef WIN32 #include <winsock2.h> #include <iphlpapi.h> +#else +#include <sys/ioctl.h> +#include <netdb.h> #endif #ifdef DARWIN diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index c672bd5fd4..ddbc4f2149 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -14,6 +14,7 @@ #include <stdio.h> #include <stdlib.h> +#include <apr.h> #if APR_HAVE_STDINT_H #include <stdint.h> #endif diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 33447ba0d0..e3923ff2f8 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -22,6 +22,10 @@ #include "msc_release.h" #include "msc_util.h" +#include <apr.h> +#if APR_HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif #include <apr_lib.h> #include <apr_sha1.h> #include "modsecurity_config.h" From 2ab08a625eb8e6cfadd757708e742b0b2a2b18f9 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 28 Sep 2017 22:21:05 +0000 Subject: [PATCH 148/477] Adds information about #1454 --- CHANGES | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGES b/CHANGES index 715dc1a11c..34a6920153 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +DD MMM YYYY - 2.9.3 - To be released +------------------------------------ + + * Adds missing headers + [Issue #1454 - @devnexen] + + 18 Jul 2017 - 2.9.2 ------------------- From 89764f12b09d131ee4ae9abf4df200cda00f1d26 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 24 Jul 2017 15:10:29 +0200 Subject: [PATCH 149/477] Fixed typos: LOG_NO_STOPWATCH instead of DLOG_NO_STOPWATCH $log_server_context instead of $log_server_context --- apache2/msc_logging.c | 6 +++--- configure.ac | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index c2274c7f57..cb0297a437 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1165,7 +1165,7 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Stopwatch2 */ -#ifdef DLOG_NO_STOPWATCH +#ifdef LOG_NO_STOPWATCH if (msr->txcfg->debuglog_level >= 9) #endif format_performance_variables_json(msr, g); @@ -1998,7 +1998,7 @@ void sec_audit_logger_native(modsec_rec *msr) { } /* Stopwatch; left in for compatibility reasons */ -#ifdef DLOG_NO_STOPWATCH +#ifdef LOG_NO_STOPWATCH if (msr->txcfg->debuglog_level >= 9) { #endif text = apr_psprintf(msr->mp, "Stopwatch: %" APR_TIME_T_FMT " %" APR_TIME_T_FMT " (- - -)\n", @@ -2013,7 +2013,7 @@ void sec_audit_logger_native(modsec_rec *msr) { "; %s\n", msr->request_time, (now - msr->request_time), perf_all); sec_auditlog_write(msr, text, strlen(text)); } -#ifdef DLOG_NO_STOPWATCH +#ifdef LOG_NO_STOPWATCH } #endif diff --git a/configure.ac b/configure.ac index 3180547cc5..e3a3595fde 100644 --- a/configure.ac +++ b/configure.ac @@ -812,7 +812,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_contex $collection_global_lock" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 5731b769182cf2e97843aaabe9fa3a4e2daa3206 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 29 Sep 2017 18:35:45 +0000 Subject: [PATCH 150/477] Adds information about #1510 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 34a6920153..09bb62363f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Uses LOG_NO_STOPWATCH instead of DLOG_NO_STOPWATCH + [Issue #1510 - @marcstern] * Adds missing headers [Issue #1454 - @devnexen] From c917df0f2a8acb0fb31262a5ad222d6d78394fe3 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 4 Oct 2017 13:48:45 +0000 Subject: [PATCH 151/477] Set of fixes to make the build/win to work in our buildbots --- iis/build_modsecurity.bat | 6 +++--- iis/dependencies/build_ssdeep.bat | 3 +++ iis/dependencies/build_yajl.bat | 15 +++++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/iis/build_modsecurity.bat b/iis/build_modsecurity.bat index 76f6fd2508..eeaeed2a29 100644 --- a/iis/build_modsecurity.bat +++ b/iis/build_modsecurity.bat @@ -15,21 +15,21 @@ set CURRENT_DIR=%cd% cd ..\apache2 del *.obj *.dll *.lib del libinjection\*.obj libinjection\*.dll libinjection\*.lib -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR% SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes @if NOT (%ERRORLEVEL%) == (0) goto build_failed @echo mlogc... cd ..\mlogc del *.obj *.dll *.lib nmake -f Makefile.win clean -nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS +nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS @if NOT (%ERRORLEVEL%) == (0) goto build_failed @echo iis... cd ..\iis del *.obj *.dll *.lib nmake -f Makefile.win clean -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR% SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl @if NOT (%ERRORLEVEL%) == (0) goto build_failed cd %CURRENT_DIR% diff --git a/iis/dependencies/build_ssdeep.bat b/iis/dependencies/build_ssdeep.bat index 36b8b1595c..3b3a46bcd4 100644 --- a/iis/dependencies/build_ssdeep.bat +++ b/iis/dependencies/build_ssdeep.bat @@ -1,5 +1,8 @@ cd "%WORK_DIR%" +echo "%SOURCE_DIR%\%SSDEEP%" +echo "%SOURCE_DIR%\%SSDEEP_BIN%" + @if NOT EXIST "%SOURCE_DIR%\%SSDEEP%" goto build_failed @7z.exe x "%SOURCE_DIR%\%SSDEEP_BIN%" diff --git a/iis/dependencies/build_yajl.bat b/iis/dependencies/build_yajl.bat index f53e885a35..895f43ed55 100644 --- a/iis/dependencies/build_yajl.bat +++ b/iis/dependencies/build_yajl.bat @@ -4,11 +4,13 @@ cd "%WORK_DIR%" 7z.exe x "%SOURCE_DIR%\%YAJL%" set YAJL_DIR=%YAJL:~0,-4% - -move "%YAJL_DIR%" "yajl" - +echo "%SOURCE_DIR%\%YAJL%" +echo "%YAJL_DIR%" +pwd +move "%YAJL_DIR%" "%WORK_DIR%\yajl" +pwd cd "yajl" - +pwd mkdir build @if NOT (%ERRORLEVEL%) == (0) goto build_failed cd build @@ -25,6 +27,11 @@ copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.dll" "%OUTPUT_DIR%" copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.lib" "%OUTPUT_DIR%" copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl_s.lib" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.dll" "%WORK_DIR%\yajl\build\%YAJL_DIR%\include\yajl.dll" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl.lib" "%WORK_DIR%\yajl\build\%YAJL_DIR%\include\yajl.lib" +copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl_s.lib" "%WORK_DIR%\yajl\build\%YAJL_DIR%\include\yajl_s.lib" + + @exit /B 0 :file_not_found_bin From b3c39136c16304a7a59ec1d17046b2c68c58a9f5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 4 Oct 2017 13:49:54 +0000 Subject: [PATCH 152/477] Adds info about 94fe3 on our changelogs --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 09bb62363f..dd7d815197 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Set of fixies to make windows build workable with the buildbots + [Commit 94fe3 - @zimmerle] * Uses LOG_NO_STOPWATCH instead of DLOG_NO_STOPWATCH [Issue #1510 - @marcstern] * Adds missing headers From bbe7f8c389dcd01358dda36ba99c44146069d9d0 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Thu, 29 Jun 2017 01:37:23 -0400 Subject: [PATCH 153/477] Proposed fix for wildcard op when loading conf files on Nginx / IIS --- standalone/config.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/standalone/config.c b/standalone/config.c index 800d5b4344..5b3d0b21d0 100644 --- a/standalone/config.c +++ b/standalone/config.c @@ -742,12 +742,12 @@ AP_DECLARE(char *) ap_make_full_path(apr_pool_t *a, const char *src1, return path; } -static int fname_alphasort(const void *fn1, const void *fn2) +static int fname_reversealphasort(const void *fn1, const void *fn2) { const fnames *f1 = fn1; const fnames *f2 = fn2; - return strcmp(f1->fname,f2->fname); + return strcmp(f2->fname,f1->fname); } int fnmatch_test(const char *pattern) @@ -840,7 +840,7 @@ static const char *process_resource_config_nofnmatch(const char *fname, apr_dir_close(dirp); if (candidates->nelts != 0) { qsort((void *) candidates->elts, candidates->nelts, - sizeof(fnames), fname_alphasort); + sizeof(fnames), fname_reversealphasort); /* * Now recurse these... we handle errors and subdirectories @@ -941,7 +941,7 @@ static const char *process_resource_config_fnmatch(const char *path, const char *error; qsort((void *) candidates->elts, candidates->nelts, - sizeof(fnames), fname_alphasort); + sizeof(fnames), fname_reversealphasort); /* * Now recurse these... we handle errors and subdirectories @@ -1201,3 +1201,4 @@ const char *process_command_config(server_rec *s, return errmsg; } + From 185ec6f72ea72d1d25af29b1628164d80bedd74e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 4 Oct 2017 21:24:36 +0000 Subject: [PATCH 154/477] Adds information about #1486 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index dd7d815197..afad80bf7d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix for wildcard operator when loading conf files on Nginx / IIS + [Issue #1486, #1285 - @victorhora and @thierry-f-78] * Set of fixies to make windows build workable with the buildbots [Commit 94fe3 - @zimmerle] * Uses LOG_NO_STOPWATCH instead of DLOG_NO_STOPWATCH From 9b90d86f75cbf6de0dcd752614ace0854e6f2af4 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Tue, 4 Jul 2017 12:17:40 -0400 Subject: [PATCH 155/477] Add capture action to @detectXSS operator --- apache2/re_operators.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index e54a540700..f444d3c506 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -2158,12 +2158,14 @@ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var */ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + int capture; int is_xss; is_xss = libinjection_xss(var->value, var->value_len); + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; if (is_xss) { + set_match_to_tx(msr, capture, var->value, 0); *error_msg = apr_psprintf(msr->mp, "detected XSS using libinjection."); if (msr->txcfg->debuglog_level >= 9) { From 9c51671b744cb561944f7f4034a5cf873e1b332d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 03:25:46 +0000 Subject: [PATCH 156/477] Adds information about #1488 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index afad80bf7d..0c576b1585 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Add capture action to @detectXSS operator + [Issue #1488, #1482 - @victorhora] * Fix for wildcard operator when loading conf files on Nginx / IIS [Issue #1486, #1285 - @victorhora and @thierry-f-78] * Set of fixies to make windows build workable with the buildbots From b8636a70d1b5bc11749d4fb4ffefc0a6214e027d Mon Sep 17 00:00:00 2001 From: Guido Ravagli <gravagli@imolinfo.it> Date: Tue, 6 Jun 2017 16:39:30 +0200 Subject: [PATCH 157/477] added "empy chunk" check --- apache2/apache2_io.c | 48 +++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index c14dd41318..3f5b4ba94f 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -85,10 +85,11 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, return APR_EGENERAL; } - if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) { - /* Copy the data we received in the chunk */ - bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, - f->r->connection->bucket_alloc); + if (chunk->length > 0) { + if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) { + /* Copy the data we received in the chunk */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, + f->r->connection->bucket_alloc); #if 0 @@ -107,33 +108,34 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, #endif - if (bucket == NULL) return APR_EGENERAL; - APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); - } - } else if (msr->stream_input_data != NULL) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); + } + } else if (msr->stream_input_data != NULL) { - msr->if_stream_changed = 0; + msr->if_stream_changed = 0; - bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL, - f->r->connection->bucket_alloc); + bucket = apr_bucket_heap_create(msr->stream_input_data, msr->stream_input_length, NULL, + f->r->connection->bucket_alloc); - if (msr->txcfg->stream_inbody_inspection) { - if(msr->stream_input_data != NULL) { - free(msr->stream_input_data); - msr->stream_input_data = NULL; + if (msr->txcfg->stream_inbody_inspection) { + if(msr->stream_input_data != NULL) { + free(msr->stream_input_data); + msr->stream_input_data = NULL; + } } - } - if (bucket == NULL) return APR_EGENERAL; - APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length); - } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length); + } + } } if (rc == 0) { From 934a9fcc02baf12da0c3fd679a1c71e5f553a728 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 13:28:28 +0000 Subject: [PATCH 158/477] Verify if chunk exists before access it --- apache2/apache2_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 3f5b4ba94f..9ab59a53bc 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -85,7 +85,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, return APR_EGENERAL; } - if (chunk->length > 0) { + if (chunk && chunk->length > 0) { if (chunk && (!msr->txcfg->stream_inbody_inspection || (msr->txcfg->stream_inbody_inspection && msr->if_stream_changed == 0))) { /* Copy the data we received in the chunk */ bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, From 7fd5439c638c42eac4e810d241feca3a855e40ee Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 13:33:11 +0000 Subject: [PATCH 159/477] Adds info about #1446 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 0c576b1585..f75f7a51f2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Added "empy chunk" check + [Issue #1347, #1446 - @gravagli, @bostrt, @zimmerle] * Add capture action to @detectXSS operator [Issue #1488, #1482 - @victorhora] * Fix for wildcard operator when loading conf files on Nginx / IIS From a0bd72334d9437883ffc68f660f2f09c42095f64 Mon Sep 17 00:00:00 2001 From: Nic Jansma <nic@nicj.net> Date: Wed, 23 Aug 2017 19:13:50 -0400 Subject: [PATCH 160/477] Fixes SecConnWriteStateLimit --- apache2/mod_security2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index b6e98e9dcd..fb399362f5 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1597,7 +1597,7 @@ static int hook_connection_early(conn_rec *conn) "Possible DoS Consumption Attack [Rejected]", ip_count_w, conn_write_state_limit, client_ip); - if (!conn_limits_filter_state == MODSEC_ENABLED) + if (conn_limits_filter_state == MODSEC_ENABLED) return OK; } } From d50f840a43053007daa3052909b1a2e93821649c Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 14:39:32 +0000 Subject: [PATCH 161/477] Adds info about #1545 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index f75f7a51f2..55ea9b201d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fixes SecConnWriteStateLimit + [Issue #1545 - @nicjansma] * Added "empy chunk" check [Issue #1347, #1446 - @gravagli, @bostrt, @zimmerle] * Add capture action to @detectXSS operator From b3a527f593a51e196eaa473572386ca22be86346 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Thu, 5 Oct 2017 16:39:57 +0000 Subject: [PATCH 162/477] Fixed a typo in build_yajl.bat --- iis/dependencies/build_yajl.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/dependencies/build_yajl.bat b/iis/dependencies/build_yajl.bat index 895f43ed55..f5c6eff078 100644 --- a/iis/dependencies/build_yajl.bat +++ b/iis/dependencies/build_yajl.bat @@ -35,7 +35,7 @@ copy /y "%WORK_DIR%\yajl\build\%YAJL_DIR%\lib\yajl_s.lib" "%WORK_DIR%\yajl\build @exit /B 0 :file_not_found_bin -@echo File not found: "%SOURCE_DIR%\%PCRE%" +@echo File not found: "%SOURCE_DIR%\%YAJL%" @goto failed :build_failed From 07c3659ddcf8f8ac72459e4526dfd7610b0b2968 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 16:40:40 +0000 Subject: [PATCH 163/477] Adds information on #1538 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 55ea9b201d..327b2bd3f4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fixed typo in build_yajl.bat + [Issue #1366 - @allanbomsft] * Fixes SecConnWriteStateLimit [Issue #1545 - @nicjansma] * Added "empy chunk" check From afae6906552fa5852ab295920e25da35392c8443 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Fri, 18 Aug 2017 17:45:44 -0700 Subject: [PATCH 164/477] Preallocate memory when SecStreamInBodyInspection is on. 20x speed improvement for 10mb upload. Also simplified modsecurity_request_body_to_stream. --- apache2/apache2_io.c | 1 - apache2/modsecurity.h | 1 + apache2/msc_reqbody.c | 89 +++++++++++++++++++++++------------------- apache2/re_operators.c | 4 +- 4 files changed, 52 insertions(+), 43 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 9ab59a53bc..74a7a7cd7f 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -283,7 +283,6 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (msr->txcfg->stream_inbody_inspection == 1) { - msr->stream_input_length+=buflen; modsecurity_request_body_to_stream(msr, buf, buflen, error_msg); } diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index f170034c99..601b5f2477 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -287,6 +287,7 @@ struct modsec_rec { unsigned int resbody_contains_html; apr_size_t stream_input_length; + apr_size_t stream_input_allocated_length; char *stream_input_data; apr_size_t stream_output_length; char *stream_output_data; diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index dc8404725c..8c8b4add2c 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -428,55 +428,62 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { - char *stream_input_body = NULL; - char *data = NULL; - int first_pkt = 0; + apr_size_t allocate; + char* allocated; - if(msr->stream_input_data == NULL) { - msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1); - first_pkt = 1; - } - else { - - data = (char *)malloc(msr->stream_input_length + 1 - buflen); + if (msr->stream_input_data == NULL) { + // Is the request body length is known beforehand? (requests that are not Transfer-Encoding: chunked) + if (msr->request_content_length > 0) { + allocate = msr->request_content_length; + } + else { + // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked) + allocate = buflen; + } - if(data == NULL) + allocated = (char*) calloc(allocate, sizeof(char)); + if (allocated) { + msr->stream_input_data = allocated; + msr->stream_input_allocated_length = allocate; + } + else { + *error_msg = apr_psprintf( + msr->mp, + "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", + allocate); return -1; - - memset(data, 0, msr->stream_input_length + 1 - buflen); - memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen); - - stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1); - - msr->stream_input_data = (char *)stream_input_body; - } - - if (msr->stream_input_data == NULL) { - if(data) { - free(data); - data = NULL; } - *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", - msr->stream_input_length + 1); - return -1; } + else { + // Do we need to expand the space we have previously allocated? + if ((msr->stream_input_length + buflen) > msr->stream_input_allocated_length) { - memset(msr->stream_input_data, 0, msr->stream_input_length+1); + // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs + allocate = msr->stream_input_length + buflen; - if(first_pkt) { - memcpy(msr->stream_input_data, buffer, msr->stream_input_length); - } else { - memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen); - memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen); + allocated = (char*) realloc(msr->stream_input_data, allocate); + if (allocated) { + msr->stream_input_data = allocated; + msr->stream_input_allocated_length = allocate; + } + else { + *error_msg = apr_psprintf( + msr->mp, + "Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", + allocate); + free(msr->stream_input_data); + return -1; + } + } } - if(data) { - free(data); - data = NULL; - } + // Append buffer to msr->stream_input_data + memcpy(msr->stream_input_data + msr->stream_input_length, buffer, buflen); + msr->stream_input_length += buflen; return 1; } + /** * Replace a bunch of chunks holding a request body with a single large chunk. */ @@ -884,15 +891,15 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { if (msr->msc_reqbody_filename != NULL) { if (keep_body) { - /* Move request body (which is a file) to the storage area. */ - const char *put_filename = NULL; - const char *put_basename = NULL; - if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { msr_log(msr, 4, "Not moving file to identical location."); goto nullify; } + /* Move request body (which is a file) to the storage area. */ + const char *put_filename = NULL; + const char *put_basename = NULL; + /* Construct the new filename. */ put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename); if (put_basename == NULL) { diff --git a/apache2/re_operators.c b/apache2/re_operators.c index f444d3c506..dbade1f49c 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -634,6 +634,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; + msr->stream_input_allocated_length = 0; msr->stream_input_data = (char *)malloc(size+1); @@ -642,7 +643,8 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, } msr->stream_input_length = size; - memset(msr->stream_input_data, 0x0, size+1); + msr->stream_input_allocated_length = size + 1; + memset(msr->stream_input_data, 0x0, size + 1); msr->if_stream_changed = 1; From 97b51ebfed981b05bea3aa37db161bcbc67410c5 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Tue, 22 Aug 2017 10:37:29 -0700 Subject: [PATCH 165/477] Renamed local var and initialized local vars. Undid accidental move. --- apache2/msc_reqbody.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 8c8b4add2c..1422065283 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -428,29 +428,29 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { - apr_size_t allocate; - char* allocated; + apr_size_t allocate_length = 0; + char* allocated = NULL; if (msr->stream_input_data == NULL) { // Is the request body length is known beforehand? (requests that are not Transfer-Encoding: chunked) if (msr->request_content_length > 0) { - allocate = msr->request_content_length; + allocate_length = msr->request_content_length; } else { // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked) - allocate = buflen; + allocate_length = buflen; } - allocated = (char*) calloc(allocate, sizeof(char)); + allocated = (char*) calloc(allocate_length, sizeof(char)); if (allocated) { msr->stream_input_data = allocated; - msr->stream_input_allocated_length = allocate; + msr->stream_input_allocated_length = allocate_length; } else { *error_msg = apr_psprintf( msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", - allocate); + allocate_length); return -1; } } @@ -459,18 +459,18 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf if ((msr->stream_input_length + buflen) > msr->stream_input_allocated_length) { // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs - allocate = msr->stream_input_length + buflen; + allocate_length = msr->stream_input_length + buflen; - allocated = (char*) realloc(msr->stream_input_data, allocate); + allocated = (char*) realloc(msr->stream_input_data, allocate_length); if (allocated) { msr->stream_input_data = allocated; - msr->stream_input_allocated_length = allocate; + msr->stream_input_allocated_length = allocate_length; } else { *error_msg = apr_psprintf( msr->mp, "Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", - allocate); + allocate_length); free(msr->stream_input_data); return -1; } @@ -891,15 +891,15 @@ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { if (msr->msc_reqbody_filename != NULL) { if (keep_body) { + /* Move request body (which is a file) to the storage area. */ + const char *put_filename = NULL; + const char *put_basename = NULL; + if (strcmp(msr->txcfg->upload_dir, msr->txcfg->tmp_dir) == 0) { msr_log(msr, 4, "Not moving file to identical location."); goto nullify; } - /* Move request body (which is a file) to the storage area. */ - const char *put_filename = NULL; - const char *put_basename = NULL; - /* Construct the new filename. */ put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename); if (put_basename == NULL) { From 023b86385399329f3fa9b75e341849b921d47cfe Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Tue, 22 Aug 2017 15:31:33 -0700 Subject: [PATCH 166/477] Ensure memory preallocation for streaming is bounded by SecRequestBodyLimit --- apache2/msc_reqbody.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 1422065283..5327e1e2f5 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -434,7 +434,8 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf if (msr->stream_input_data == NULL) { // Is the request body length is known beforehand? (requests that are not Transfer-Encoding: chunked) if (msr->request_content_length > 0) { - allocate_length = msr->request_content_length; + // Use min of Content-Length and SecRequestBodyLimit + allocate_length = min(msr->request_content_length, msr->txcfg->reqbody_limit); } else { // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked) @@ -472,6 +473,9 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf "Unable to reallocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", allocate_length); free(msr->stream_input_data); + msr->stream_input_data = NULL; + msr->stream_input_length = 0; + msr->stream_input_allocated_length = 0; return -1; } } From 6ce7f4d68996b195b490b373cc47fefbfee19af4 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Tue, 22 Aug 2017 15:32:52 -0700 Subject: [PATCH 167/477] Remove the unneeded null termination for the stream_input_data --- apache2/re_operators.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index dbade1f49c..05db118fbf 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -636,15 +636,15 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_length = 0; msr->stream_input_allocated_length = 0; - msr->stream_input_data = (char *)malloc(size+1); + msr->stream_input_data = (char *)malloc(size); if(msr->stream_input_data == NULL) { return -1; } msr->stream_input_length = size; - msr->stream_input_allocated_length = size + 1; - memset(msr->stream_input_data, 0x0, size + 1); + msr->stream_input_allocated_length = size; + memset(msr->stream_input_data, 0x0, size); msr->if_stream_changed = 1; From 7fff8938baae58a8ce3236e0ee18d645e72a4d87 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Tue, 22 Aug 2017 17:12:37 -0700 Subject: [PATCH 168/477] Check return value of modsecurity_request_body_store --- apache2/apache2_io.c | 4 +++- apache2/msc_reqbody.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 74a7a7cd7f..9007f9d518 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -283,7 +283,9 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (msr->txcfg->stream_inbody_inspection == 1) { - modsecurity_request_body_to_stream(msr, buf, buflen, error_msg); + if (modsecurity_request_body_to_stream(msr, buf, buflen, error_msg) < 0) { + return -1; + } } msr->reqbody_length += buflen; diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 5327e1e2f5..77755a9eec 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -432,7 +432,7 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf char* allocated = NULL; if (msr->stream_input_data == NULL) { - // Is the request body length is known beforehand? (requests that are not Transfer-Encoding: chunked) + // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked) if (msr->request_content_length > 0) { // Use min of Content-Length and SecRequestBodyLimit allocate_length = min(msr->request_content_length, msr->txcfg->reqbody_limit); From 2e9ea0a6773ff2cd0f29a94d42dfc2b688b8517d Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Tue, 29 Aug 2017 23:22:04 -0700 Subject: [PATCH 169/477] Avoid use of min-macro, as it is not available in all envs --- apache2/msc_reqbody.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 77755a9eec..ebf4e51639 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -435,7 +435,7 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked) if (msr->request_content_length > 0) { // Use min of Content-Length and SecRequestBodyLimit - allocate_length = min(msr->request_content_length, msr->txcfg->reqbody_limit); + allocate_length = msr->request_content_length < msr->txcfg->reqbody_limit ? msr->request_content_length : msr->txcfg->reqbody_limit; } else { // We don't know how this request is going to be, so hope for just buflen to begin with (requests that are Transfer-Encoding: chunked) From 6406e2108db29697501a84015e46296b8d09356d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 18:25:52 +0000 Subject: [PATCH 170/477] Makes `large stream optimization' optional --- apache2/apache2_io.c | 6 ++++- apache2/modsecurity.h | 3 +++ apache2/msc_reqbody.c | 53 ++++++++++++++++++++++++++++++++++++++++-- apache2/re_operators.c | 9 ++++++- configure.ac | 18 +++++++++++++- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 9007f9d518..2e7325dc7b 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -192,7 +192,6 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Reading request body."); } - if (modsecurity_request_body_start(msr, error_msg) < 0) { return -1; } @@ -283,9 +282,14 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (msr->txcfg->stream_inbody_inspection == 1) { +#ifndef MSC_LARGE_STREAM_INPUT + msr->stream_input_length+=buflen; + modsecurity_request_body_to_stream(msr, buf, buflen, error_msg); +#else if (modsecurity_request_body_to_stream(msr, buf, buflen, error_msg) < 0) { return -1; } +#endif } msr->reqbody_length += buflen; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 601b5f2477..f24bc756a4 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -287,7 +287,10 @@ struct modsec_rec { unsigned int resbody_contains_html; apr_size_t stream_input_length; +#ifdef MSC_LARGE_STREAM_INPUT apr_size_t stream_input_allocated_length; +#endif + char *stream_input_data; apr_size_t stream_output_length; char *stream_output_data; diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index ebf4e51639..fc6b380bb5 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -428,9 +428,59 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { +#ifndef MSC_LARGE_STREAM_INPUT + char *stream_input_body = NULL; + char *data = NULL; + int first_pkt = 0; +#else apr_size_t allocate_length = 0; char* allocated = NULL; +#endif + +#ifndef MSC_LARGE_STREAM_INPUT + if(msr->stream_input_data == NULL) { + msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1); + first_pkt = 1; + } + else { + + data = (char *)malloc(msr->stream_input_length + 1 - buflen); + + if(data == NULL) + return -1; + + memset(data, 0, msr->stream_input_length + 1 - buflen); + memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen); + + stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1); + + msr->stream_input_data = (char *)stream_input_body; + } + + if (msr->stream_input_data == NULL) { + if(data) { + free(data); + data = NULL; + } + *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", + msr->stream_input_length + 1); + return -1; + } + + memset(msr->stream_input_data, 0, msr->stream_input_length+1); + + if(first_pkt) { + memcpy(msr->stream_input_data, buffer, msr->stream_input_length); + } else { + memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen); + memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen); + } + if(data) { + free(data); + data = NULL; + } +#else if (msr->stream_input_data == NULL) { // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked) if (msr->request_content_length > 0) { @@ -458,7 +508,6 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf else { // Do we need to expand the space we have previously allocated? if ((msr->stream_input_length + buflen) > msr->stream_input_allocated_length) { - // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs allocate_length = msr->stream_input_length + buflen; @@ -480,10 +529,10 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf } } } - // Append buffer to msr->stream_input_data memcpy(msr->stream_input_data + msr->stream_input_length, buffer, buflen); msr->stream_input_length += buflen; +#endif return 1; } diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 05db118fbf..b6d1c03c94 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -634,18 +634,25 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; +#ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = 0; msr->stream_input_data = (char *)malloc(size); +#else + msr->stream_input_data = (char *)malloc(size+1); +#endif if(msr->stream_input_data == NULL) { return -1; } msr->stream_input_length = size; +#ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = size; memset(msr->stream_input_data, 0x0, size); - +#else + memset(msr->stream_input_data, 0x0, size+1); +#endif msr->if_stream_changed = 1; memcpy(msr->stream_input_data, data, size); diff --git a/configure.ac b/configure.ac index e3a3595fde..01d2fb4b81 100644 --- a/configure.ac +++ b/configure.ac @@ -690,6 +690,22 @@ AC_ARG_ENABLE(modsec-api, modsec_api= ]) +# MSC_LARGE_STREAM_INPUT +AC_ARG_ENABLE(large-stream-input, + AS_HELP_STRING([--enable-large-stream-input], + [Enable optimization for large stream input]), +[ + if test "$enableval" == "yes"; then + large_stream_input="-DMSC_LARGE_STREAM_INPUT" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" + else + large_stream_input= + fi +], +[ + large_stream_input= +]) + # Find apxs AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) AC_ARG_WITH(apxs, @@ -812,7 +828,7 @@ else fi fi -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 4ee1d9c1796700bb85a494291fc3a6f27410c068 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 5 Oct 2017 18:28:07 +0000 Subject: [PATCH 171/477] Adds information on #1538 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 327b2bd3f4..2c254d8cd8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Optionally preallocates memory when SecStreamInBodyInspection is on + [Issue #1366 - @allanbomsft, @zimmerle] * Fixed typo in build_yajl.bat [Issue #1366 - @allanbomsft] * Fixes SecConnWriteStateLimit From f86de566d18dda6351ecba52d5e5f1d29ad02a12 Mon Sep 17 00:00:00 2001 From: florian-eichelberger <florian-eichelberger@users.noreply.github.com> Date: Tue, 30 May 2017 22:05:16 -0300 Subject: [PATCH 172/477] Enables sanitizing of json request bodies in the apache module for native log format --- apache2/msc_json.c | 5 +++++ apache2/msc_logging.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 0f9a4645e2..1909f9b52e 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -16,6 +16,8 @@ #ifdef WITH_YAJL +char *base_offset=NULL; + int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { msc_arg *arg = (msc_arg *) NULL; @@ -48,6 +50,8 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) */ arg->value = apr_pstrmemdup(msr->mp, value, length); arg->value_len = length; + arg->value_origin_len = length; + arg->value_origin_offset = value-base_offset; arg->origin = "JSON"; if (msr->txcfg->debuglog_level >= 9) { @@ -273,6 +277,7 @@ int json_init(modsec_rec *msr, char **error_msg) { int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; + base_offset=buf; /* Feed our parser and catch any errors */ msr->json->status = yajl_parse(msr->json->handle, buf, size); diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index cb0297a437..6ee1e58333 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -878,7 +878,7 @@ void sec_audit_logger_json(modsec_rec *msr) { for(i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; if (arg->origin != NULL && - strcmp(arg->origin, "BODY") != 0) + ( strcmp(arg->origin, "BODY") != 0 && strcmp(arg->origin, "JSON") !=0) ) continue; if (last_offset == 0) { /* The first time we're here. */ From 9ae7b6e1e5f6dadec980c0800ff6070412471252 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 28 Feb 2018 11:16:34 -0300 Subject: [PATCH 173/477] Fix arabic charset in unicode_mapping file Contribution from @alaa-ahmed-a --- unicode.mapping | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unicode.mapping b/unicode.mapping index 6af8117f38..2654c4a619 100644 --- a/unicode.mapping +++ b/unicode.mapping @@ -23,7 +23,7 @@ 0191:46 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e 1256 (ANSI - Arabic) -00c0:41 00c2:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00ce:49 00cf:49 00d4:4f 00d9:55 00db:55 00dc:55 0191:46 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e +0620:41 0621:41 0622:43 0623:45 0624:45 0625:45 0626:45 0627:49 0628:49 0629:4f 062a:55 062b:55 062c:55 062d:46 062e:43 062f:44 0630:45 0631:46 0632:47 0633:48 0634:49 0635:4a 0636:4b 0637:4c 0638:4d 0639:4e 063a:4f 0641:41 0642:42 0643:43 0644:44 0645:45 0646:46 0647:47 0648:48 0649:49 064a:4a 064b:4b 064c:4c 064d:4d 064e:4e 064f:4f 0650:50 0651:51 0652:52 1257 (ANSI - Baltic) ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e From 203e85e33f517ad0e739680b78aaacbb2253d8dd Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 28 Feb 2018 11:20:13 -0300 Subject: [PATCH 174/477] Adds information on #1619 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 2c254d8cd8..bec10a4818 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix arabic charset in unicode_mapping file + [Issue #1619 - @alaa-ahmed-a] * Optionally preallocates memory when SecStreamInBodyInspection is on [Issue #1366 - @allanbomsft, @zimmerle] * Fixed typo in build_yajl.bat From 830f0b7c54cae1546166c3e146f51e3f27ad8947 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 20 Mar 2018 10:57:19 -0700 Subject: [PATCH 175/477] Fix compiler warning in JSON parser --- apache2/msc_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 1909f9b52e..3a7a03d728 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -16,7 +16,7 @@ #ifdef WITH_YAJL -char *base_offset=NULL; +const char *base_offset=NULL; int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { From 8d4124eee26cc018f6ed306e0d404737ce82c849 Mon Sep 17 00:00:00 2001 From: Robert Paprocki <robert@cryptobells.com> Date: Tue, 20 Mar 2018 11:35:40 -0700 Subject: [PATCH 176/477] Enable sanitizing JSON request bodies in native audit log format f86de56 enabled sanitizing JSON request body data in JSON audit log formats (the commit message is misleading). This commit supplements JSON request body sanitization to support sanitized elements in native audit log formats. --- apache2/msc_logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 6ee1e58333..47fbfe7774 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1739,7 +1739,7 @@ void sec_audit_logger_native(modsec_rec *msr) { for(i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; if (arg->origin != NULL && - strcmp(arg->origin, "BODY") != 0) + ( strcmp(arg->origin, "BODY") != 0 && strcmp(arg->origin, "JSON") != 0) ) continue; if (last_offset == 0) { /* The first time we're here. */ From d6366d12e6db3427ce48e364d8eb65e25c78ee8c Mon Sep 17 00:00:00 2001 From: Charles Peterson <cpeterson@brokerbin.com> Date: Tue, 8 May 2018 12:40:23 -0500 Subject: [PATCH 177/477] fix when multiple lines for curl version example.... ### before fix ```bash # /usr/bin/curl --version | sed 's/^[^0-9][^[:space:]][^[:space:]]*[[:space:]]*//' 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 tftp ftp telnet dict ldap ldaps http file https ftps scp sftp GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz ``` ### after fix ```bash # /usr/bin/curl --version | sed 's/^[^0-9][^[:space:]][^[:space:]]*[[:space:]]*//' | tr '\r\n' ' ' 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2 tftp ftp telnet dict ldap ldaps http file https ftps scp sftp GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz ``` --- build/find_curl.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/find_curl.m4 b/build/find_curl.m4 index 3310e40494..d868a30f03 100644 --- a/build/find_curl.m4 +++ b/build/find_curl.m4 @@ -54,7 +54,7 @@ if test -n "${curl_path}"; then CURL_CONFIG="${curl_path}/${CURL_CONFIG}" fi AC_MSG_RESULT([${CURL_CONFIG}]) - CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//'` + CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//' | tr '\r\n' ' '` if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl VERSION: $CURL_VERSION); fi CURL_CFLAGS="`${CURL_CONFIG} --cflags`" if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl CFLAGS: $CURL_CFLAGS); fi From 7aa2f2dd5af673e32dd7cc4893c5c78820954ae2 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 10 May 2018 15:32:38 -0300 Subject: [PATCH 178/477] Adds information about #1771 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index bec10a4818..9be2584025 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * build: fix when multiple lines for curl version + [Issue #1771 - @Artistan] * Fix arabic charset in unicode_mapping file [Issue #1619 - @alaa-ahmed-a] * Optionally preallocates memory when SecStreamInBodyInspection is on From ec7110219754702a6f830696cf8fefecd7f2cfd2 Mon Sep 17 00:00:00 2001 From: Padraig Doran <padraigdoran@users.noreply.github.com> Date: Sun, 25 Mar 2018 17:38:54 +0100 Subject: [PATCH 179/477] Fix spelling "reachers" should be "reaches" --- modsecurity.conf-recommended | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 728afc1afd..60317acb74 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -39,7 +39,7 @@ SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072 # Store up to 128 KB of request body data in memory. When the multipart -# parser reachers this limit, it will start using your hard disk for +# parser reaches this limit, it will start using your hard disk for # storage. That is slow, but unavoidable. # SecRequestBodyInMemoryLimit 131072 From 21adc0a7686341cd756f271d751239ed8b92cda9 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 10 May 2018 18:42:45 -0300 Subject: [PATCH 180/477] Adds information about #1721 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 9be2584025..8420734606 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * modsecurity.conf-recommended: Fix spelling + [Issue #1721 - @padraigdoran] * build: fix when multiple lines for curl version [Issue #1771 - @Artistan] * Fix arabic charset in unicode_mapping file From 9bfdbc57dbd9bbd8d737ec3989e60a3d9f5f1aef Mon Sep 17 00:00:00 2001 From: Ryan Kramer <default.kramer@gmail.com> Date: Wed, 23 May 2018 17:01:38 -0500 Subject: [PATCH 181/477] IIS: set overrideModeDefault to Allow so that individual websites can add <ModSecurity ...> to their web.config file --- iis/installer.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/installer.wxs b/iis/installer.wxs index 015c9351f8..271d9cba87 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -346,7 +346,7 @@ <!-- Modify ApplicationHost.config --> <util:XmlConfig Id="appHostEntry" File="$(var.ConfigFile)" Action="create" ElementPath="//configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" VerifyPath="section[\[]@name='ModSecurity'[\]]" Name="section" Node="element" Sequence="1" On="install" /> <util:XmlConfig Id="appHostEntryName" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="name" Value="ModSecurity" Sequence="2" /> - <util:XmlConfig Id="appHostEntryOverrideMode" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="overrideModeDefault" Value="Deny" Sequence="3" /> + <util:XmlConfig Id="appHostEntryOverrideMode" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="overrideModeDefault" Value="Allow" Sequence="3" /> <util:XmlConfig Id="appHostEntryAllowDefinition" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="allowDefinition" Value="Everywhere" Sequence="4" /> <util:XmlConfig Id="removeAppHostEntry" File="$(var.ConfigFile)" Action="delete" ElementPath="/configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" Node="element" VerifyPath="section[\[]@name='ModSecurity'[\]]" On="uninstall" Sequence="1" /> <util:XmlConfig Id="removeAppHostEntry2" File="$(var.ConfigFile)" Action="delete" ElementPath="/configuration/system.webServer" Node="element" VerifyPath="/configuration/system.webServer/ModSecurity" Name="section" On="uninstall" Sequence="2" /> From 71f650ad48c8b92ddf76817a86824b66a431a0d5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 28 May 2018 17:55:37 -0300 Subject: [PATCH 182/477] Adds information on #1781 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 8420734606..ed4f105f51 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: set overrideModeDefault to Allow so that individual websites can + add <ModSecurity ...> to their web.config file + [Issue #1781 - @default-kramer] * modsecurity.conf-recommended: Fix spelling [Issue #1721 - @padraigdoran] * build: fix when multiple lines for curl version From f66cd4111f08a26d4429cb0071e992deb050928a Mon Sep 17 00:00:00 2001 From: Reed Morrison <reed.morrison@verizondigitalmedia.com> Date: Thu, 7 Jun 2018 14:48:18 -0300 Subject: [PATCH 183/477] Fix ip tree lookup on netmask content --- CHANGES | 2 ++ apache2/msc_tree.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index ed4f105f51..30d0ea5463 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix ip tree lookup on netmask content + [Issue #1793 - @tinselcity, @zimmerle] * IIS: set overrideModeDefault to Allow so that individual websites can add <ModSecurity ...> to their web.config file [Issue #1781 - @default-kramer] diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index ddbc4f2149..07c76a0060 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -755,7 +755,7 @@ TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip return node; } - if (memcmp(node->prefix->buffer, temp_data, bytes) == 0) { + if ((node->netmasks == NULL) && (memcmp(node->prefix->buffer, temp_data, bytes) == 0)) { mask = SHIFT_LEFT_MASK(8 - ip_bitmask % 8); if ((ip_bitmask % 8) == 0) { From 739048749e11eeb2344151ef2412106362ad494b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 4 Sep 2018 21:00:26 -0300 Subject: [PATCH 184/477] Fix utf-8 character encoding conversion Reported on: #1794 --- CHANGES | 2 ++ apache2/re_operators.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 30d0ea5463..0650fa9369 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix utf-8 character encoding conversion + [Issue #1794 - @tinselcity, @zimmerle] * Fix ip tree lookup on netmask content [Issue #1793 - @tinselcity, @zimmerle] * IIS: set overrideModeDefault to Allow so that individual websites can diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b6d1c03c94..e0fc6fa857 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -4321,7 +4321,7 @@ static int detect_utf8_character(const unsigned char *p_read, unsigned int lengt else { unicode_len = 4; /* compute character number */ - d = ((c & 0x07) << 18) | ((*(p_read + 1) & 0x3F) << 12) | ((*(p_read + 2) & 0x3F) < 6) | (*(p_read + 3) & 0x3F); + d = ((c & 0x07) << 18) | ((*(p_read + 1) & 0x3F) << 12) | ((*(p_read + 2) & 0x3F) << 6) | (*(p_read + 3) & 0x3F); } } /* any other first byte is invalid (RFC 3629) */ From fecc4296e34897bc62bba644a2f73e13b6dd3ac0 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 4 Sep 2018 22:40:26 -0300 Subject: [PATCH 185/477] Adds more tests to REQUEST_BASENAME Meant to test #1795 --- tests/regression/target/00-targets.t | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/regression/target/00-targets.t b/tests/regression/target/00-targets.t index d00b5a50c8..62846c0bef 100644 --- a/tests/regression/target/00-targets.t +++ b/tests/regression/target/00-targets.t @@ -475,8 +475,29 @@ "arg1=val1&arg2=val2", ), }, - - +{ + type => "target", + comment => "REQUEST_BASENAME (get)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecResponseBodyAccess On + SecResponseBodyMimeType null + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_BASENAME "index.html" "phase:2,log,pass,id:500189" + ), + match_log => { + error => [ qr/Pattern match "index.html" at REQUEST_BASENAME.*/s, 1 ], + debug => [ qr/Pattern match "index.html" at REQUEST_BASENAME.*/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/index.html?apath=/my/cool/path.com", + ), +}, # AUTH_TYPE #{ From 89f5427c1c0e062dd674649cebb078686d011a8f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 5 Sep 2018 15:33:39 -0300 Subject: [PATCH 186/477] potential off by one in parse_arguments Issue: #1799 --- CHANGES | 3 ++- apache2/msc_parsers.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 0650fa9369..a5d5ceaec3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,7 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ - + * potential off by one in parse_arguments + [Issue #1799 - @tinselcity, @zimmerle] * Fix utf-8 character encoding conversion [Issue #1794 - @tinselcity, @zimmerle] * Fix ip tree lookup on netmask content diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 57f291ec2a..61344aa1b9 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -266,7 +266,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, if (status == 0) { /* parameter name */ arg->name_origin_offset = i; - while ((s[i] != '=') && (s[i] != argument_separator) && (i < inputlength)) { + while ((i < inputlength) && (s[i] != '=') && (s[i] != argument_separator)) { buf[j] = s[i]; j++; i++; From 2ae357be8865f4ab2a2092853c703a719fad627f Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Mon, 6 Nov 2017 14:03:25 -0800 Subject: [PATCH 187/477] Let body parsers observe SecRequestBodyNoFilesLimit Previously, modsecurity_request_body_store would keep feeding the body parsers (JSON/XML/Multipart) even after the SecRequestBodyNoFilesLimit limit was met. This change prevents this. Also, modsecurity_request_body_end now returns an error code when the limit is met, so that a message can be logged for this event. --- apache2/apache2_io.c | 5 ++--- apache2/msc_reqbody.c | 17 +++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 2e7325dc7b..66b865f37e 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -335,8 +335,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { apr_brigade_cleanup(bb_in); } while(!finished_reading); - // TODO: Why ignore the return code here? - modsecurity_request_body_end(msr, error_msg); + apr_status_t rcbe = modsecurity_request_body_end(msr, error_msg); if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Completed receiving request body (length %" APR_SIZE_T_FMT ").", @@ -345,7 +344,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { msr->if_status = IF_STATUS_WANTS_TO_RUN; - return 1; + return rcbe; } diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index fc6b380bb5..337343735a 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -396,13 +396,14 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, /* Check that we are not over the request body no files limit. */ if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) { - *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); if (msr->txcfg->debuglog_level >= 1) { msr_log(msr, 1, "%s", *error_msg); } + msr->msc_reqbody_error = 1; + if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { return -5; } else if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) { @@ -411,7 +412,6 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } } - /* Store data. */ if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { return modsecurity_request_body_store_memory(msr, data, length, error_msg); @@ -656,6 +656,19 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { /* Note that we've read the body. */ msr->msc_reqbody_read = 1; + + /* Check that we are not over the request body no files limit. */ + if (msr->msc_reqbody_no_files_length >= (unsigned long)msr->txcfg->reqbody_no_files_limit) { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + if (msr->txcfg->debuglog_level >= 1) { + msr_log(msr, 1, "%s", *error_msg); + } + + return -5; + } + + /* Finalise body processing. */ if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) { char *my_error_msg = NULL; From 6bb44619111cfd64d6449922eaaa0d148ac7d84c Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Wed, 23 May 2018 19:21:25 -0700 Subject: [PATCH 188/477] AppGw WAF version that doesn't block failed body parsing in detect-only mode --- apache2/mod_security2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index fb399362f5..7bb215e2ed 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1013,7 +1013,7 @@ static int hook_request_late(request_rec *r) { } rc = read_request_body(msr, &my_error_msg); - if (rc < 0) { + if (rc < 0 && msr->txcfg->is_enabled == MODSEC_ENABLED) { switch(rc) { case -1 : if (my_error_msg != NULL) { From 5367bca1b372f4f602ffa5bf0139735165bd84a1 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 5 Sep 2018 16:27:49 -0300 Subject: [PATCH 189/477] CHANGES: adds info on #1613 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index a5d5ceaec3..f63afc4136 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + + * Let body parsers observe SecRequestBodyNoFilesLimit + [Issue #1613 - @allanbomsft] * potential off by one in parse_arguments [Issue #1799 - @tinselcity, @zimmerle] * Fix utf-8 character encoding conversion From 8dd40709ee266515b28e248b1215bb8c9f6f710e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 5 Sep 2018 23:25:51 -0300 Subject: [PATCH 190/477] good practices: Initialize variables before use it Original author: Marc Stern (#1889) --- CHANGES | 2 ++ apache2/msc_util.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index f63afc4136..b62c2ac620 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * good practices: Initialize variables before use it + [Issue #1889 - Marc Stern] * Let body parsers observe SecRequestBodyNoFilesLimit [Issue #1613 - @allanbomsft] * potential off by one in parse_arguments diff --git a/apache2/msc_util.c b/apache2/msc_util.c index e3923ff2f8..2cc6065fd6 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -405,7 +405,8 @@ char *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule char converted = 0; int i, x; unsigned char bin = 0, esc = 0, bin_offset = 0; - unsigned char bin_parm[3], c = 0; + unsigned char c = 0; + unsigned char bin_parm[3] = { 0 }; char *processed = NULL; content = apr_pstrdup(rule->ruleset->mp, op_parm); From 18af2597779c0e8947e9541104f6100c1667ba22 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Wed, 10 Jan 2018 18:36:52 -0800 Subject: [PATCH 191/477] IIS, buffer request body before taking lock IIS, buffer request body before taking lock --- iis/mymodule.cpp | 121 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 27 deletions(-) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 607fdf0a6d..627c6ab738 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -32,6 +32,13 @@ #include "winsock2.h" +// Used to hold each chunk of request body that gets read before the full ModSec engine is invoked +typedef struct preAllocBodyChunk { + preAllocBodyChunk* next; + size_t length; + void* data; +} preAllocBodyChunk; + class REQUEST_STORED_CONTEXT : public IHttpStoredContext { public: @@ -82,8 +89,11 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *m_pResponseBuffer; ULONGLONG m_pResponseLength; ULONGLONG m_pResponsePosition; + + preAllocBodyChunk* requestBodyBufferHead; }; + //---------------------------------------------------------------------------- char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) @@ -286,6 +296,44 @@ REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r) return NULL; } +HRESULT GetRequestBodyFromIIS(IHttpRequest* pRequest, preAllocBodyChunk** head) +{ + HRESULT hr = S_OK; + HTTP_REQUEST * pRawRequest = pRequest->GetRawHttpRequest(); + preAllocBodyChunk** cur = head; + while (pRequest->GetRemainingEntityBytes() > 0) + { + // Allocate memory for the preAllocBodyChunk linked list structure, and also the actual body content + // HUGE_STRING_LEN is hardcoded because this is also hardcoded in apache2_io.c's call to ap_get_brigade + preAllocBodyChunk* chunk = (preAllocBodyChunk*)malloc(sizeof(preAllocBodyChunk) + HUGE_STRING_LEN); + chunk->next = NULL; + + // Pointer to rest of allocated memory, for convenience + chunk->data = chunk + 1; + + DWORD readcnt = 0; + hr = pRequest->ReadEntityBody(chunk->data, HUGE_STRING_LEN, false, &readcnt, NULL); + if (ERROR_HANDLE_EOF == (hr & 0x0000FFFF)) + { + free(chunk); + hr = S_OK; + break; + } + chunk->length = readcnt; + + // Append to linked list + *cur = chunk; + cur = &(chunk->next); + + if (hr != S_OK) + { + break; + } + } + + return hr; +} + HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf) { OVERLAPPED ovl; @@ -752,6 +800,24 @@ CMyHttpModule::OnBeginRequest( goto Finished; } + // Get request body without holding lock, because some clients may be slow at sending + LeaveCriticalSection(&m_csLock); + preAllocBodyChunk* requestBodyBufferHead = NULL; + hr = GetRequestBodyFromIIS(pRequest, &requestBodyBufferHead); + if (hr != S_OK) + { + goto FinishedWithoutLock; + } + EnterCriticalSection(&m_csLock); + + // Get the config again, in case it changed during the time we released the lock + hr = MODSECURITY_STORED_CONTEXT::GetConfig(pHttpContext, &pConfig); + if (FAILED(hr)) + { + hr = S_OK; + goto Finished; + } + // every 3 seconds we check for changes in config file // DWORD ctime = GetTickCount(); @@ -841,6 +907,8 @@ CMyHttpModule::OnBeginRequest( rsc->m_pRequestRec = r; rsc->m_pHttpContext = pHttpContext; rsc->m_pProvider = pProvider; + rsc->requestBodyBufferHead = requestBodyBufferHead; + requestBodyBufferHead = NULL; // This is to indicate to the cleanup process to use rsc->requestBodyBufferHead instead of requestBodyBufferHead now pHttpContext->GetModuleContextContainer()->SetModuleContext(rsc, g_pModuleContext); @@ -1086,6 +1154,16 @@ CMyHttpModule::OnBeginRequest( Finished: LeaveCriticalSection(&m_csLock); +FinishedWithoutLock: + // Free the preallocated body in case there was a failure and it wasn't consumed already + preAllocBodyChunk* chunkToFree = requestBodyBufferHead ? requestBodyBufferHead : rsc->requestBodyBufferHead; + while (chunkToFree != NULL) + { + preAllocBodyChunk* next = chunkToFree->next; + free(chunkToFree); + chunkToFree = next; + } + if ( FAILED( hr ) ) { return RQ_NOTIFICATION_FINISH_REQUEST; @@ -1095,40 +1173,29 @@ CMyHttpModule::OnBeginRequest( apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos) { - REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r); - - *readcnt = 0; - - if(rsc == NULL) - { - *is_eos = 1; - return APR_SUCCESS; - } + REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r); - IHttpContext *pHttpContext = rsc->m_pHttpContext; - IHttpRequest *pRequest = pHttpContext->GetRequest(); + if (rsc->requestBodyBufferHead == NULL) + { + *is_eos = 1; + return APR_SUCCESS; + } - if(pRequest->GetRemainingEntityBytes() == 0) - { - *is_eos = 1; - return APR_SUCCESS; - } + *readcnt = length < (unsigned int) rsc->requestBodyBufferHead->length ? length : (unsigned int) rsc->requestBodyBufferHead->length; + void* src = (char*)rsc->requestBodyBufferHead->data; + memcpy_s(buf, length, src, *readcnt); - HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL); + // Remove the front and proceed to next chunk in the linked list + preAllocBodyChunk* chunkToFree = rsc->requestBodyBufferHead; + rsc->requestBodyBufferHead = rsc->requestBodyBufferHead->next; + free(chunkToFree); - if (FAILED(hr)) + if (rsc->requestBodyBufferHead == NULL) { - // End of data is okay. - if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF)) - { - // Set the error status. - rsc->m_pProvider->SetErrorStatus( hr ); - } - - *is_eos = 1; + *is_eos = 1; } - return APR_SUCCESS; + return APR_SUCCESS; } apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length) From 6bc838eeaf68ced890544add26cf92d96b14fdd5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 6 Sep 2018 10:03:15 -0300 Subject: [PATCH 192/477] CHANGES: adds info on #1651 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index b62c2ac620..232d3131f3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: buffer request body before taking lock + [Issue #1651 - @allanbomsft] * good practices: Initialize variables before use it [Issue #1889 - Marc Stern] * Let body parsers observe SecRequestBodyNoFilesLimit From 51a971760154e1f628d29a1b1ba94e05fd1c1c2e Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Wed, 6 Jun 2018 20:08:03 -0700 Subject: [PATCH 193/477] IIS: no lock on ProcessRequest. No reload of config. (#24) IIS: no lock on ProcessRequest. No reload of config. --- iis/moduleconfig.cpp | 5 +--- iis/moduleconfig.h | 2 -- iis/mymodule.cpp | 65 +++++++++++++++++--------------------------- 3 files changed, 26 insertions(+), 46 deletions(-) diff --git a/iis/moduleconfig.cpp b/iis/moduleconfig.cpp index a92d51ffb1..d3bcefc9b6 100644 --- a/iis/moduleconfig.cpp +++ b/iis/moduleconfig.cpp @@ -466,11 +466,8 @@ MODSECURITY_STORED_CONTEXT::~MODSECURITY_STORED_CONTEXT() MODSECURITY_STORED_CONTEXT::MODSECURITY_STORED_CONTEXT(): m_bIsEnabled ( FALSE ), m_pszPath( NULL ), - m_Config( NULL ), - m_dwLastCheck( 0 ) + m_Config( NULL ) { - m_LastChange.dwLowDateTime = 0; - m_LastChange.dwHighDateTime = 0; } DWORD diff --git a/iis/moduleconfig.h b/iis/moduleconfig.h index 83b7517d34..75ee71dca2 100644 --- a/iis/moduleconfig.h +++ b/iis/moduleconfig.h @@ -68,8 +68,6 @@ class MODSECURITY_STORED_CONTEXT : public IHttpStoredContext USHORT* pdwLengthDestination ); void* m_Config; - DWORD m_dwLastCheck; - FILETIME m_LastChange; private: HRESULT diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 627c6ab738..32decf43da 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -818,11 +818,7 @@ CMyHttpModule::OnBeginRequest( goto Finished; } - // every 3 seconds we check for changes in config file - // - DWORD ctime = GetTickCount(); - - if(pConfig->m_Config == NULL || (ctime - pConfig->m_dwLastCheck) > 3000) + if(pConfig->m_Config == NULL) { char *path; USHORT pathlen; @@ -835,55 +831,42 @@ CMyHttpModule::OnBeginRequest( goto Finished; } - WIN32_FILE_ATTRIBUTE_DATA fdata; - BOOL ret; + pConfig->m_Config = modsecGetDefaultConfig(); - ret = GetFileAttributesEx(path, GetFileExInfoStandard, &fdata); + PCWSTR servpath = pHttpContext->GetApplication()->GetApplicationPhysicalPath(); + char *apppath; + USHORT apppathlen; - pConfig->m_dwLastCheck = ctime; + hr = pConfig->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen); - if(pConfig->m_Config == NULL || (ret != 0 && (pConfig->m_LastChange.dwLowDateTime != fdata.ftLastWriteTime.dwLowDateTime || - pConfig->m_LastChange.dwHighDateTime != fdata.ftLastWriteTime.dwHighDateTime))) + if ( FAILED( hr ) ) { - pConfig->m_LastChange.dwLowDateTime = fdata.ftLastWriteTime.dwLowDateTime; - pConfig->m_LastChange.dwHighDateTime = fdata.ftLastWriteTime.dwHighDateTime; - - pConfig->m_Config = modsecGetDefaultConfig(); - - PCWSTR servpath = pHttpContext->GetApplication()->GetApplicationPhysicalPath(); - char *apppath; - USHORT apppathlen; + delete path; + hr = E_UNEXPECTED; + goto Finished; + } - hr = pConfig->GlobalWideCharToMultiByte((WCHAR *)servpath, wcslen(servpath), &apppath, &apppathlen); + if(path[0] != 0) + { + const char * err = modsecProcessConfig((directory_config *)pConfig->m_Config, path, apppath); - if ( FAILED( hr ) ) + if(err != NULL) { + WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE); + delete apppath; delete path; - hr = E_UNEXPECTED; goto Finished; } - if(path[0] != 0) + modsecReportRemoteLoadedRules(); + if (this->status_call_already_sent == false) { - const char * err = modsecProcessConfig((directory_config *)pConfig->m_Config, path, apppath); - - if(err != NULL) - { - WriteEventViewerLog(err, EVENTLOG_ERROR_TYPE); - delete apppath; - delete path; - goto Finished; - } - - modsecReportRemoteLoadedRules(); - if (this->status_call_already_sent == false) - { - this->status_call_already_sent = true; - modsecStatusEngineCall(); - } + this->status_call_already_sent = true; + modsecStatusEngineCall(); } - delete apppath; } + + delete apppath; delete path; } @@ -1140,7 +1123,9 @@ CMyHttpModule::OnBeginRequest( #endif c->remote_host = NULL; + LeaveCriticalSection(&m_csLock); int status = modsecProcessRequest(r); + EnterCriticalSection(&m_csLock); if(status != DECLINED) { From a168669cb5cba90a4d6109eb8a7bb188d6f20c3f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 6 Sep 2018 10:09:12 -0300 Subject: [PATCH 194/477] CHANGES: adds info on #1826 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 232d3131f3..f417ec68ff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: no lock on ProcessRequest. No reload of config. + [Issue #1826 - @allanbomsft] * IIS: buffer request body before taking lock [Issue #1651 - @allanbomsft] * good practices: Initialize variables before use it From b76f961aae75b4f5b0d52e8a07d08aafdf9ad004 Mon Sep 17 00:00:00 2001 From: Yang Luo <hsluoyz@qq.com> Date: Sat, 28 Jul 2018 22:09:13 +0800 Subject: [PATCH 195/477] Reformat the README to Markdown --- README.TXT | 110 ----------------------- README.md | 70 +++++++++++++++ README_WINDOWS.TXT => README_WINDOWS.md | 112 ++++++++++++------------ 3 files changed, 128 insertions(+), 164 deletions(-) delete mode 100644 README.TXT create mode 100644 README.md rename README_WINDOWS.TXT => README_WINDOWS.md (52%) diff --git a/README.TXT b/README.TXT deleted file mode 100644 index 03767e345f..0000000000 --- a/README.TXT +++ /dev/null @@ -1,110 +0,0 @@ -ModSecurity for Apache 2.x, http://www.modsecurity.org/ -Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) - -You may not use this file except in compliance with -the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -If any of the files related to licensing are missing or if you have any -other questions related to licensing please contact Trustwave Holdings, Inc. -directly using the email address security@modsecurity.org. - - -DOCUMENTATION - -Please refer to the documentation folder (/doc) for -the reference manual. - - -############################################## ----------------------------------- -OWASP ModSecurity Core Rule Set (CRS) - - -Project Site: -https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project - - -Download: -https://github.com/SpiderLabs/owasp-modsecurity-crs - ----------------------------------- - -ModSecurityâ„¢ is a web application firewall engine that provides very -little protection on its own. In order to become useful, ModSecurityâ„¢ must -be configured with rules. In order to enable users to take full advantage -of ModSecurityâ„¢ out of the box, Trustwave's SpiderLabs is providing a free -certified rule set for ModSecurityâ„¢ 2.x. Unlike intrusion detection and -prevention systems, which rely on signatures specific to known -vulnerabilities, the Core Rules provide generic protection from unknown -vulnerabilities often found in web applications, which are in most cases -custom coded. The Core Rules are heavily commented to allow it to be used -as a step-by-step deployment guide for ModSecurityâ„¢. -Core Rules Content - -In order to provide generic web applications protection, the Core Rules -use the following techniques: - -* HTTP Protection - detecting violations of the HTTP protocol and a -locally defined usage policy. -* Real-time Blacklist Lookups - utilizes 3rd Party IP Reputation -* Web-based Malware Detection - identifies malicious web content by check -against the Google Safe Browsing API. -* HTTP Denial of Service Protections - defense against HTTP Flooding and -Slow HTTP DoS Attacks. -* Common Web Attacks Protection - detecting common web application -security attack. -* Automation Detection - Detecting bots, crawlers, scanners and other -surface malicious activity. -* Integration with AV Scanning for File Uploads - detects malicious files -uploaded through the web application. -* Tracking Sensitive Data - Tracks Credit Card usage and blocks leakages. -* Trojan Protection - Detecting access to Trojans horses. -* Identification of Application Defects - alerts on application -misconfigurations. -* Error Detection and Hiding - Disguising error messages sent by the -server. - - ----------------------------------- -ModSecurity Rules from Trustwave SpiderLabs - -Project Site: -https://www.trustwave.com/modsecurity-rules-support.php - -Download: -https://ssl.trustwave.com/web-application-firewall - ----------------------------------- - - - -Trustwave now provides a commercial certified rule set for ModSecurity 2.x -that protects against known attacks that target vulnerabilities in public -software and are based on intelligence gathered from real-world -investigations, honeypot data and research. - -1. More than 16,000 specific rules, broken out into the following attack -categories: - * SQL injection - * Cross-site Scripting (XSS) - * Local File Include - * Remote File Include - -2. User option for application specific rules, covering the same -vulnerability classes for applications such as: - * WordPress - * cPanel - * osCommerce - * Joomla - * For a complete listing of application coverage, please refer to this -link (which is updated daily). -https://modsecurity.org/application_coverage.html - -3. Complements and integrates with the OWASP Core Rule Set -4. IP Reputation capabilities which provide protection against malicious -clients identified by the Trustwave SpiderLabs Distributed Web Honeypots -5. Malware Detection capabilities which prevent your web site from -distributing malicious code to clients. -############################################## diff --git a/README.md b/README.md new file mode 100644 index 0000000000..a40c07e8a0 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +ModSecurity for Apache 2.x +====== + +http://www.modsecurity.org/ + +Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) + +You may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 + +If any of the files related to licensing are missing or if you have any other questions related to licensing please contact Trustwave Holdings, Inc. directly using the email address: security@modsecurity.org. + + +## Documentation + +Please refer to: [the documentation folder](https://github.com/SpiderLabs/ModSecurity/tree/v2/master/doc) for the reference manual. + +## OWASP ModSecurity Core Rule Set (CRS) + +Project Site: https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project + +Download: https://github.com/SpiderLabs/owasp-modsecurity-crs + +ModSecurityâ„¢ is a web application firewall engine that provides very little protection on its own. In order to become useful, ModSecurityâ„¢ must be configured with rules. In order to enable users to take full advantage of ModSecurityâ„¢ out of the box, Trustwave's SpiderLabs is providing a free certified rule set for ModSecurityâ„¢ 2.x. + +Unlike intrusion detection and prevention systems, which rely on signatures specific to known vulnerabilities, the Core Rules provide generic protection from unknown vulnerabilities often found in web applications, which are in most cases custom coded. The Core Rules are heavily commented to allow it to be used as a step-by-step deployment guide for ModSecurityâ„¢. + +### Core Rules Content + +In order to provide generic web applications protection, the Core Rules use the following techniques: + +* **HTTP Protection** - detecting violations of the HTTP protocol and a locally defined usage policy. +* **Real-time Blacklist Lookups** - utilizes 3rd Party IP Reputation +* **Web-based Malware Detection** - identifies malicious web content by check against the Google Safe Browsing API. +* **HTTP Denial of Service Protections** - defense against HTTP Flooding and Slow HTTP DoS Attacks. +* **Common Web Attacks Protection** - detecting common web application security attack. +* **Automation Detection** - Detecting bots, crawlers, scanners and other surface malicious activity. +* **Integration with AV Scanning for File Uploads** - detects malicious files uploaded through the web application. +* **Tracking Sensitive Data** - Tracks Credit Card usage and blocks leakages. +* **Trojan Protection** - Detecting access to Trojans horses. +* **Identification of Application Defects** - alerts on application misconfigurations. +* **Error Detection and Hiding** - Disguising error messages sent by the server. + +## ModSecurity Rules from Trustwave SpiderLabs + +Project Site: https://www.trustwave.com/modsecurity-rules-support.php + +Download: https://ssl.trustwave.com/web-application-firewall + +Trustwave now provides a commercial certified rule set for ModSecurity 2.x that protects against known attacks that target vulnerabilities in public software and are based on intelligence gathered from real-world investigations, honeypot data and research. + +1. More than 16,000 specific rules, broken out into the following attack categories: + + * SQL injection + * Cross-site Scripting (XSS) + * Local File Include + * Remote File Include + +2. User option for application specific rules, covering the same vulnerability classes for applications such as: + + * WordPress + * cPanel + * osCommerce + * Joomla + * For a complete listing of application coverage, please refer to this link (which is updated daily): https://modsecurity.org/application_coverage.html + +3. Complements and integrates with the OWASP Core Rule Set + +4. IP Reputation capabilities which provide protection against malicious clients identified by the Trustwave SpiderLabs Distributed Web Honeypots + +5. Malware Detection capabilities which prevent your web site from distributing malicious code to clients. diff --git a/README_WINDOWS.TXT b/README_WINDOWS.md similarity index 52% rename from README_WINDOWS.TXT rename to README_WINDOWS.md index 94c2bc9db9..30ee2e97f1 100644 --- a/README_WINDOWS.TXT +++ b/README_WINDOWS.md @@ -1,37 +1,32 @@ -===================================================================== -MOD_SECURITY 2.6 Command-line Build notes for Windows 4/2/2011 -by Tom Donovam -===================================================================== -PREREQUISITES: +## ModSecurity 2.x Command-line build notes for Windows - Microsoft Visual Studio C++ tested with Visual Studio 2008 (aka VC9) +by Tom Donovam, 4/2/2011 - CMake build system from: http://www.cmake.org/ tested with CMake v2.8.0 - Apache 2.2.x from: http://httpd.apache.org/ tested with Apache 2.2.17 - Apache must be built from source using the same Visual Studio compiler as mod_security. +## Prerequisites: - PCRE Perl Compatible Regular Expression library from: http://www.pcre.org/ tested with PCRE v8.12 +Dependency | Tested with | Note +----|------|---- +Microsoft Visual Studio C++ | Visual Studio 2008 (aka VC9) | +[CMake build system](http://www.cmake.org/) | CMake v2.8.0 | +[Apache 2.2.x](http://httpd.apache.org/) | Apache 2.2.17 | Apache must be built from source using the same Visual Studio compiler as mod_security. +[PCRE, Perl Compatible Regular Expression library](http://www.pcre.org/) | PCRE v8.12 +[LibXML2](http://xmlsoft.org/) | LibXML2 v2.7.7 | Note that LibXML2 v2.7.8 does not build correctly for Windows +[Lua Scripting Language](http://www.lua.org/) | Lua v5.1.4 +[cURL multiprotocol file transfer library](http://curl.haxx.se/) | cURL v7.21.4 - LibXML2 from: http://xmlsoft.org/ tested with LibXML2 v2.7.7 - Note that LibXML2 v2.7.8 does not build correctly for Windows - Lua Scripting Language from: http://www.lua.org/ tested with Lua v5.1.4 +## Before building - cURL multiprotocol file transfer library from: http://curl.haxx.se/ tested with cURL v7.21.4 - - -BEFORE BUILDING - -The directory where you build software from source ( C:\work in this exmaple) +The directory where you build software from source ( ``C:\work`` in this exmaple) must contain the Apache source you used to build the Apache web serverand the mod_security source Apache source is in C:\work\httpd-2.2.17 in this example. Apache has been installed to C:\Apache2217 in this example. Mod_security source is in C:\work\mod_security in this example. -Download and untar the prerequite library sources: +## Download and untar the prerequisite library sources: Download pcre-8.12.tar.gz from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ untar it into C:\work\ creating C:\work\pcre-8.12 @@ -45,40 +40,52 @@ Download and untar the prerequite library sources: Download curl-7.21.4.tar.gz from http://curl.haxx.se/download.html untar it into C:\work\ creating C:\work\curl-7.21.4 -Setup your build environment: +## Setup your build environment: + +1. The ``PATH`` environment variable must include the Visual Studio variables as set by ``vsvars32.bat`` + +2. The ``PATH`` environment variable must also include the CMAKE ``bin\`` directory - The PATH environment variable must include the Visual Studio variables as set by vsvars32.bat - The PATH environment variable must also include the CMAKE bin\ directory +3. Set an environment variable to the Apache source code directory: - Set an environment variable to the Apache source code directory: +``` + SET HTTPD_BUILD=C:\work\httpd-2.2.17 +``` - SET HTTPD_BUILD=C:\work\httpd-2.2.17 +### Optional: - If OpenSSL and Zlib support were included when you built Apache 2.2, and you want them available to LIBXML2 and CURL +If OpenSSL and zlib support were included when you built Apache 2.2, and you want them available to LibXML2 and cURL - Ensure that cURL and libXML2 can find the OpenSSL and Zlib includes and libraries that Apache was built with. +1. Ensure that cURL and LibXML2 can find the OpenSSL and zlib includes and libraries that Apache was built with. - SET INCLUDE=%INCLUDE%;%HTTPD_BUILD%\srclib\openssl\inc32;%HTTPD_BUILD%\srclib\zlib - SET LIB=%LIB%;%HTTPD_BUILD%\srclib\openssl\out32dll;%HTTPD_BUILD%\srclib\zlib +``` + SET INCLUDE=%INCLUDE%;%HTTPD_BUILD%\srclib\openssl\inc32;%HTTPD_BUILD%\srclib\zlib + SET LIB=%LIB%;%HTTPD_BUILD%\srclib\openssl\out32dll;%HTTPD_BUILD%\srclib\zlib +``` - Ensure that cURL and libXML2 don't use the static zlib library: zlib.lib. - Force cURL and libXML2 to use zdll.lib instead, requiring zlib1.dll at runtime: +2. Ensure that cURL and libXML2 don't use the static zlib library: ``zlib.lib``. Force cURL and libXML2 to use ``zdll.lib`` instead, requiring ``zlib1.dll`` at runtime: - IF EXIST %HTTPD_BUILD%\srclib\zlib\zlib.lib DEL %HTTPD_BUILD%\srclib\zlib\zlib.lib +``` + IF EXIST %HTTPD_BUILD%\srclib\zlib\zlib.lib DEL %HTTPD_BUILD%\srclib\zlib\zlib.lib +``` -BUILD PCRE-8.12 +## Build + +### PCRE-8.12 CD C:\work\pcre-8.12 CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True NMAKE -BUILD LIBXML2-2.7.7 (note: the more recent version: 2.7.8 does not build correctly on Windows) +### LibXML2-2.7.7 + +Note: the more recent version: 2.7.8 does not build correctly on Windows) CD C:\work\libxml2-2.7.7\win32 CSCRIPT configure.js iconv=no vcmanifest=yes zlib=yes NMAKE -f Makefile.msvc -BUILD LUA-5.1.4 +### Lua-5.1.4 CD C:\work\lua-5.1.4\src CL /Ox /arch:SSE2 /GF /GL /Gy /FD /EHsc /MD /Zi /TC /wd4005 /D "_MBCS" /D "LUA_CORE" /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_WIN32" /D "_WINDLL" /c *.c @@ -86,34 +93,34 @@ BUILD LUA-5.1.4 LINK /DLL /LTCG /DEBUG /OUT:lua5.1.dll *.obj IF EXIST lua5.1.dll.manifest MT -manifest lua5.1.dll.manifest -outputresource:lua5.1.dll;2 -BUILD CURL-7.21.4 +### cURL-7.21.4 CD C:\work\curl-7.21.4 CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True -DCURL_ZLIB=True NMAKE -BUILD MOD_SECURITY-2.6 +### ModSecurity-2.6 CD C:\work\mod_security\apache2 NMAKE -f Makefile.win APACHE=C:\Apache2217 PCRE=C:\work\pcre-8.12 LIBXML2=C:\work\libxml2-2.7.7 LUA=C:\work\lua-5.1.4\src -INSTALL MOD_SECURITY AND RUN APACHE +## Install ModSecurity and run Apache + +Copy these five files to ``C:\Apache2217\bin``: -Copy these five files to C:\Apache2217\bin: C:\work\pcre-8.12\pcre.dll C:\Apache2217\bin\ C:\work\lua-5.1.4\src\lua5.1.dll C:\Apache2217\bin\ C:\work\libxml2-2.7.7\win32\bin.msvc\libxml2.dll C:\Apache2217\bin\ C:\work\curl-7.21.4\libcurl.dll C:\Apache2217\bin\ C:\work\mod_security\apache2\mlogc-src\mlogc.exe -Copy this one file to C:\Apache2217\modules: +Copy this one file to ``C:\Apache2217\modules``: C:\work\mod_security\apache2\mod_security2.so -You may also copy C:\work\curl-7.21.4\curl.exe to C:\Apache2217\bin, if you want to use the cURL command-line program. +You may also copy ``C:\work\curl-7.21.4\curl.exe`` to ``C:\Apache2217\bin``, if you want to use the cURL command-line program. -Download the core rules from http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/ -and unzip them into C:\Apache2217\conf\modsecurity_crs +Download the core rules from http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/ and unzip them into ``C:\Apache2217\conf\modsecurity_crs`` Add configuration directives to your Apache conf\httpd.conf: @@ -134,11 +141,9 @@ Add configuration directives to your Apache conf\httpd.conf: SecAuditLog logs/modsecurity.log </IfModule> +## Optional: Build and configure the ModSecurity-2.x MLOGC piped-logging program -============================================================================================== -OPTIONAL: BUILD AND CONFIGURE THE MOD_SECURITY-2.6 MLOGC piped-logging program - -Edit the top of C:\work\mod_security\apache2\mlogc-src\Makefile.win and set your local paths +Edit the top of ``C:\work\mod_security\apache2\mlogc-src\Makefile.win`` and set your local paths # Path to Apache httpd installation BASE = C:\Apache2217 @@ -154,19 +159,19 @@ Edit the top of C:\work\mod_security\apache2\mlogc-src\Makefile.win and set your $(CURL)\libcurl_imp.lib \ wsock32.lib -Build the mlogc.exe program: +Build the ``mlogc.exe`` program: CD C:\work\mod_security_trunk\mlogc NMAKE -f Makefile.win -Copy mlocg.exe to C:\Apache2217\bin\ +Copy ``mlocg.exe`` to ``C:\Apache2217\bin\`` -Create a new command file C:\Apache2217\bin\mlogc.bat with one line: +Create a new command file ``C:\Apache2217\bin\mlogc.bat`` with one line: C:\Apache2217\bin\mlogc.exe C:\Apache2217\conf\mlogc.conf -Create a new configuration file C:\Apache2217\conf\mlogc.conf to control the piped-logging program mlogc.exe. -Here is an example conf\mlogc.conf: +Create a new configuration file ``C:\Apache2217\conf\mlogc.conf`` to control the piped-logging program ``mlogc.exe``. +Here is an example ``conf\mlogc.conf``: CollectorRoot "C:/Apache2217/logs" ConsoleURI "https://localhost:8888/rpc/auditLogReceiver" @@ -186,7 +191,6 @@ Here is an example conf\mlogc.conf: CheckpointInterval 15 ServerErrorTimeout 60 -Change the SecAuditLog directive in conf\httpd.conf to pipe the log data to mlogc -instead of writing them to a file: +Change the SecAuditLog directive in ``conf\httpd.conf`` to pipe the log data to mlogc instead of writing them to a file: SecAuditLog |C:/Apache2217/bin/mlogc.bat From e0a087b54036537f1145e86a602094d8a3d2933f Mon Sep 17 00:00:00 2001 From: Yang Luo <hsluoyz@qq.com> Date: Thu, 23 Aug 2018 09:56:16 +0800 Subject: [PATCH 196/477] Update the dependencies in README for Windows based on refactory of 2.9.2 release. --- README_WINDOWS.md | 94 +++++++++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/README_WINDOWS.md b/README_WINDOWS.md index 30ee2e97f1..dcb7e0db3a 100644 --- a/README_WINDOWS.md +++ b/README_WINDOWS.md @@ -8,13 +8,13 @@ by Tom Donovam, 4/2/2011 Dependency | Tested with | Note ----|------|---- -Microsoft Visual Studio C++ | Visual Studio 2008 (aka VC9) | -[CMake build system](http://www.cmake.org/) | CMake v2.8.0 | -[Apache 2.2.x](http://httpd.apache.org/) | Apache 2.2.17 | Apache must be built from source using the same Visual Studio compiler as mod_security. -[PCRE, Perl Compatible Regular Expression library](http://www.pcre.org/) | PCRE v8.12 -[LibXML2](http://xmlsoft.org/) | LibXML2 v2.7.7 | Note that LibXML2 v2.7.8 does not build correctly for Windows -[Lua Scripting Language](http://www.lua.org/) | Lua v5.1.4 -[cURL multiprotocol file transfer library](http://curl.haxx.se/) | cURL v7.21.4 +Microsoft Visual Studio C++ | Visual Studio 2013 (aka VC12) | +[CMake build system](http://www.cmake.org/) | CMake v3.8.2 | +[Apache 2.4.x](http://httpd.apache.org/) | Apache 2.4.27 | Apache must be built from source using the same Visual Studio compiler as mod_security. +[PCRE, Perl Compatible Regular Expression library](http://www.pcre.org/) | PCRE v8.40 +[LibXML2](http://xmlsoft.org/) | LibXML2 v2.9.4 | +[Lua Scripting Language](http://www.lua.org/) | Lua v5.3.4 +[cURL multiprotocol file transfer library](http://curl.haxx.se/) | cURL v7.54.0 ## Before building @@ -22,23 +22,23 @@ Microsoft Visual Studio C++ | Visual Studio 2008 (aka VC9) | The directory where you build software from source ( ``C:\work`` in this exmaple) must contain the Apache source you used to build the Apache web serverand the mod_security source - Apache source is in C:\work\httpd-2.2.17 in this example. - Apache has been installed to C:\Apache2217 in this example. + Apache source is in C:\work\httpd-2.4.27 in this example. + Apache has been installed to C:\Apache2427 in this example. Mod_security source is in C:\work\mod_security in this example. ## Download and untar the prerequisite library sources: - Download pcre-8.12.tar.gz from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ - untar it into C:\work\ creating C:\work\pcre-8.12 + Download pcre-8.40.tar.gz from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + untar it into C:\work\ creating C:\work\pcre-8.40 - Download libxml2-2.7.7.tar.gz from ftp://xmlsoft.org/libxml2/ - untar it into C:\work\ creating C:\work\libxml2-2.7.7 + Download libxml2-2.9.4.tar.gz from ftp://xmlsoft.org/libxml2/ + untar it into C:\work\ creating C:\work\libxml2-2.9.4 - Download lua-5.1.4.tar.gz from http://www.lua.org/ftp/ - untar it into C:\work\ creating C:\work\lua-5.1.4 + Download lua-5.3.4.tar.gz from http://www.lua.org/ftp/ + untar it into C:\work\ creating C:\work\lua-5.3.4 - Download curl-7.21.4.tar.gz from http://curl.haxx.se/download.html - untar it into C:\work\ creating C:\work\curl-7.21.4 + Download curl-7.54.0.tar.gz from http://curl.haxx.se/download.html + untar it into C:\work\ creating C:\work\curl-7.54.0 ## Setup your build environment: @@ -49,12 +49,12 @@ must contain the Apache source you used to build the Apache web serverand the mo 3. Set an environment variable to the Apache source code directory: ``` - SET HTTPD_BUILD=C:\work\httpd-2.2.17 + SET HTTPD_BUILD=C:\work\httpd-2.4.27 ``` ### Optional: -If OpenSSL and zlib support were included when you built Apache 2.2, and you want them available to LibXML2 and cURL +If OpenSSL and zlib support were included when you built Apache 2.4, and you want them available to LibXML2 and cURL 1. Ensure that cURL and LibXML2 can find the OpenSSL and zlib includes and libraries that Apache was built with. @@ -71,56 +71,54 @@ If OpenSSL and zlib support were included when you built Apache 2.2, and you wan ## Build -### PCRE-8.12 +### PCRE-8.40 - CD C:\work\pcre-8.12 + CD C:\work\pcre-8.40 CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True NMAKE -### LibXML2-2.7.7 +### LibXML2-2.9.4 -Note: the more recent version: 2.7.8 does not build correctly on Windows) - - CD C:\work\libxml2-2.7.7\win32 + CD C:\work\libxml2-2.9.4\win32 CSCRIPT configure.js iconv=no vcmanifest=yes zlib=yes NMAKE -f Makefile.msvc -### Lua-5.1.4 +### Lua-5.3.4 - CD C:\work\lua-5.1.4\src + CD C:\work\lua-5.3.4\src CL /Ox /arch:SSE2 /GF /GL /Gy /FD /EHsc /MD /Zi /TC /wd4005 /D "_MBCS" /D "LUA_CORE" /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_WIN32" /D "_WINDLL" /c *.c DEL lua.obj luac.obj LINK /DLL /LTCG /DEBUG /OUT:lua5.1.dll *.obj IF EXIST lua5.1.dll.manifest MT -manifest lua5.1.dll.manifest -outputresource:lua5.1.dll;2 -### cURL-7.21.4 +### cURL-7.54.0 - CD C:\work\curl-7.21.4 + CD C:\work\curl-7.54.0 CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True -DCURL_ZLIB=True NMAKE -### ModSecurity-2.6 +### ModSecurity-2.9.x CD C:\work\mod_security\apache2 - NMAKE -f Makefile.win APACHE=C:\Apache2217 PCRE=C:\work\pcre-8.12 LIBXML2=C:\work\libxml2-2.7.7 LUA=C:\work\lua-5.1.4\src + NMAKE -f Makefile.win APACHE=C:\Apache2427 PCRE=C:\work\pcre-8.40 LIBXML2=C:\work\libxml2-2.9.4 LUA=C:\work\lua-5.3.4\src ## Install ModSecurity and run Apache -Copy these five files to ``C:\Apache2217\bin``: +Copy these five files to ``C:\Apache2427\bin``: - C:\work\pcre-8.12\pcre.dll C:\Apache2217\bin\ - C:\work\lua-5.1.4\src\lua5.1.dll C:\Apache2217\bin\ - C:\work\libxml2-2.7.7\win32\bin.msvc\libxml2.dll C:\Apache2217\bin\ - C:\work\curl-7.21.4\libcurl.dll C:\Apache2217\bin\ + C:\work\pcre-8.40\pcre.dll C:\Apache2427\bin\ + C:\work\lua-5.3.4\src\lua5.1.dll C:\Apache2427\bin\ + C:\work\libxml2-2.9.4\win32\bin.msvc\libxml2.dll C:\Apache2427\bin\ + C:\work\curl-7.54.0\libcurl.dll C:\Apache2427\bin\ C:\work\mod_security\apache2\mlogc-src\mlogc.exe -Copy this one file to ``C:\Apache2217\modules``: +Copy this one file to ``C:\Apache2427\modules``: C:\work\mod_security\apache2\mod_security2.so -You may also copy ``C:\work\curl-7.21.4\curl.exe`` to ``C:\Apache2217\bin``, if you want to use the cURL command-line program. +You may also copy ``C:\work\curl-7.54.0\curl.exe`` to ``C:\Apache2427\bin``, if you want to use the cURL command-line program. -Download the core rules from http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/ and unzip them into ``C:\Apache2217\conf\modsecurity_crs`` +Download the core rules from http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/ and unzip them into ``C:\Apache2427\conf\modsecurity_crs`` Add configuration directives to your Apache conf\httpd.conf: @@ -146,11 +144,11 @@ Add configuration directives to your Apache conf\httpd.conf: Edit the top of ``C:\work\mod_security\apache2\mlogc-src\Makefile.win`` and set your local paths # Path to Apache httpd installation - BASE = C:\Apache2217 + BASE = C:\Apache2427 # Paths to required libraries - PCRE = C:\work\pcre-8.12 - CURL = C:\work\curl-7.21.4 + PCRE = C:\work\pcre-8.40 + CURL = C:\work\curl-7.54.0 # Linking libraries LIBS = $(BASE)\lib\libapr-1.lib \ @@ -164,16 +162,16 @@ Build the ``mlogc.exe`` program: CD C:\work\mod_security_trunk\mlogc NMAKE -f Makefile.win -Copy ``mlocg.exe`` to ``C:\Apache2217\bin\`` +Copy ``mlocg.exe`` to ``C:\Apache2427\bin\`` -Create a new command file ``C:\Apache2217\bin\mlogc.bat`` with one line: +Create a new command file ``C:\Apache2427\bin\mlogc.bat`` with one line: - C:\Apache2217\bin\mlogc.exe C:\Apache2217\conf\mlogc.conf + C:\Apache2427\bin\mlogc.exe C:\Apache2427\conf\mlogc.conf -Create a new configuration file ``C:\Apache2217\conf\mlogc.conf`` to control the piped-logging program ``mlogc.exe``. +Create a new configuration file ``C:\Apache2427\conf\mlogc.conf`` to control the piped-logging program ``mlogc.exe``. Here is an example ``conf\mlogc.conf``: - CollectorRoot "C:/Apache2217/logs" + CollectorRoot "C:/Apache2427/logs" ConsoleURI "https://localhost:8888/rpc/auditLogReceiver" SensorUsername "test" SensorPassword "testtest" @@ -193,4 +191,4 @@ Here is an example ``conf\mlogc.conf``: Change the SecAuditLog directive in ``conf\httpd.conf`` to pipe the log data to mlogc instead of writing them to a file: - SecAuditLog |C:/Apache2217/bin/mlogc.bat + SecAuditLog |C:/Apache2427/bin/mlogc.bat From b9bf98f2c164e109d66b789a5ee86232338662e2 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Thu, 20 Sep 2018 16:43:08 -0400 Subject: [PATCH 197/477] CHANGES: Adds info about: #1857 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index f417ec68ff..33f85fccaa 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Docs: Reformat README to Markdown and update dependencies + [Issue #1857 - @hsluoyz, @victorhora] * IIS: no lock on ProcessRequest. No reload of config. [Issue #1826 - @allanbomsft] * IIS: buffer request body before taking lock From a6774560786bda02fc86d721c722a6daad0592a7 Mon Sep 17 00:00:00 2001 From: Daniel Muey <simplemood.com@gmail.com> Date: Wed, 28 Feb 2018 12:34:32 -0600 Subject: [PATCH 198/477] Issue #1671: Only generate SecHashKey when SecHashEngine is On --- CHANGES | 2 ++ apache2/apache2_config.c | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 33f85fccaa..c5870fa05d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Only generate SecHashKey when SecHashEngine is On + [Issue #1671 - @dmuey, @monkburger, @zimmerle] * Docs: Reformat README to Markdown and update dependencies [Issue #1857 - @hsluoyz, @victorhora] * IIS: no lock on ProcessRequest. No reload of config. diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index ce97950f54..9a7b7b5ccf 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -732,8 +732,13 @@ void init_directory_config(directory_config *dcfg) if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600; /* Hash */ - if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp); - if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key); + if (dcfg->hash_is_enabled == HASH_ENABLED) { + if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp); + if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key); + } else { + if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = ""; + if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = 0; + } if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = HASH_KEYONLY; if (dcfg->crypto_param_name == NOT_SET_P) dcfg->crypto_param_name = "crypt"; if (dcfg->hash_is_enabled == NOT_SET) dcfg->hash_is_enabled = HASH_DISABLED; From aab128f810dcb8b557d3435fba703805a732b298 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sat, 22 Sep 2018 20:21:23 -0400 Subject: [PATCH 199/477] Code cosmetics: checks if actionset is not null before use it --- apache2/apache2_config.c | 14 +++++++++----- apache2/re.c | 6 +++--- apache2/re_operators.c | 12 +++++++++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 9a7b7b5ccf..80f8f2b507 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -239,9 +239,9 @@ static void copy_rules_phase(apr_pool_t *mp, /* Copy the rule. */ *(msre_rule **)apr_array_push(child_phase_arr) = rule; - if (rule->actionset->is_chained) mode = 2; + if (rule->actionset && rule->actionset->is_chained) mode = 2; } else { - if (rule->actionset->is_chained) mode = 1; + if (rule->actionset && rule->actionset->is_chained) mode = 1; } } else { if (mode == 2) { @@ -897,8 +897,10 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, rule->actionset, 1); /* Keep track of the parent action for "block" */ - rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; - rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; + if (rule->actionset) { + rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; + rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; + } /* Must NOT specify a disruptive action in logging phase. */ if ((rule->actionset != NULL) @@ -913,7 +915,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, if (dcfg->tmp_chain_starter != NULL) { rule->chain_starter = dcfg->tmp_chain_starter; - rule->actionset->phase = rule->chain_starter->actionset->phase; + if (rule->actionset) { + rule->actionset->phase = rule->chain_starter->actionset->phase; + } } if (rule->actionset->is_chained != 1) { diff --git a/apache2/re.c b/apache2/re.c index abc6e4d5a5..2428a17437 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1781,7 +1781,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } if (rc == RULE_NO_MATCH) { - if (rule->actionset->is_chained) { + if (rule->actionset && rule->actionset->is_chained) { /* If the current rule is part of a chain then * we need to skip over all the rules in the chain. */ @@ -2138,9 +2138,9 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, if (remove_rule) { /* Do not increment j. */ removed_count++; - if (rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ + if (rule->actionset && rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ } else { - if (rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ + if (rule->actionset && rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ rules[j++] = rules[i]; } } else { /* Handling rule that is part of a chain. */ diff --git a/apache2/re_operators.c b/apache2/re_operators.c index e0fc6fa857..e0ef2f201d 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -2851,7 +2851,9 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * * and we are done. */ - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (rule->actionset) { + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + } if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; @@ -3159,7 +3161,9 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (rule->actionset) { + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + } if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; @@ -3451,7 +3455,9 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (rule->actionset) { + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + } if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; From 96756533bae550df3db929b6bb281d713b8509b3 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sat, 22 Sep 2018 20:40:30 -0400 Subject: [PATCH 200/477] Code cosmetics: Minor change to match commit 2a42cc --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 2428a17437..64a2a6abe5 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1781,7 +1781,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } if (rc == RULE_NO_MATCH) { - if (rule->actionset && rule->actionset->is_chained) { + if (rule->actionset->is_chained) { /* If the current rule is part of a chain then * we need to skip over all the rules in the chain. */ @@ -1905,7 +1905,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re apr_table_clear(msr->matched_vars); return -1; } else { - if (rule->actionset->is_chained) { + if (rule->actionset && rule->actionset->is_chained) { /* If the current rule is part of a chain then * we need to skip over all the rules in the chain. */ From d50650ba4fd0c72e859a666a83facb7c296a227f Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sat, 22 Sep 2018 20:51:27 -0400 Subject: [PATCH 201/477] CHANGES: adds info on #1556 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c5870fa05d..e74e1119cc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Code cosmetics: checks if actionset is not null before use it + [Issue #1556 - @marcstern, @zimmerle, @victorhora] * Only generate SecHashKey when SecHashEngine is On [Issue #1671 - @dmuey, @monkburger, @zimmerle] * Docs: Reformat README to Markdown and update dependencies From a3dc60212883186fb71ea421c237664fecbda35f Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sat, 22 Sep 2018 18:33:12 -0400 Subject: [PATCH 202/477] ju5t patch to fix mpm-itk mod_ruid2 compatibility --- apache2/msc_logging.c | 12 +++++++++++- apache2/persist_dbm.c | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 6ee1e58333..a088fc1b2f 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -230,10 +230,20 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { char tstr[300]; apr_size_t len; + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + * It also changes the return statement. + */ + char *username; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, mp); + apr_uid_name_get(&username, uid, mp); + apr_time_exp_lt(&t, apr_time_now()); apr_strftime(tstr, &len, 299, "/%Y%m%d/%Y%m%d-%H%M/%Y%m%d-%H%M%S", &t); - return apr_psprintf(mp, "%s-%s", tstr, uniqueid); + return apr_psprintf(mp, "/%s%s-%s", username, tstr, uniqueid); } /** diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 597d5b8fc7..efbbf6ebd9 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -101,6 +101,14 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec int expired = 0; int i; + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *username; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + apr_uid_name_get(&username, uid, msr->mp); if (msr->txcfg->data_dir == NULL) { msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " @@ -109,7 +117,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec goto cleanup; } - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), @@ -374,6 +382,15 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { const apr_table_t *stored_col = NULL; const apr_table_t *orig_col = NULL; + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *username; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + apr_uid_name_get(&username, uid, msr->mp); + var_name = (msc_string *)apr_table_get(col, "__name"); if (var_name == NULL) { goto error; @@ -392,7 +409,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { } // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", var_name->value, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), @@ -655,6 +672,15 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { apr_time_t now = apr_time_sec(msr->request_time); int i; + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *username; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + apr_uid_name_get(&username, uid, msr->mp); + if (msr->txcfg->data_dir == NULL) { /* The user has been warned about this problem enough times already by now. * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " @@ -664,9 +690,9 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", msr->txcfg->webappid, "_", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", msr->txcfg->webappid, "_", col_name, NULL); else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), From 1a28de9cefed2668afeb8c01179e54227685735d Mon Sep 17 00:00:00 2001 From: Victor Hora <victorhora@users.noreply.github.com> Date: Fri, 12 Oct 2018 21:27:50 -0400 Subject: [PATCH 203/477] CHANGES: Adds info about: #712 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index e74e1119cc..4adac105af 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix mpm-itk / mod_ruid2 compatibility + [Issue #712 - @ju5t , @derhansen, @meatlayer, @victorhora] * Code cosmetics: checks if actionset is not null before use it [Issue #1556 - @marcstern, @zimmerle, @victorhora] * Only generate SecHashKey when SecHashEngine is On From f93709b66c58ce8fab703b49c26552abec9df574 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Wed, 17 Oct 2018 09:21:02 -0300 Subject: [PATCH 204/477] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 47 ++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..5346d6b738 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,47 @@ +--- +name: Bug report +about: Create a report to help us improve. If you don't know a specific detail or + piece of information leave it blank, if necessary we will help you to figure out. + +--- + +**Describe the bug** + +A clear and concise description of what the bug is. + +**Logs and dumps** + +Output of: + 1. DebugLogs (level 9) + 2. AuditLogs + 3. Error logs + 4. If there is a crash, the core dump file. + +_Notice:_ Be carefully to not leak any confidential information. + +**To Reproduce** + +Steps to reproduce the behavior: + +A **curl** command line that mimics the original request and reproduces the problem. Or a ModSecurity v3 test case. + +[e.g: curl "modsec-full/ca/..\\..\\..\\..\\..\\..\\/\\etc/\\passwd" or [issue-394.json](https://github.com/SpiderLabs/ModSecurity/blob/v3/master/test/test-cases/regression/issue-394.json)] + + +**Expected behavior** + +A clear and concise description of what you expected to happen. + +**Server (please complete the following information):** + - ModSecurity version (and connector): [e.g. ModSecurity v3.0.1 with nginx-connector v1.0.0] + - WebServer: [e.g. nginx-1.15.5] + - OS (and distro): [e.g. Linux, archlinux] + + +**Rule Set (please complete the following information):** + - Running any public or commercial rule set? [e.g. SpiderLabs commercial rules] + - What is the version number? [e.g. 2018-08-11] + +**Additional context** + +Add any other context about the problem here. From a55a9481b3eb29495814f80c12b654216be14674 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Wed, 26 Sep 2018 17:23:17 -0700 Subject: [PATCH 205/477] IIS: Remove body prebuffering again. Unneeded due to no lock on modsecProcessRequest. --- iis/mymodule.cpp | 105 ++++++++++------------------------------------- 1 file changed, 21 insertions(+), 84 deletions(-) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 32decf43da..e9d5ce3768 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -32,12 +32,6 @@ #include "winsock2.h" -// Used to hold each chunk of request body that gets read before the full ModSec engine is invoked -typedef struct preAllocBodyChunk { - preAllocBodyChunk* next; - size_t length; - void* data; -} preAllocBodyChunk; class REQUEST_STORED_CONTEXT : public IHttpStoredContext { @@ -89,8 +83,6 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *m_pResponseBuffer; ULONGLONG m_pResponseLength; ULONGLONG m_pResponsePosition; - - preAllocBodyChunk* requestBodyBufferHead; }; @@ -296,43 +288,6 @@ REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r) return NULL; } -HRESULT GetRequestBodyFromIIS(IHttpRequest* pRequest, preAllocBodyChunk** head) -{ - HRESULT hr = S_OK; - HTTP_REQUEST * pRawRequest = pRequest->GetRawHttpRequest(); - preAllocBodyChunk** cur = head; - while (pRequest->GetRemainingEntityBytes() > 0) - { - // Allocate memory for the preAllocBodyChunk linked list structure, and also the actual body content - // HUGE_STRING_LEN is hardcoded because this is also hardcoded in apache2_io.c's call to ap_get_brigade - preAllocBodyChunk* chunk = (preAllocBodyChunk*)malloc(sizeof(preAllocBodyChunk) + HUGE_STRING_LEN); - chunk->next = NULL; - - // Pointer to rest of allocated memory, for convenience - chunk->data = chunk + 1; - - DWORD readcnt = 0; - hr = pRequest->ReadEntityBody(chunk->data, HUGE_STRING_LEN, false, &readcnt, NULL); - if (ERROR_HANDLE_EOF == (hr & 0x0000FFFF)) - { - free(chunk); - hr = S_OK; - break; - } - chunk->length = readcnt; - - // Append to linked list - *cur = chunk; - cur = &(chunk->next); - - if (hr != S_OK) - { - break; - } - } - - return hr; -} HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf) { @@ -800,24 +755,6 @@ CMyHttpModule::OnBeginRequest( goto Finished; } - // Get request body without holding lock, because some clients may be slow at sending - LeaveCriticalSection(&m_csLock); - preAllocBodyChunk* requestBodyBufferHead = NULL; - hr = GetRequestBodyFromIIS(pRequest, &requestBodyBufferHead); - if (hr != S_OK) - { - goto FinishedWithoutLock; - } - EnterCriticalSection(&m_csLock); - - // Get the config again, in case it changed during the time we released the lock - hr = MODSECURITY_STORED_CONTEXT::GetConfig(pHttpContext, &pConfig); - if (FAILED(hr)) - { - hr = S_OK; - goto Finished; - } - if(pConfig->m_Config == NULL) { char *path; @@ -890,8 +827,6 @@ CMyHttpModule::OnBeginRequest( rsc->m_pRequestRec = r; rsc->m_pHttpContext = pHttpContext; rsc->m_pProvider = pProvider; - rsc->requestBodyBufferHead = requestBodyBufferHead; - requestBodyBufferHead = NULL; // This is to indicate to the cleanup process to use rsc->requestBodyBufferHead instead of requestBodyBufferHead now pHttpContext->GetModuleContextContainer()->SetModuleContext(rsc, g_pModuleContext); @@ -1139,16 +1074,6 @@ CMyHttpModule::OnBeginRequest( Finished: LeaveCriticalSection(&m_csLock); -FinishedWithoutLock: - // Free the preallocated body in case there was a failure and it wasn't consumed already - preAllocBodyChunk* chunkToFree = requestBodyBufferHead ? requestBodyBufferHead : rsc->requestBodyBufferHead; - while (chunkToFree != NULL) - { - preAllocBodyChunk* next = chunkToFree->next; - free(chunkToFree); - chunkToFree = next; - } - if ( FAILED( hr ) ) { return RQ_NOTIFICATION_FINISH_REQUEST; @@ -1156,27 +1081,39 @@ CMyHttpModule::OnBeginRequest( return RQ_NOTIFICATION_CONTINUE; } + apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos) { REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r); - if (rsc->requestBodyBufferHead == NULL) + *readcnt = 0; + + if (rsc == NULL) { *is_eos = 1; return APR_SUCCESS; } - *readcnt = length < (unsigned int) rsc->requestBodyBufferHead->length ? length : (unsigned int) rsc->requestBodyBufferHead->length; - void* src = (char*)rsc->requestBodyBufferHead->data; - memcpy_s(buf, length, src, *readcnt); + IHttpContext *pHttpContext = rsc->m_pHttpContext; + IHttpRequest *pRequest = pHttpContext->GetRequest(); - // Remove the front and proceed to next chunk in the linked list - preAllocBodyChunk* chunkToFree = rsc->requestBodyBufferHead; - rsc->requestBodyBufferHead = rsc->requestBodyBufferHead->next; - free(chunkToFree); + if (pRequest->GetRemainingEntityBytes() == 0) + { + *is_eos = 1; + return APR_SUCCESS; + } + + HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL); - if (rsc->requestBodyBufferHead == NULL) + if (FAILED(hr)) { + // End of data is okay. + if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF)) + { + // Set the error status. + rsc->m_pProvider->SetErrorStatus(hr); + } + *is_eos = 1; } From 49495f1925a14f74f93cb0ef01172e5abc3e4c55 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Fri, 19 Oct 2018 19:50:05 -0400 Subject: [PATCH 206/477] CHANGES: Adds info about: #1917 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 4adac105af..ef42151ffc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: Remove body prebuffering due to no locking in modsecProcessRequest + [Issue #1917 - @allanbomsft, @victorhora] * Fix mpm-itk / mod_ruid2 compatibility [Issue #712 - @ju5t , @derhansen, @meatlayer, @victorhora] * Code cosmetics: checks if actionset is not null before use it From 1843b79adbceec6152987efb157a45fe1f152b66 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Fri, 2 Nov 2018 19:01:36 -0400 Subject: [PATCH 207/477] IIS: Make failed MSI installer messages more helpful --- iis/installer.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/installer.wxs b/iis/installer.wxs index 271d9cba87..49090aba22 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -91,7 +91,7 @@ <RegistrySearch Id="FindInetPubFolder" Root="HKLM" Key="SOFTWARE\Microsoft\InetStp" Name="PathWWWRoot" Type="directory" /> </Property> <Property Id="MSIUSEREALADMINDETECTION" Value="1" /> - <Condition Message="This setup requires IIS 7.0 or 8.0."><![CDATA[(IIS="#7") OR (IIS="#8") OR (IIS="#10")]]></Condition> + <Condition Message="This setup requires IIS 7.0, 8.0 or 10.0. If that's the case, please ensure that the installer is running as administrator or try running it from the 'Apps and features' or 'Add/Remove Programs' menu"><![CDATA[(IIS="#7") OR (IIS="#8") OR (IIS="#10")]]></Condition> <!-- Version 2.7.5 had an uninstall issue that leaves some files behind. Asking the user to manually hash this out. --> <Condition Message="A older version of ModSecurityIIS was found in your computer. Please complete uninstall by removing the following file: [FILEEXISTS]. You may have to remove ModSecurity module from IIS, use the IIS Manager to do so."><![CDATA[(NOT FILEEXISTS) OR (Installed)]]></Condition> <Condition Message="64-bit operating system was detected, please use the 64-bit installer."> From e97799c9bc5dbf614e317ac3269ce8e7fd6c0176 Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Fri, 3 Nov 2017 16:04:00 -0700 Subject: [PATCH 208/477] Windows build, fixed duplicate YAJL dir in script --- iis/build_modsecurity.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iis/build_modsecurity.bat b/iis/build_modsecurity.bat index eeaeed2a29..4ee8348f56 100644 --- a/iis/build_modsecurity.bat +++ b/iis/build_modsecurity.bat @@ -15,21 +15,21 @@ set CURRENT_DIR=%cd% cd ..\apache2 del *.obj *.dll *.lib del libinjection\*.obj libinjection\*.dll libinjection\*.lib -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl IIS_BUILD=yes @if NOT (%ERRORLEVEL%) == (0) goto build_failed @echo mlogc... cd ..\mlogc del *.obj *.dll *.lib nmake -f Makefile.win clean -nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS +nmake -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre CURL=..\iis\%DEPENDENCIES_DIR%\curl YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep VERSION=VERSION_IIS @if NOT (%ERRORLEVEL%) == (0) goto build_failed @echo iis... cd ..\iis del *.obj *.dll *.lib nmake -f Makefile.win clean -NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\%YAJL_DIR%\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl +NMAKE -f Makefile.win APACHE=..\iis\%DEPENDENCIES_DIR%\Apache24 PCRE=..\iis\%DEPENDENCIES_DIR%\pcre LIBXML2=..\iis\%DEPENDENCIES_DIR%\libxml2 LUA=..\iis\%DEPENDENCIES_DIR%\lua\src VERSION=VERSION_IIS YAJL=..\iis\%DEPENDENCIES_DIR%\yajl\build\yajl-2.1.0 SSDEEP=..\iis\%DEPENDENCIES_DIR%\ssdeep CURL=..\iis\%DEPENDENCIES_DIR%\curl @if NOT (%ERRORLEVEL%) == (0) goto build_failed cd %CURRENT_DIR% From 96e21b0f3ee5dc9a4fd373fadf809380e4c6bdcd Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sun, 4 Nov 2018 13:06:37 -0500 Subject: [PATCH 209/477] CHANGES: Adds info about: #1612 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index ef42151ffc..f80e00c767 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: Windows build, fix duplicate YAJL dir in script + [Issue #1612 - @allanbomsft, @victorhora] * IIS: Remove body prebuffering due to no locking in modsecProcessRequest [Issue #1917 - @allanbomsft, @victorhora] * Fix mpm-itk / mod_ruid2 compatibility From b3fa87dc7cc8eec21adf8c26e7f0e373b0bb935d Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sun, 4 Nov 2018 21:20:10 -0500 Subject: [PATCH 210/477] Fix NetBSD build by renaming the hmac function to avoid conflicts --- CHANGES | 2 ++ apache2/msc_crypt.c | 72 +++++++++++++++++++++++++++++++++++++++++++-- apache2/msc_crypt.h | 5 ++++ 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index f80e00c767..020d17496d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix NetBSD build by renaming the hmac function to avoid conflicts + [Issue #1241 - @victorhora, @joerg, @sevan] * IIS: Windows build, fix duplicate YAJL dir in script [Issue #1612 - @allanbomsft, @victorhora] * IIS: Remove body prebuffering due to no locking in modsecProcessRequest diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index cf6a4a7705..dff2234a64 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -188,8 +188,13 @@ char *getkey(apr_pool_t *mp) { * * \retval hex_digest The MAC */ +#ifdef __NetBSD__ +char *mschmac(modsec_rec *msr, const char *key, int key_len, + unsigned char *msg, int msglen) { +#else char *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen) { +#endif apr_sha1_ctx_t ctx; unsigned char digest[APR_SHA1_DIGESTSIZE]; unsigned char hmac_ipad[HMAC_PAD_SIZE], hmac_opad[HMAC_PAD_SIZE]; @@ -1260,8 +1265,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) +#ifdef __NetBSD__ + hash_value = mschmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); - +#endif if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 @@ -1272,13 +1280,21 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } } @@ -1289,7 +1305,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } } else { return NULL; @@ -1303,8 +1323,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) +#ifdef __NetBSD__ + hash_value = mschmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); - +#endif if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 @@ -1315,13 +1338,21 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } } @@ -1332,7 +1363,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); +#endif } } else { return NULL; @@ -1344,8 +1379,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) +#ifdef __NetBSD__ + hash_value = mschmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#else hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); - +#endif if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 @@ -1356,13 +1394,21 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#endif } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#endif } } @@ -1373,7 +1419,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); +#endif } } @@ -1398,7 +1448,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) +#ifdef __NetBSD__ + hash_value = mschmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#else hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#endif if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { @@ -1410,13 +1464,21 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#endif } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#endif } } @@ -1427,7 +1489,11 @@ char *do_hash_link(modsec_rec *msr, char *link, int type) { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); +#ifdef __NetBSD__ + hash_value = mschmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#else hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); +#endif } link = relative_uri; diff --git a/apache2/msc_crypt.h b/apache2/msc_crypt.h index 3b3aa6da44..fb3d515112 100644 --- a/apache2/msc_crypt.h +++ b/apache2/msc_crypt.h @@ -27,8 +27,13 @@ #define INT32_MAX (2147483647) #endif +#ifdef __NetBSD__ +char DSOLOCAL *mschmac(modsec_rec *msr, const char *key, int key_len, + unsigned char *msg, int msglen); +#else char DSOLOCAL *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen); +#endif char DSOLOCAL *do_hash_link(modsec_rec *msr, char *link, int type); char DSOLOCAL *getkey(apr_pool_t *mp); From 9be0a407ebc8a7972b129a76109d54500e19bb41 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sun, 4 Nov 2018 22:04:34 -0500 Subject: [PATCH 211/477] Add sanity check for a couple malloc() and make code more resilient --- CHANGES | 2 ++ apache2/msc_remote_rules.c | 5 +++++ apache2/msc_util.c | 15 ++++++++++++--- apache2/msc_util.h | 4 ++-- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 020d17496d..89ab4e0a2f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Add sanity check for a couple malloc() and make code more resilient + [Issue #979 - @dogbert2, @victorhora, @zimmerl] * Fix NetBSD build by renaming the hmac function to avoid conflicts [Issue #1241 - @victorhora, @joerg, @sevan] * IIS: Windows build, fix duplicate YAJL dir in script diff --git a/apache2/msc_remote_rules.c b/apache2/msc_remote_rules.c index 8a6df9e0ab..99968f0405 100644 --- a/apache2/msc_remote_rules.c +++ b/apache2/msc_remote_rules.c @@ -312,6 +312,11 @@ int msc_remote_download_content(apr_pool_t *mp, const char *uri, const char *key struct curl_slist *headers_chunk = NULL; #ifdef WIN32 char *buf = malloc(sizeof(TCHAR) * (2048 + 1)); + if (buf == NULL) { /* malloc failed... */ + *error_msg = apr_psprintf(mp, "Unable to allocate memory"); + ret = -2; + goto failed; + } char *ptr = NULL; DWORD res_len; #endif diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 2cc6065fd6..9781d2d60d 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2779,8 +2779,8 @@ int ip_tree_from_param(apr_pool_t *mp, } #ifdef WITH_CURL -size_t msc_curl_write_memory_cb(void *contents, size_t size, - size_t nmemb, void *userp) +size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size, + size_t nmemb, void *userp, char **error_msg) { size_t realsize = size * nmemb; struct msc_curl_memory_buffer_t *mem = (struct msc_curl_memory_buffer_t *)userp; @@ -2788,11 +2788,20 @@ size_t msc_curl_write_memory_cb(void *contents, size_t size, if (mem->size == 0) { mem->memory = malloc(realsize + 1); + if (mem->memory == NULL) { + *error_msg = apr_psprintf(mp, "Unable to allocate buffer for mem->memory"); + return 0; + } memset(mem->memory, '\0', sizeof(realsize + 1)); } else { - mem->memory = realloc(mem->memory, mem->size + realsize + 1); + void *tmp; + tmp = mem->memory; + tmp = realloc(mem->memory, mem->size + realsize + 1); + if (tmp != NULL) { + mem->memory = tmp; + } memset(mem->memory + mem->size, '\0', sizeof(realsize + 1)); } diff --git a/apache2/msc_util.h b/apache2/msc_util.h index f7e1280f21..d69b62ac27 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -166,8 +166,8 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, int read_line(char *buff, int size, FILE *fp); -size_t msc_curl_write_memory_cb(void *contents, size_t size, - size_t nmemb, void *userp); +size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size, + size_t nmemb, void *userp, char **error_msg); struct msc_curl_memory_buffer_t { From 22322ce355a24e50de18b530b52b0bf9e57660cb Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Fri, 9 Nov 2018 17:57:31 -0500 Subject: [PATCH 212/477] Update modsecurity.conf file for IIS build --- iis/wix/modsecurity.conf | 23 +++++----- iis/wix/unicode.mapping | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 12 deletions(-) create mode 100644 iis/wix/unicode.mapping diff --git a/iis/wix/modsecurity.conf b/iis/wix/modsecurity.conf index 60f09129e1..5348686141 100644 --- a/iis/wix/modsecurity.conf +++ b/iis/wix/modsecurity.conf @@ -20,7 +20,7 @@ SecRequestBodyAccess On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type # -SecRule REQUEST_HEADERS:Content-Type "text/xml" \ +SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" # Enable JSON request body parser. @@ -40,7 +40,7 @@ SecRequestBodyLimit 13107200 SecRequestBodyNoFilesLimit 131072 # Store up to 128 KB of request body data in memory. When the multipart -# parser reachers this limit, it will start using your hard disk for +# parser reaches this limit, it will start using your hard disk for # storage. That is slow, but unavoidable. # SecRequestBodyInMemoryLimit 131072 @@ -110,7 +110,7 @@ SecRule TX:/^MSC_/ "!@streq 0" \ # Do keep in mind that enabling this directive does increases both # memory consumption and response latency. # -#SecResponseBodyAccess On +SecResponseBodyAccess On # Which response MIME types do you want to inspect? You should adjust the # configuration below to catch documents but avoid static files @@ -151,7 +151,7 @@ SecDataDir c:\inetpub\temp\ # location must be private to ModSecurity. You don't want other users on # the server to access the files, do you? # -#SecUploadDir /opt/modsecurity/var/upload/ +#SecUploadDir c:\inetpub\temp\ # By default, only keep the files that were determined to be unusual # in some way (by an external inspection script). For this to work you @@ -171,7 +171,7 @@ SecDataDir c:\inetpub\temp\ # The default debug log configuration is to duplicate the error, warning # and notice messages from the error log. # -#SecDebugLog /opt/modsecurity/var/log/debug.log +#SecDebugLog c:\inetpub\temp\debug.log #SecDebugLogLevel 3 @@ -181,17 +181,17 @@ SecDataDir c:\inetpub\temp\ # trigger a server error (determined by a 5xx or 4xx, excluding 404, # level response status codes). # -#SecAuditEngine RelevantOnly -#SecAuditLogRelevantStatus "^(?:5|4(?!04))" +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus "^(?:5|4(?!04))" # Log everything we know about a transaction. -#SecAuditLogParts ABIJDEFHZ +SecAuditLogParts ABIJDEFHZ # Use a single file for logging. This is much easier to look at, but # assumes that you will use the audit log only ocassionally. # -#SecAuditLogType Serial -#SecAuditLog c:\inetpub\log\modsec_audit.log +SecAuditLogType Serial +SecAuditLog c:\inetpub\log\modsec_audit.log # Specify the path for concurrent audit logging. #SecAuditLogStorageDir c:\inetpub\log\ @@ -216,8 +216,7 @@ SecCookieFormat 0 # to properly map encoded data to your language. Properly setting # these directives helps to reduce false positives and negatives. # -#SecUnicodeCodePage 20127 -#SecUnicodeMapFile unicode.mappinga +SecUnicodeMapFile unicode.mapping 20127 # Improve the quality of ModSecurity by sharing information about your # current ModSecurity version and dependencies versions. diff --git a/iis/wix/unicode.mapping b/iis/wix/unicode.mapping new file mode 100644 index 0000000000..2654c4a619 --- /dev/null +++ b/iis/wix/unicode.mapping @@ -0,0 +1,96 @@ +(MAC - Roman) + + +(MAC - Icelandic) + + +1250 (ANSI - Central Europe) +00a1:21 00a2:63 00a3:4c 00a5:59 00aa:61 00b2:32 00b3:33 00b9:31 00ba:6f 00bc:31 00bd:31 00be:33 00c0:41 00c3:41 00c5:41 00c6:41 00c8:45 00ca:45 00cc:49 00cf:49 00d1:4e 00d2:4f 00d5:4f 00d8:4f 00d9:55 00db:55 00e0:61 00e3:61 00e5:61 00e6:61 00e8:65 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f8:6f 00f9:75 00fb:75 00ff:79 0100:41 0101:61 0108:43 0109:63 010a:43 010b:63 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 013b:4c 013c:6c 0145:4e 0146:6e 014c:4f 014d:6f 014e:4f 014f:6f 0152:4f 0153:6f 0156:52 0157:72 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2032:27 2035:60 203c:21 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2191:5e 2194:2d 2195:7c 21a8:7c 2212:2d 2215:2f 2216:5c 2217:2a 221f:4c 2223:7c 2236:3a 223c:7e 2303:5e 2329:3c 232a:3e 2502:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263c:30 2640:2b 2642:3e 266a:64 266b:64 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1251 (ANSI - Cyrillic) +00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 203c:21 2190:3c 2191:5e 2192:3e 2193:76 2194:2d 221a:76 221f:4c 2500:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2552:2d 2558:4c 2559:4c 255a:4c 255b:2d 255c:2d 255d:2d 2564:54 2565:54 2566:54 256a:2b 256b:2b 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1252 (ANSI - Latin I) +0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c8:27 02cb:60 02cd:5f 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 0393:47 0398:54 03a3:53 03a6:46 03a9:4f 03b1:61 03b4:64 03b5:65 03c0:70 03c3:73 03c4:74 03c6:66 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2017:3d 2032:27 2035:60 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 207f:6e 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2212:2d 2215:2f 2216:5c 2217:2a 221a:76 221e:38 2223:7c 2229:6e 2236:3a 223c:7e 2261:3d 2264:3d 2265:3d 2303:5e 2320:28 2321:29 2329:3c 232a:3e 2500:2d 250c:2b 2510:2b 2514:2b 2518:2b 251c:2b 252c:2d 2534:2d 253c:2b 2550:2d 2552:2b 2553:2b 2554:2b 2555:2b 2556:2b 2557:2b 2558:2b 2559:2b 255a:2b 255b:2b 255c:2b 255d:2b 2564:2d 2565:2d 2566:2d 2567:2d 2568:2d 2569:2d 256a:2b 256b:2b 256c:2b 2584:5f 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1253 (ANSI - Greek) +00b4:2f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 037e:3b 203c:21 2190:3c 2191:5e 2192:3e 2193:76 2194:2d 221f:4c 2500:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1254 (ANSI - Turkish) +00dd:59 00fd:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c7:5e 02c8:27 02cb:60 02cd:5f 02d8:5e 02d9:27 0300:60 0302:5e 0331:5f 0332:5f 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2032:27 2035:60 203c:21 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2081:30 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2191:5e 2193:76 2194:2d 2195:7c 21a8:7c 2212:2d 2215:2f 2216:5c 2217:2a 221f:4c 2223:7c 2236:3a 223c:7e 2303:5e 2329:3c 232a:3e 2502:2d 250c:2d 2514:4c 2518:2d 251c:2b 2524:2b 252c:54 2534:2b 253c:2b 2550:3d 2554:2d 255a:4c 255d:2d 2566:54 256c:2b 2580:2d 2584:2d 2588:2d 2591:2d 2592:2d 2593:2d 25ac:2d 25b2:5e 25ba:3e 25c4:3c 25cb:30 25d9:30 263a:4f 263b:4f 263c:30 2640:2b 2642:3e 266a:64 266b:64 2758:7c 3000:20 3008:3c 3009:3e 301a:5b 301b:3d 301d:22 301e:22 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1255 (ANSI - Hebrew) +0191:46 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1256 (ANSI - Arabic) +0620:41 0621:41 0622:43 0623:45 0624:45 0625:45 0626:45 0627:49 0628:49 0629:4f 062a:55 062b:55 062c:55 062d:46 062e:43 062f:44 0630:45 0631:46 0632:47 0633:48 0634:49 0635:4a 0636:4b 0637:4c 0638:4d 0639:4e 063a:4f 0641:41 0642:42 0643:43 0644:44 0645:45 0646:46 0647:47 0648:48 0649:49 064a:4a 064b:4b 064c:4c 064d:4d 064e:4e 064f:4f 0650:50 0651:51 0652:52 + +1257 (ANSI - Baltic) +ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +1258 (ANSI/OEM - Viet Nam) +ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +20127 (US-ASCII) +00a0:20 00a1:21 00a2:63 00a4:24 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ad:2d 00ae:52 00b2:32 00b3:33 00b7:2e 00b8:2c 00b9:31 00ba:6f 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +20261 (T.61) +f8dd:5c f8de:5e f8df:60 f8e0:7b f8fc:7d f8fd:7e f8fe:7f + +20866 (Russian - KOI8) +00a7:15 00ab:3c 00ad:2d 00ae:52 00b1:2b 00b6:14 00bb:3e 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2026:3a 2030:25 2039:3c 203a:3e 203c:13 2122:54 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e + +28591 (ISO 8859-1 Latin I) +0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +28592 (ISO 8859-2 Central Europe) +00a1:21 00a2:63 00a5:59 00a6:7c 00a9:43 00aa:61 00ab:3c 00ae:52 00b2:32 00b3:33 00b7:2e 00b9:31 00ba:6f 00bb:3e 00c0:41 00c3:41 00c5:41 00c6:41 00c8:45 00ca:45 00cc:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d5:4f 00d8:4f 00d9:55 00db:55 00e0:61 00e3:61 00e5:61 00e6:61 00e8:65 00ea:65 00ec:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f8:6f 00f9:75 00fb:75 00ff:79 0100:41 0101:61 0108:43 0109:63 010a:43 010b:63 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 013b:4c 013c:6c 0145:4e 0146:6e 014c:4f 014d:6f 014e:4f 014f:6f 0152:4f 0153:6f 0156:52 0157:72 015c:53 015d:73 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +28605 (ISO 8859-15 Latin 9) +00a6:7c 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0138:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014a:4e 014b:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:54 0169:74 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0179:5a 017b:5a 017c:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:2e 2026:2e 2032:27 2035:60 2039:3c 203a:3e 2122:54 ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +37 (IBM EBCDIC - U.S./Canada) +0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:5a 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005f:6d 0060:79 007c:4f 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a2:4a 00a6:6a 00ac:5f 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:5a ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3f:6d ff40:79 ff5c:4f + +437 (OEM - United States) +00a4:0f 00a7:15 00a8:22 00a9:63 00ad:2d 00ae:72 00af:5f 00b3:33 00b4:27 00b6:14 00b8:2c 00b9:31 00be:5f 00c0:41 00c1:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d7:78 00d8:4f 00d9:55 00da:55 00db:55 00dd:59 00de:5f 00e3:61 00f0:64 00f5:6f 00f8:6f 00fd:79 00fe:5f 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02ca:27 02cb:60 02cd:5f 02dc:7e 0300:60 0301:27 0302:5e 0303:7e 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:60 2019:27 201a:2c 201c:22 201d:22 201e:2c 2020:2b 2022:07 2026:2e 2030:25 2032:27 2035:60 2039:3c 203a:3e 203c:13 2044:2f 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2082:32 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:09 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2212:2d 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2758:7c 3000:20 3007:09 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +500 (IBM EBCDIC - International) +0004:37 0005:2d 0006:2e 0007:2f 0008:16 0009:05 000a:25 0014:3c 0015:3d 0016:32 0017:26 001a:3f 001b:27 0020:40 0021:4f 0022:7f 0023:7b 0024:5b 0025:6c 0026:50 0027:7d 0028:4d 0029:5d 002a:5c 002b:4e 002c:6b 002d:60 002e:4b 002f:61 003a:7a 003b:5e 003c:4c 003d:7e 003e:6e 003f:6f 0040:7c 005b:4a 005d:5a 005e:5f 005f:6d 0060:79 007f:07 0080:20 0081:21 0082:22 0083:23 0084:24 0085:15 0086:06 0087:17 0088:28 0089:29 008a:2a 008b:2b 008c:2c 008d:09 008e:0a 008f:1b 0090:30 0091:31 0092:1a 0093:33 0094:34 0095:35 0096:36 0097:08 0098:38 0099:39 009a:3a 009b:3b 009c:04 009d:14 009e:3e 00a0:41 00a6:6a 00c0:64 00c1:65 00c2:62 00c3:66 00c4:63 00c5:67 00c7:68 00c8:74 00c9:71 00ca:72 00cb:73 00cc:78 00cd:75 00ce:76 00cf:77 00d1:69 00df:59 00e0:44 00e1:45 00e2:42 00e3:46 00e4:43 00e5:47 00e7:48 00e8:54 00e9:51 00ea:52 00eb:53 00ec:58 00ed:55 00ee:56 00ef:57 00f1:49 00f8:70 ff01:4f ff02:7f ff03:7b ff04:5b ff05:6c ff06:50 ff07:7d ff08:4d ff09:5d ff0a:5c ff0b:4e ff0c:6b ff0d:60 ff0e:4b ff0f:61 ff1a:7a ff1b:5e ff1c:4c ff1d:7e ff1e:6e ff20:7c ff3b:4a ff3d:5a ff3e:5f ff3f:6d ff40:79 + +850 (OEM - Multilingual Latin I) +0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01a9:53 01ab:74 01ae:54 01af:55 01b0:75 01b6:5a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02cb:27 02cd:5f 02dc:7e 0300:27 0302:5e 0303:7e 030e:22 0331:5f 0332:5f 037e:3b 0393:47 03a3:53 03a6:46 03a9:4f 03b1:61 03b4:64 03b5:65 03c0:70 03c3:73 03c4:74 03c6:66 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:2e 2030:25 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:39 207f:6e 2080:30 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:50 2119:50 211a:51 211b:52 211c:52 211d:52 2122:54 2124:5a 2126:4f 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2211:53 2212:2d 2215:2f 2216:2f 2217:2a 2219:07 221a:56 221e:38 221f:1c 2229:6e 2236:3a 223c:7e 2248:7e 2261:3d 2264:3d 2265:3d 2302:7f 2303:5e 2320:28 2321:29 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 2713:56 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +860 (OEM - Portuguese) +00a4:0f 00a5:59 00a7:15 00a8:22 00a9:63 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00be:33 00c4:41 00c5:41 00c6:41 00cb:45 00ce:49 00cf:49 00d0:44 00d6:4f 00d7:58 00d8:4f 00db:55 00dd:59 00de:54 00e4:61 00e5:61 00e6:61 00eb:65 00ee:69 00ef:69 00f0:64 00f6:6f 00f8:6f 00fb:75 00fd:79 00fe:74 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:5c 0161:7c 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0191:46 0192:66 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c0:7c 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 0278:66 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:5f 2011:5f 2013:5f 2014:5f 2017:5f 2018:27 2019:27 201a:2c 201c:22 201d:22 201e:22 2022:07 2024:07 2026:2e 2030:25 2032:27 2035:60 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 + +861 (OEM - Icelandic) +00a2:63 00a4:0f 00a5:59 00a7:15 00a8:22 00a9:63 00aa:61 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00ba:6f 00be:33 00c0:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d4:4f 00d5:4f 00d7:58 00d9:55 00db:55 00e3:61 00ec:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f5:6f 00f9:75 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 0278:66 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 + +863 (OEM - Canadian French) +00a1:21 00a5:59 00a9:63 00aa:61 00ad:16 00ae:72 00b9:33 00ba:6f 00c1:41 00c3:41 00c4:41 00c5:41 00c6:41 00cc:49 00cd:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d5:4f 00d6:4f 00d7:58 00d8:4f 00da:55 00dd:59 00de:54 00e1:61 00e3:61 00e4:61 00e5:61 00e6:61 00ec:69 00ed:69 00f0:64 00f1:6e 00f2:6f 00f5:6f 00f6:6f 00f8:6f 00fd:79 00fe:74 00ff:79 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:22 02ba:27 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02cb:60 02cd:5f 02dc:7e 0300:60 0302:5e 0303:7e 0304:16 0305:16 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20a7:50 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212b:41 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 301a:5b 301b:5d 30fb:07 + +865 (OEM - Nordic) +00a2:63 00a5:59 00a7:15 00a8:22 00a9:63 00ad:5f 00ae:72 00af:16 00b3:33 00b4:2f 00b6:14 00b8:2c 00b9:31 00bb:3e 00be:33 00c0:41 00c1:41 00c2:41 00c3:41 00c8:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d7:58 00d9:55 00da:55 00db:55 00dd:59 00de:54 00e3:61 00f0:64 00f5:6f 00fd:79 00fe:74 0100:41 0101:61 0102:41 0103:61 0104:41 0105:61 0106:43 0107:63 0108:43 0109:63 010a:43 010b:63 010c:43 010d:63 010e:44 010f:64 0110:44 0111:64 0112:45 0113:65 0114:45 0115:65 0116:45 0117:65 0118:45 0119:65 011a:45 011b:65 011c:47 011d:67 011e:47 011f:67 0120:47 0121:67 0122:47 0123:67 0124:48 0125:68 0126:48 0127:68 0128:49 0129:69 012a:49 012b:69 012c:49 012d:69 012e:49 012f:69 0130:49 0131:69 0134:4a 0135:6a 0136:4b 0137:6b 0139:4c 013a:6c 013b:4c 013c:6c 013d:4c 013e:6c 0141:4c 0142:6c 0143:4e 0144:6e 0145:4e 0146:6e 0147:4e 0148:6e 014c:4f 014d:6f 014e:4f 014f:6f 0150:4f 0151:6f 0152:4f 0153:6f 0154:52 0155:72 0156:52 0157:72 0158:52 0159:72 015a:53 015b:73 015c:53 015d:73 015e:53 015f:73 0160:53 0161:73 0162:54 0163:74 0164:54 0165:74 0166:54 0167:74 0168:55 0169:75 016a:55 016b:75 016c:55 016d:75 016e:55 016f:75 0170:55 0171:75 0172:55 0173:75 0174:57 0175:77 0176:59 0177:79 0178:59 0179:5a 017b:5a 017c:7a 017d:5a 017e:7a 0180:62 0189:44 0197:49 019a:6c 019f:4f 01a0:4f 01a1:6f 01ab:74 01ae:54 01af:55 01b0:75 01b6:7a 01c3:21 01cd:41 01ce:61 01cf:49 01d0:69 01d1:4f 01d2:6f 01d3:55 01d4:75 01d5:55 01d6:75 01d7:55 01d8:75 01d9:55 01da:75 01db:55 01dc:75 01de:41 01df:61 01e4:47 01e5:67 01e6:47 01e7:67 01e8:4b 01e9:6b 01ea:4f 01eb:6f 01ec:4f 01ed:6f 01f0:6a 0261:67 02b9:27 02ba:22 02bc:27 02c4:5e 02c6:5e 02c8:27 02c9:16 02ca:2f 02cb:60 02cd:5f 02dc:7e 0300:60 0301:2f 0302:5e 0303:7e 0304:16 0305:16 0308:22 030e:22 0327:2c 0331:5f 0332:5f 037e:3b 04bb:68 0589:3a 066a:25 2000:20 2001:20 2002:20 2003:20 2004:20 2005:20 2006:20 2010:2d 2011:2d 2013:2d 2014:2d 2017:5f 2018:27 2019:27 201a:27 201c:22 201d:22 201e:22 2022:07 2024:07 2026:07 2030:25 2032:27 2035:27 2039:3c 203a:3e 203c:13 2044:2f 2070:30 2074:34 2075:35 2076:36 2077:37 2078:38 2080:30 2081:31 2083:33 2084:34 2085:35 2086:36 2087:37 2088:38 2089:39 20dd:4f 2102:43 2107:45 210a:67 210b:48 210c:48 210d:48 210e:68 2110:49 2111:49 2112:4c 2113:6c 2115:4e 2118:70 2119:50 211a:51 211b:52 211c:52 211d:52 2122:74 2124:5a 2128:5a 212a:4b 212c:42 212d:43 212e:65 212f:65 2130:45 2131:46 2133:4d 2134:6f 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 2205:4f 2212:5f 2215:2f 2216:5c 2217:2a 221f:1c 2223:7c 2236:3a 223c:7e 226b:3c 22c5:07 2302:7f 2303:5e 2329:3c 232a:3e 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e 3000:20 3007:4f 3008:3c 3009:3e 300b:3e 301a:5b 301b:5d 30fb:07 + +874 (ANSI/OEM - Thai) +00a7:15 00b6:14 203c:13 2190:1b 2191:18 2192:1a 2193:19 2194:1d 2195:12 21a8:17 221f:1c 2302:7f 25ac:16 25b2:1e 25ba:10 25bc:1f 25c4:11 25cb:09 25d8:08 25d9:0a 263a:01 263b:02 263c:0f 2640:0c 2642:0b 2660:06 2663:05 2665:03 2666:04 266a:0d 266b:0e ff01:21 ff02:22 ff03:23 ff04:24 ff05:25 ff06:26 ff07:27 ff08:28 ff09:29 ff0a:2a ff0b:2b ff0c:2c ff0d:2d ff0e:2e ff0f:2f ff10:30 ff11:31 ff12:32 ff13:33 ff14:34 ff15:35 ff16:36 ff17:37 ff18:38 ff19:39 ff1a:3a ff1b:3b ff1c:3c ff1d:3d ff1e:3e ff20:40 ff21:41 ff22:42 ff23:43 ff24:44 ff25:45 ff26:46 ff27:47 ff28:48 ff29:49 ff2a:4a ff2b:4b ff2c:4c ff2d:4d ff2e:4e ff2f:4f ff30:50 ff31:51 ff32:52 ff33:53 ff34:54 ff35:55 ff36:56 ff37:57 ff38:58 ff39:59 ff3a:5a ff3b:5b ff3c:5c ff3d:5d ff3e:5e ff3f:5f ff40:60 ff41:61 ff42:62 ff43:63 ff44:64 ff45:65 ff46:66 ff47:67 ff48:68 ff49:69 ff4a:6a ff4b:6b ff4c:6c ff4d:6d ff4e:6e ff4f:6f ff50:70 ff51:71 ff52:72 ff53:73 ff54:74 ff55:75 ff56:76 ff57:77 ff58:78 ff59:79 ff5a:7a ff5b:7b ff5c:7c ff5d:7d ff5e:7e + +932 (ANSI/OEM - Japanese Shift-JIS) +00a1:21 00a5:5c 00a6:7c 00a9:63 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:64 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00fe:74 00ff:79 + +936 (ANSI/OEM - Simplified Chinese GBK) +00a6:7c 00aa:61 00ad:2d 00b2:32 00b3:33 00b9:31 00ba:6f 00d0:44 00dd:59 00de:54 00e2:61 00f0:65 00fd:79 00fe:74 + +949 (ANSI/OEM - Korean) +00a6:7c 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00ff:79 20a9:5c + +950 (ANSI/OEM - Traditional Chinese Big5) +00a1:21 00a6:7c 00a9:63 00aa:61 00ad:2d 00ae:52 00b2:32 00b3:33 00b9:31 00ba:6f 00c0:41 00c1:41 00c2:41 00c3:41 00c4:41 00c5:41 00c6:41 00c7:43 00c8:45 00c9:45 00ca:45 00cb:45 00cc:49 00cd:49 00ce:49 00cf:49 00d0:44 00d1:4e 00d2:4f 00d3:4f 00d4:4f 00d5:4f 00d6:4f 00d8:4f 00d9:55 00da:55 00db:55 00dc:55 00dd:59 00de:54 00df:73 00e0:61 00e1:61 00e2:61 00e3:61 00e4:61 00e5:61 00e6:61 00e7:63 00e8:65 00e9:65 00ea:65 00eb:65 00ec:69 00ed:69 00ee:69 00ef:69 00f0:65 00f1:6e 00f2:6f 00f3:6f 00f4:6f 00f5:6f 00f6:6f 00f8:6f 00f9:75 00fa:75 00fb:75 00fc:75 00fd:79 00fe:74 00ff:79 + +(UTF-7) + + +(UTF-8) + + From 45337265f1df8f45908390caf896158d241aae72 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Fri, 9 Nov 2018 18:06:56 -0500 Subject: [PATCH 213/477] Set SecStreamInBodyInspection by default on IIS builds (#1299) --- iis/wix/modsecurity.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iis/wix/modsecurity.conf b/iis/wix/modsecurity.conf index 5348686141..42e6b55399 100644 --- a/iis/wix/modsecurity.conf +++ b/iis/wix/modsecurity.conf @@ -16,6 +16,9 @@ SecRuleEngine DetectionOnly # SecRequestBodyAccess On +# SecStreamInBodyInspection is required by IIS for proper body inspection +# See issue #1299 for more information +SecStreamInBodyInspection On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type From b7e82aae0e4e85e0dd6dac9595b8157cb1a3fdd0 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Fri, 9 Nov 2018 18:10:59 -0500 Subject: [PATCH 214/477] CHANGES: Adds info about: #788 and #1299 --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 89ab4e0a2f..ebadec0f75 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: Set SecStreamInBodyInspection by default on IIS builds (#1299) + [Issue #1299 - @victorhora] + * IIS: Update modsecurity.conf + [Issue #788 - @victorhora, @brianclark] * Add sanity check for a couple malloc() and make code more resilient [Issue #979 - @dogbert2, @victorhora, @zimmerl] * Fix NetBSD build by renaming the hmac function to avoid conflicts From 63cbd91723fc663f68090b08158ad204883d3a29 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Sun, 11 Nov 2018 15:33:29 -0500 Subject: [PATCH 215/477] IIS: Update dependencies for Windows build --- CHANGES | 2 ++ iis/build_dependencies.bat | 16 ++++++++-------- iis/build_msi.bat | 2 +- iis/dependencies/build_pcre.bat | 12 +++++++----- iis/download_files.bat | 32 +++++++++++++++----------------- 5 files changed, 33 insertions(+), 31 deletions(-) diff --git a/CHANGES b/CHANGES index ebadec0f75..df79fcd30e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: Update dependencies for Windows build + [Issue #1848 - @victorhora, @hsluoyz] * IIS: Set SecStreamInBodyInspection by default on IIS builds (#1299) [Issue #1299 - @victorhora] * IIS: Update modsecurity.conf diff --git a/iis/build_dependencies.bat b/iis/build_dependencies.bat index 1ae2a607a1..61cffb6352 100644 --- a/iis/build_dependencies.bat +++ b/iis/build_dependencies.bat @@ -7,15 +7,15 @@ @set SOURCE_DIR=%USERPROFILE%\Downloads :: Dependencies -@set CMAKE=cmake-3.8.2-win32-x86.zip -@set PCRE=pcre-8.40.zip +@set CMAKE=cmake-3.12.4-win32-x86.zip +@set PCRE=pcre-8.41.zip @set ZLIB=zlib-1.2.11.tar.gz -@set LIBXML2=libxml2-2.9.4.tar.gz -@set LUA=lua-5.3.4.tar.gz -@set CURL=curl-7.54.1.zip -@set APACHE_SRC=httpd-2.4.27.tar.gz -@set APACHE_BIN32=httpd-2.4.27-win32-VC11.zip -@set APACHE_BIN64=httpd-2.4.27-win64-VC11.zip +@set LIBXML2=libxml2-2.9.8.tar.gz +@set LUA=lua-5.3.5.tar.gz +@set CURL=curl-7.62.0.zip +@set APACHE_SRC=httpd-2.4.37.tar.gz +@set APACHE_BIN32=httpd-2.4.37-win32-VC11.zip +@set APACHE_BIN64=httpd-2.4.37-win64-VC11.zip @set YAJL=yajl-2.1.0.zip @set SSDEEP=ssdeep-2.13.tar.gz @set SSDEEP_BIN=ssdeep-2.13.zip diff --git a/iis/build_msi.bat b/iis/build_msi.bat index 0ea7d369fe..fde4022cd9 100644 --- a/iis/build_msi.bat +++ b/iis/build_msi.bat @@ -1,6 +1,6 @@ -set PATH="%PATH%;C:\Program Files (x86)\WiX Toolset v3.8\bin;C:\Program Files (x86)\WiX Toolset v3.7\bin;" +set PATH="%PATH%;C:\Program Files (x86)\WiX Toolset v3.11\bin;C:\Program Files (x86)\WiX Toolset v3.8\bin;C:\Program Files (x86)\WiX Toolset v3.7\bin;" set CURRENT_DIR=%cd% del installer.wix* diff --git a/iis/dependencies/build_pcre.bat b/iis/dependencies/build_pcre.bat index b7841b2549..d2cbcce0f9 100644 --- a/iis/dependencies/build_pcre.bat +++ b/iis/dependencies/build_pcre.bat @@ -10,14 +10,16 @@ set PCRE_DIR=%PCRE:~0,-4% move "%PCRE_DIR%" "pcre" @if "%PCRE_DIR%" == "pcre-8.40" ( - Echo. && Echo "PCRE 8.40 found... patching with patch-pcre-8.40.vbs..." - cscript /B /Nologo ../patch-pcre-8.40.vbs + Echo. && Echo "PCRE 8.40 found... trying to patch it to compile cleanly" + ::cscript /B /Nologo ../patch-pcre-8.40.vbs + cd "pcre" + cat CMakeLists.txt | sed "s/PCRE_STATIC_RUNTIME OFF CACHE BOOL/PCRE_STATIC_RUNTIME/g" > CMakeLists.txt.ops + move CMakeLists.txt CMakeLists.txt.old + move CMakeLists.txt.ops CMakeLists.txt + cd .. ) cd "pcre" -cat CMakeLists.txt | sed "s/PCRE_STATIC_RUNTIME OFF CACHE BOOL/PCRE_STATIC_RUNTIME/g" > CMakeLists.txt.ops -move CMakeLists.txt CMakeLists.txt.old -move CMakeLists.txt.ops CMakeLists.txt CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True @if NOT (%ERRORLEVEL%) == (0) goto build_failed NMAKE diff --git a/iis/download_files.bat b/iis/download_files.bat index f0db400e13..dd0773aad2 100644 --- a/iis/download_files.bat +++ b/iis/download_files.bat @@ -1,34 +1,32 @@ - -::@set CMAKE=cmake-3.8.2-win32-x86.zip -::@set PCRE=pcre-8.40.zip -::@set ZLIB=zlib-1.2.11.tar.gz -::@set LIBXML2=libxml2-2.9.4.tar.gz -::@set LUA=lua-5.3.4.tar.gz -::@set CURL=curl-7.54.1.zip -::@set APACHE_SRC=httpd-2.4.27.tar.gz -::@set APACHE_BIN32=httpd-2.4.27-win32-VC11.zip -::@set APACHE_BIN64=httpd-2.4.27-win64-VC11.zip -::@set YAJL=yajl-2.1.0.zip -::@set SSDEEP=ssdeep-2.13.tar.gz -::@set SSDEEP_BIN=ssdeep-2.13.zip +@set CMAKE=cmake-3.12.4-win32-x86.zip +@set PCRE=pcre-8.41.zip +@set ZLIB=zlib-1.2.11.tar.gz +@set LIBXML2=libxml2-2.9.8.tar.gz +@set LUA=lua-5.3.5.tar.gz +@set CURL=curl-7.62.0.zip +@set APACHE_SRC=httpd-2.4.37.tar.gz +@set APACHE_BIN32=httpd-2.4.37-win32-VC11.zip +@set APACHE_BIN64=httpd-2.4.37-win64-VC11.zip +@set YAJL=yajl-2.1.0.zip +@set SSDEEP=ssdeep-2.13.tar.gz +@set SSDEEP_BIN=ssdeep-2.13.zip :: BITSAdmin refuses to download YAJL from GitHub URL :: @set YAJL_URL=https://github.com/lloyd/yajl/archive/%YAJL:~-9% @set YAJL_URL=http://http.debian.net/debian/pool/main/y/yajl/yajl_2.1.0.orig.tar.gz -@set CMAKE_URL=https://cmake.org/files/v3.8/%CMAKE% +@set CMAKE_URL=https://cmake.org/files/v3.12/%CMAKE% @set PCRE_URL=https://ftp.pcre.org/pub/pcre/%PCRE% @set ZLIB_URL=https://zlib.net/%ZLIB% @set LIBXML2_URL=http://xmlsoft.org/sources/%LIBXML2% -@set LUA_URL=https://www.lua.org/ftp/%LUA% +@set LUA_URL=https://www.lua.org/ftp/%LUA% @set CURL_URL=http://curl.askapache.com/download/%CURL% @set APACHE_SRC_URL=https://www.apache.org/dist/httpd/%APACHE_SRC% -@set APACHE_BIN_URL=https://www.apachelounge.com/download/VC11/binaries +@set APACHE_BIN_URL=https://home.apache.org/~steffenal/VC11/binaries @set SSDEEP_URL=https://downloads.sourceforge.net/project/ssdeep/ssdeep-2.13 bitsadmin.exe /transfer "Downloading dependencies..." %CMAKE_URL% %SOURCE_DIR%\%CMAKE% %PCRE_URL% %SOURCE_DIR%\%PCRE% %ZLIB_URL% %SOURCE_DIR%\%ZLIB% %LIBXML2_URL% %SOURCE_DIR%\%LIBXML2% %LUA_URL% %SOURCE_DIR%\%LUA% %CURL_URL% %SOURCE_DIR%\%CURL% %APACHE_SRC_URL% %SOURCE_DIR%\%APACHE_SRC% %APACHE_BIN_URL%/%APACHE_BIN32% %SOURCE_DIR%\%APACHE_BIN32% %APACHE_BIN_URL%/%APACHE_BIN64% %SOURCE_DIR%\%APACHE_BIN64% %YAJL_URL% %SOURCE_DIR%\%YAJL% %SSDEEP_URL%/%SSDEEP% %SOURCE_DIR%\%SSDEEP% %SSDEEP_URL%/%SSDEEP_BIN% %SOURCE_DIR%\%SSDEEP_BIN% - @if NOT (%ERRORLEVEL%) == (0) goto :failed_to_download @exit /B 0 From f35075b2a791754ccfc71e4b0d9e8a6e5e44f1c2 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Mon, 12 Nov 2018 15:45:47 -0500 Subject: [PATCH 216/477] IIS: Update Wix installer to bundle a supported CRS version (3.0) --- iis/installer.wxs | 250 ++++++++++++++++------------------- iis/wix/modsecurity_iis.conf | 4 +- 2 files changed, 118 insertions(+), 136 deletions(-) diff --git a/iis/installer.wxs b/iis/installer.wxs index 49090aba22..4f6a1fffbf 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -132,121 +132,89 @@ <?endif ?> <Directory Id="$(var.PlatformProgramFilesFolder)"> <Directory Id="INSTALLFOLDER" Name="ModSecurity IIS"> - <Component Id="OWASP_CRS_V_2_2_9_SETUP" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6500"> - <File Id="MODSECURITY_CRS_10_SETUP.CONF.EXAMPLE" Name="modsecurity_crs_10_setup.conf" Source="release\owasp_crs\modsecurity_crs_10_setup.conf.example" /> + <Component Id="OWASP_CRS_V_3_0_2_SETUP" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6500"> + <File Id="CRS_SETUP.CONF.EXAMPLE" Name="crs-setup.conf.example" Source="release\owasp_crs\crs-setup.conf.example" /> </Component> <Directory Id="OWASP_CRS" Name="owasp_crs"> - <Component Id="OWASP_CRS_V_2_2_9" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6502"> + <Component Id="OWASP_CRS_V_3_0_2" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6502"> <File Id="CHANGES" Name="CHANGES" Source="release\owasp_crs\CHANGES" /> + <File Id="CONTRIBUTORS" Name="CONTRIBUTORS" Source="release\owasp_crs\CONTRIBUTORS" /> + <File Id="IDNUMBERING" Name="IDNUMBERING" Source="release\owasp_crs\IDNUMBERING" /> <File Id="INSTALL" Name="INSTALL" Source="release\owasp_crs\INSTALL" /> <File Id="LICENSE" Name="LICENSE" Source="release\owasp_crs\LICENSE" /> + <File Id="KNOWN_BUGS" Name="KNOWN_BUGS" Source="release\owasp_crs\KNOWN_BUGS" /> <File Id="README.MD" Name="README.md" Source="release\owasp_crs\README.md" /> </Component> - <Directory Id="ACTIVATED_RULES" Name="activated_rules"> + <Directory Id="DOCUMENTATION" Name="documentation"> <Component Id="README" DiskId="1" Guid="F06FC044-52E6-412E-80E6-6644486A522B"> - <File Id="README" Name="README" Source="release\owasp_crs\activated_rules\README" /> - </Component> - </Directory> - <Directory Id="BASE_RULES" Name="base_rules"> - <Component Id="BASE_RULES" DiskId="1" Guid="66EB7DE9-E12D-4360-B096-75CAB0498E88"> - <File Id="MODSECURITY_35_BAD_ROBOTS.DATA" Name="modsecurity_35_bad_robots.data" Source="release\owasp_crs\base_rules\modsecurity_35_bad_robots.data" /> - <File Id="MODSECURITY_35_SCANNERS.DATA" Name="modsecurity_35_scanners.data" Source="release\owasp_crs\base_rules\modsecurity_35_scanners.data" /> - <File Id="MODSECURITY_40_GENERIC_ATTACKS.DATA" Name="modsecurity_40_generic_attacks.data" Source="release\owasp_crs\base_rules\modsecurity_40_generic_attacks.data" /> - <File Id="MODSECURITY_50_OUTBOUND.DATA" Name="modsecurity_50_outbound.data" Source="release\owasp_crs\base_rules\modsecurity_50_outbound.data" /> - <File Id="MODSECURITY_50_OUTBOUND_MALWARE.DATA" Name="modsecurity_50_outbound_malware.data" Source="release\owasp_crs\base_rules\modsecurity_50_outbound_malware.data" /> - <File Id="MODSECURITY_CRS_20_PROTOCOL_VIOLATIONS.CONF" Name="modsecurity_crs_20_protocol_violations.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_20_protocol_violations.conf" /> - <File Id="MODSECURITY_CRS_21_PROTOCOL_ANOMALIES.CONF" Name="modsecurity_crs_21_protocol_anomalies.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_21_protocol_anomalies.conf" /> - <File Id="MODSECURITY_CRS_23_REQUEST_LIMITS.CONF" Name="modsecurity_crs_23_request_limits.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_23_request_limits.conf" /> - <File Id="MODSECURITY_CRS_30_HTTP_POLICY.CONF" Name="modsecurity_crs_30_http_policy.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_30_http_policy.conf" /> - <File Id="MODSECURITY_CRS_35_BAD_ROBOTS.CONF" Name="modsecurity_crs_35_bad_robots.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_35_bad_robots.conf" /> - <File Id="MODSECURITY_CRS_40_GENERIC_ATTACKS.CONF" Name="modsecurity_crs_40_generic_attacks.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_40_generic_attacks.conf" /> - <File Id="MODSECURITY_CRS_41_SQL_INJECTION_ATTACKS.CONF" Name="modsecurity_crs_41_sql_injection_attacks.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_41_sql_injection_attacks.conf" /> - <File Id="MODSECURITY_CRS_41_XSS_ATTACKS.CONF" Name="modsecurity_crs_41_xss_attacks.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_41_xss_attacks.conf" /> - <File Id="MODSECURITY_CRS_42_TIGHT_SECURITY.CONF" Name="modsecurity_crs_42_tight_security.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_42_tight_security.conf" /> - <File Id="MODSECURITY_CRS_45_TROJANS.CONF" Name="modsecurity_crs_45_trojans.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_45_trojans.conf" /> - <File Id="MODSECURITY_CRS_47_COMMON_EXCEPTIONS.CONF" Name="modsecurity_crs_47_common_exceptions.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_47_common_exceptions.conf" /> - <File Id="MODSECURITY_CRS_48_LOCAL_EXCEPTIONS.CONF.EXAMPLE" Name="modsecurity_crs_48_local_exceptions.conf.example" Source="release\owasp_crs\base_rules\modsecurity_crs_48_local_exceptions.conf.example" /> - <File Id="MODSECURITY_CRS_49_INBOUND_BLOCKING.CONF" Name="modsecurity_crs_49_inbound_blocking.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_49_inbound_blocking.conf" /> - <File Id="MODSECURITY_CRS_50_OUTBOUND.CONF" Name="modsecurity_crs_50_outbound.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_50_outbound.conf" /> - <File Id="MODSECURITY_CRS_59_OUTBOUND_BLOCKING.CONF" Name="modsecurity_crs_59_outbound_blocking.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_59_outbound_blocking.conf" /> - <File Id="MODSECURITY_CRS_60_CORRELATION.CONF" Name="modsecurity_crs_60_correlation.conf" Source="release\owasp_crs\base_rules\modsecurity_crs_60_correlation.conf" /> - </Component> - </Directory> - <Directory Id="EXPERIMENTAL_RULES" Name="experimental_rules"> - <Component Id="EXPERIMENTAL_RULES" DiskId="1" Guid="B2504C95-7338-49CA-9786-ACEF671ABB93"> - <File Id="MODSECURITY_CRS_11_BRUTE_FORCE.CONF" Name="modsecurity_crs_11_brute_force.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_11_brute_force.conf" /> - <File Id="MODSECURITY_CRS_11_DOS_PROTECTION.CONF" Name="modsecurity_crs_11_dos_protection.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_11_dos_protection.conf" /> - <File Id="MODSECURITY_CRS_11_PROXY_ABUSE.CONF" Name="modsecurity_crs_11_proxy_abuse.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_11_proxy_abuse.conf" /> - <File Id="MODSECURITY_CRS_11_SLOW_DOS_PROTECTION.CONF" Name="modsecurity_crs_11_slow_dos_protection.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_11_slow_dos_protection.conf" /> - <File Id="MODSECURITY_CRS_16_SCANNER_INTEGRATION.CONF" Name="modsecurity_crs_16_scanner_integration.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_16_scanner_integration.conf" /> - <File Id="MODSECURITY_CRS_25_CC_TRACK_PAN.CONF" Name="modsecurity_crs_25_cc_track_pan.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_25_cc_track_pan.conf" /> - <File Id="MODSECURITY_CRS_40_APPSENSOR_DETECTION_POINT_2.0_SETUP.CONF" Name="modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf" /> - <File Id="MODSECURITY_CRS_40_APPSENSOR_DETECTION_POINT_2.1_REQUEST_EXCEPTION.CONF" Name="modsecurity_crs_40_appsensor_detection_point_2.1_request_exception.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_40_appsensor_detection_point_2.1_request_exception.conf" /> - <File Id="MODSECURITY_CRS_40_APPSENSOR_DETECTION_POINT_2.9_HONEYTRAP.CONF" Name="modsecurity_crs_40_appsensor_detection_point_2.9_honeytrap.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_40_appsensor_detection_point_2.9_honeytrap.conf" /> - <File Id="MODSECURITY_CRS_40_APPSENSOR_DETECTION_POINT_3.0_END.CONF" Name="modsecurity_crs_40_appsensor_detection_point_3.0_end.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_40_appsensor_detection_point_3.0_end.conf" /> - <File Id="MODSECURITY_CRS_40_HTTP_PARAMETER_POLLUTION.CONF" Name="modsecurity_crs_40_http_parameter_pollution.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_40_http_parameter_pollution.conf" /> - <File Id="MODSECURITY_CRS_42_CSP_ENFORCEMENT.CONF" Name="modsecurity_crs_42_csp_enforcement.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_42_csp_enforcement.conf" /> - <File Id="MODSECURITY_CRS_46_SCANNER_INTEGRATION.CONF" Name="modsecurity_crs_46_scanner_integration.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_46_scanner_integration.conf" /> - <File Id="MODSECURITY_CRS_48_BAYES_ANALYSIS.CONF" Name="modsecurity_crs_48_bayes_analysis.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_48_bayes_analysis.conf" /> - <File Id="MODSECURITY_CRS_55_RESPONSE_PROFILING.CONF" Name="modsecurity_crs_55_response_profiling.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_55_response_profiling.conf" /> - <File Id="MODSECURITY_CRS_56_PVI_CHECKS.CONF" Name="modsecurity_crs_56_pvi_checks.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_56_pvi_checks.conf" /> - <File Id="MODSECURITY_CRS_61_IP_FORENSICS.CONF" Name="modsecurity_crs_61_ip_forensics.conf" Source="release\owasp_crs\experimental_rules\modsecurity_crs_61_ip_forensics.conf" /> - </Component> - </Directory> - <Directory Id="LUA" Name="lua"> - <Component Id="LUA" DiskId="1" Guid="BF9033A5-C9A4-4867-92CA-CDD174CBE420"> - <File Id="ADVANCED_FILTER_CONVERTER.LUA" Name="advanced_filter_converter.lua" Source="release\owasp_crs\lua\advanced_filter_converter.lua" /> - <File Id="APPSENSOR_REQUEST_EXCEPTION_ENFORCE.LUA" Name="appsensor_request_exception_enforce.lua" Source="release\owasp_crs\lua\appsensor_request_exception_enforce.lua" /> - <File Id="APPSENSOR_REQUEST_EXCEPTION_PROFILE.LUA" Name="appsensor_request_exception_profile.lua" Source="release\owasp_crs\lua\appsensor_request_exception_profile.lua" /> - <File Id="ARACHNI_INTEGRATION.LUA" Name="arachni_integration.lua" Source="release\owasp_crs\lua\arachni_integration.lua" /> - <File Id="BAYES_CHECK_SPAM.LUA" Name="bayes_check_spam.lua" Source="release\owasp_crs\lua\bayes_check_spam.lua" /> - <File Id="BAYES_TRAIN_HAM.LUA" Name="bayes_train_ham.lua" Source="release\owasp_crs\lua\bayes_train_ham.lua" /> - <File Id="BAYES_TRAIN_SPAM.LUA" Name="bayes_train_spam.lua" Source="release\owasp_crs\lua\bayes_train_spam.lua" /> - <File Id="GATHER_IP_DATA.LUA" Name="gather_ip_data.lua" Source="release\owasp_crs\lua\gather_ip_data.lua" /> - <File Id="OSVDB.LUA" Name="osvdb.lua" Source="release\owasp_crs\lua\osvdb.lua" /> - <File Id="PROFILE_PAGE_SCRIPTS.LUA" Name="profile_page_scripts.lua" Source="release\owasp_crs\lua\profile_page_scripts.lua" /> + <File Id="README" Name="README" Source="release\owasp_crs\documentation\README" /> </Component> + <Directory Id="OWASP_CRS_DOCUMENTATION" Name="OWASP-CRS-Documentation"> + </Directory> </Directory> - <Directory Id="OPTIONAL_RULES" Name="optional_rules"> - <Component Id="OPTIONAL_RULES" DiskId="1" Guid="8744C127-31F0-4C4E-85FB-D86BDEA3627B"> - <File Id="MODSECURITY_42_COMMENT_SPAM.DATA" Name="modsecurity_42_comment_spam.data" Source="release\owasp_crs\optional_rules\modsecurity_42_comment_spam.data" /> - <File Id="MODSECURITY_CRS_10_IGNORE_STATIC.CONF" Name="modsecurity_crs_10_ignore_static.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_10_ignore_static.conf" /> - <File Id="MODSECURITY_CRS_11_AVS_TRAFFIC.CONF" Name="modsecurity_crs_11_avs_traffic.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_11_avs_traffic.conf" /> - <File Id="MODSECURITY_CRS_13_XML_ENABLER.CONF" Name="modsecurity_crs_13_xml_enabler.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_13_xml_enabler.conf" /> - <File Id="MODSECURITY_CRS_16_AUTHENTICATION_TRACKING.CONF" Name="modsecurity_crs_16_authentication_tracking.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_16_authentication_tracking.conf" /> - <File Id="MODSECURITY_CRS_16_SESSION_HIJACKING.CONF" Name="modsecurity_crs_16_session_hijacking.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_16_session_hijacking.conf" /> - <File Id="MODSECURITY_CRS_16_USERNAME_TRACKING.CONF" Name="modsecurity_crs_16_username_tracking.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_16_username_tracking.conf" /> - <File Id="MODSECURITY_CRS_25_CC_KNOWN.CONF" Name="modsecurity_crs_25_cc_known.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_25_cc_known.conf" /> - <File Id="MODSECURITY_CRS_42_COMMENT_SPAM.CONF" Name="modsecurity_crs_42_comment_spam.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_42_comment_spam.conf" /> - <File Id="MODSECURITY_CRS_43_CSRF_PROTECTION.CONF" Name="modsecurity_crs_43_csrf_protection.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_43_csrf_protection.conf" /> - <File Id="MODSECURITY_CRS_46_AV_SCANNING.CONF" Name="modsecurity_crs_46_av_scanning.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_46_av_scanning.conf" /> - <File Id="MODSECURITY_CRS_47_SKIP_OUTBOUND_CHECKS.CONF" Name="modsecurity_crs_47_skip_outbound_checks.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_47_skip_outbound_checks.conf" /> - <File Id="MODSECURITY_CRS_49_HEADER_TAGGING.CONF" Name="modsecurity_crs_49_header_tagging.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_49_header_tagging.conf" /> - <File Id="MODSECURITY_CRS_55_APPLICATION_DEFECTS.CONF" Name="modsecurity_crs_55_application_defects.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_55_application_defects.conf" /> - <File Id="MODSECURITY_CRS_55_MARKETING.CONF" Name="modsecurity_crs_55_marketing.conf" Source="release\owasp_crs\optional_rules\modsecurity_crs_55_marketing.conf" /> + <Directory Id="ID_RENUMBERING" Name="id_renumbering"> + <Component Id="ID_NUMBERING" DiskId="1" Guid="F06FC044-52E6-412E-80E6-6644486A522D"> + <File Id="IDNUMBERING_1" Name="IDNUMBERING" Source="release\owasp_crs\id_renumbering\IDNUMBERING" /> + <File Id="IDNUMBERING.CSV" Name="IdNumbering.csv" Source="release\owasp_crs\id_renumbering\IdNumbering.csv" /> + <File Id="UPDATE.PY" Name="update.py" Source="release\owasp_crs\id_renumbering\update.py" /> </Component> </Directory> - <Directory Id="SLR_RULES" Name="slr_rules"> - <Component Id="SLR_RULES" DiskId="1" Guid="A880D035-8933-4A83-9D14-2FE010F4BF79"> - <File Id="MODSECURITY_46_SLR_ET_JOOMLA.DATA" Name="modsecurity_46_slr_et_joomla.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_joomla.data" /> - <File Id="MODSECURITY_46_SLR_ET_LFI.DATA" Name="modsecurity_46_slr_et_lfi.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_lfi.data" /> - <File Id="MODSECURITY_46_SLR_ET_PHPBB.DATA" Name="modsecurity_46_slr_et_phpbb.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_phpbb.data" /> - <File Id="MODSECURITY_46_SLR_ET_RFI.DATA" Name="modsecurity_46_slr_et_rfi.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_rfi.data" /> - <File Id="MODSECURITY_46_SLR_ET_SQLI.DATA" Name="modsecurity_46_slr_et_sqli.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_sqli.data" /> - <File Id="MODSECURITY_46_SLR_ET_WORDPRESS.DATA" Name="modsecurity_46_slr_et_wordpress.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_wordpress.data" /> - <File Id="MODSECURITY_46_SLR_ET_XSS.DATA" Name="modsecurity_46_slr_et_xss.data" Source="release\owasp_crs\slr_rules\modsecurity_46_slr_et_xss.data" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_JOOMLA_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_joomla_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_joomla_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_LFI_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_lfi_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_lfi_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_PHPBB_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_phpbb_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_phpbb_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_RFI_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_rfi_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_rfi_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_SQLI_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_sqli_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_sqli_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_WORDPRESS_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_wordpress_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_wordpress_attacks.conf" /> - <File Id="MODSECURITY_CRS_46_SLR_ET_XSS_ATTACKS.CONF" Name="modsecurity_crs_46_slr_et_xss_attacks.conf" Source="release\owasp_crs\slr_rules\modsecurity_crs_46_slr_et_xss_attacks.conf" /> + <Directory Id="RULES" Name="rules"> + <Component Id="RULES" DiskId="1" Guid="66EB7DE9-E12D-4360-B096-75CAB0498E88"> + <File Id="CRAWLERS_USER_AGENTS.DATA" Name="crawlers-user-agents.data" Source="release\owasp_crs\rules\crawlers-user-agents.data" /> + <File Id="IIS_ERRORS.DATA" Name="iis-errors.data" Source="release\owasp_crs\rules\iis-errors.data" /> + <File Id="JAVA_CODE_LEAKAGES.DATA" Name="java-code-leakages.data" Source="release\owasp_crs\rules\java-code-leakages.data" /> + <File Id="JAVA_ERRORS.DATA" Name="java-errors.data" Source="release\owasp_crs\rules\java-errors.data" /> + <File Id="LFI_OS_FILES.DATA" Name="lfi-os-files.data" Source="release\owasp_crs\rules\lfi-os-files.data" /> + <File Id="PHP_CONFIG_DIRECTIVES.DATA" Name="php-config-directives.data" Source="release\owasp_crs\rules\php-config-directives.data" /> + <File Id="PHP_ERRORS.DATA" Name="php-errors.data" Source="release\owasp_crs\rules\php-errors.data" /> + <File Id="PHP_FUNCTION_NAMES_933150.DATA" Name="php-function-names-933150.data" Source="release\owasp_crs\rules\php-function-names-933150.data" /> + <File Id="PHP_FUNCTION_NAMES_933151.DATA" Name="php-function-names-933151.data" Source="release\owasp_crs\rules\php-function-names-933151.data" /> + <File Id="PHP_VARIABLES.DATA" Name="php-variables.data" Source="release\owasp_crs\rules\php-variables.data" /> + <File Id="REQUEST_900_EXCLUSION_RULES_BEFORE_CRS.conf.example" Name="REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf" Source="release\owasp_crs\rules\REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf" /> + <File Id="REQUEST_901_INITIALIZATION.conf" Name="REQUEST-901-INITIALIZATION.conf" Source="release\owasp_crs\rules\REQUEST-901-INITIALIZATION.conf" /> + <File Id="REQUEST_903.9001_DRUPAL_EXCLUSION_RULES.conf" Name="REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf" Source="release\owasp_crs\rules\REQUEST-903.9001-DRUPAL-EXCLUSION-RULES.conf" /> + <File Id="REQUEST_903.9002_WORDPRESS_EXCLUSION_RULES.conf" Name="REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf" Source="release\owasp_crs\rules\REQUEST-903.9002-WORDPRESS-EXCLUSION-RULES.conf" /> + <File Id="REQUEST_905_COMMON_EXCEPTIONS.conf" Name="REQUEST-905-COMMON-EXCEPTIONS.conf" Source="release\owasp_crs\rules\REQUEST-905-COMMON-EXCEPTIONS.conf" /> + <File Id="REQUEST_910_IP_REPUTATION.conf" Name="REQUEST-910-IP-REPUTATION.conf" Source="release\owasp_crs\rules\REQUEST-910-IP-REPUTATION.conf" /> + <File Id="REQUEST_911_METHOD_ENFORCEMENT.conf" Name="REQUEST-911-METHOD-ENFORCEMENT.conf" Source="release\owasp_crs\rules\REQUEST-911-METHOD-ENFORCEMENT.conf" /> + <File Id="REQUEST_912_DOS_PROTECTION.conf" Name="REQUEST-912-DOS-PROTECTION.conf" Source="release\owasp_crs\rules\REQUEST-912-DOS-PROTECTION.conf" /> + <File Id="REQUEST_913_SCANNER_DETECTION.conf" Name="REQUEST-913-SCANNER-DETECTION.conf" Source="release\owasp_crs\rules\REQUEST-913-SCANNER-DETECTION.conf" /> + <File Id="REQUEST_920_PROTOCOL_ENFORCEMENT.conf" Name="REQUEST-920-PROTOCOL-ENFORCEMENT.conf" Source="release\owasp_crs\rules\REQUEST-920-PROTOCOL-ENFORCEMENT.conf" /> + <File Id="REQUEST_921_PROTOCOL_ATTACK.conf" Name="REQUEST-921-PROTOCOL-ATTACK.conf" Source="release\owasp_crs\rules\REQUEST-921-PROTOCOL-ATTACK.conf" /> + <File Id="REQUEST_930_APPLICATION_ATTACK_LFI.conf" Name="REQUEST-930-APPLICATION-ATTACK-LFI.conf" Source="release\owasp_crs\rules\REQUEST-930-APPLICATION-ATTACK-LFI.conf" /> + <File Id="REQUEST_931_APPLICATION_ATTACK_RFI.conf" Name="REQUEST-931-APPLICATION-ATTACK-RFI.conf" Source="release\owasp_crs\rules\REQUEST-931-APPLICATION-ATTACK-RFI.conf" /> + <File Id="REQUEST_932_APPLICATION_ATTACK_RCE.conf" Name="REQUEST-932-APPLICATION-ATTACK-RCE.conf" Source="release\owasp_crs\rules\REQUEST-932-APPLICATION-ATTACK-RCE.conf" /> + <File Id="REQUEST_933_APPLICATION_ATTACK_PHP.conf" Name="REQUEST-933-APPLICATION-ATTACK-PHP.conf" Source="release\owasp_crs\rules\REQUEST-933-APPLICATION-ATTACK-PHP.conf" /> + <File Id="REQUEST_941_APPLICATION_ATTACK_XSS.conf" Name="REQUEST-941-APPLICATION-ATTACK-XSS.conf" Source="release\owasp_crs\rules\REQUEST-941-APPLICATION-ATTACK-XSS.conf" /> + <File Id="REQUEST_942_APPLICATION_ATTACK_SQLI.conf" Name="REQUEST-942-APPLICATION-ATTACK-SQLI.conf" Source="release\owasp_crs\rules\REQUEST-942-APPLICATION-ATTACK-SQLI.conf" /> + <File Id="REQUEST_943_APPLICATION_ATTACK_SESSION_FIXATION.conf" Name="REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf" Source="release\owasp_crs\rules\REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION.conf" /> + <File Id="REQUEST_949_BLOCKING_EVALUATION.conf" Name="REQUEST-949-BLOCKING-EVALUATION.conf" Source="release\owasp_crs\rules\REQUEST-949-BLOCKING-EVALUATION.conf" /> + <File Id="RESPONSE_950_DATA_LEAKAGES.conf" Name="RESPONSE-950-DATA-LEAKAGES.conf" Source="release\owasp_crs\rules\RESPONSE-950-DATA-LEAKAGES.conf" /> + <File Id="RESPONSE_951_DATA_LEAKAGES_SQL.conf" Name="RESPONSE-951-DATA-LEAKAGES-SQL.conf" Source="release\owasp_crs\rules\RESPONSE-951-DATA-LEAKAGES-SQL.conf" /> + <File Id="RESPONSE_952_DATA_LEAKAGES_JAVA.conf" Name="RESPONSE-952-DATA-LEAKAGES-JAVA.conf" Source="release\owasp_crs\rules\RESPONSE-952-DATA-LEAKAGES-JAVA.conf" /> + <File Id="RESPONSE_953_DATA_LEAKAGES_PHP.conf" Name="RESPONSE-953-DATA-LEAKAGES-PHP.conf" Source="release\owasp_crs\rules\RESPONSE-953-DATA-LEAKAGES-PHP.conf" /> + <File Id="RESPONSE_954_DATA_LEAKAGES_IIS.conf" Name="RESPONSE-954-DATA-LEAKAGES-IIS.conf" Source="release\owasp_crs\rules\RESPONSE-954-DATA-LEAKAGES-IIS.conf" /> + <File Id="RESPONSE_959_BLOCKING_EVALUATION.conf" Name="RESPONSE-959-BLOCKING-EVALUATION.conf" Source="release\owasp_crs\rules\RESPONSE-959-BLOCKING-EVALUATION.conf" /> + <File Id="RESPONSE_980_CORRELATION.conf" Name="RESPONSE-980-CORRELATION.conf" Source="release\owasp_crs\rules\RESPONSE-980-CORRELATION.conf" /> + <File Id="RESPONSE_999_EXCLUSION_RULES_AFTER_CRS.conf" Name="RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf" Source="release\owasp_crs\rules\RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf" /> + <File Id="RESTRICTED_FILES.DATA" Name="restricted-files.data" Source="release\owasp_crs\rules\restricted-files.data" /> + <File Id="SCANNERS_HEADERS.DATA" Name="scanners-headers.data" Source="release\owasp_crs\rules\scanners-headers.data" /> + <File Id="SCANNERS_URLS.DATA" Name="scanners-urls.data" Source="release\owasp_crs\rules\scanners-urls.data" /> + <File Id="SCANNERS_USER_AGENTS.DATA" Name="scanners-user-agents.data" Source="release\owasp_crs\rules\scanners-user-agents.data" /> + <File Id="SCRIPTING_USER_AGENTS.DATA" Name="scripting-user-agents.data" Source="release\owasp_crs\rules\scripting-user-agents.data" /> + <File Id="SQL_ERRORS.DATA" Name="sql-errors.data" Source="release\owasp_crs\rules\sql-errors.data" /> + <File Id="SQL_FUNCTION_NAMES.DATA" Name="sql-function-names.data" Source="release\owasp_crs\rules\sql-function-names.data" /> + <File Id="UNIX_SHELL.DATA" Name="unix-shell.data" Source="release\owasp_crs\rules\unix-shell.data" /> + <File Id="WINDOWS_POWERSHELL_COMMANDS.DATA" Name="windows-powershell-commands.data" Source="release\owasp_crs\rules\windows-powershell-commands.data" /> </Component> </Directory> <Directory Id="UTIL" Name="util"> <Component Id="UTIL" DiskId="1" Guid="A95D50D7-4E87-4A87-BAD1-12370B8F5B9B"> + <File Id="ID_RANGE" Name="id-range" Source="release\owasp_crs\util\id-range" /> <File Id="README_1" Name="README" Source="release\owasp_crs\util\README" /> + <File Id="UPGRADE.PY" Name="upgrade.py" Source="release\owasp_crs\util\upgrade.py" /> + <File Id="VERIFY.RB" Name="verify.rb" Source="release\owasp_crs\util\verify.rb" /> </Component> <Directory Id="AV_SCANNING" Name="av-scanning"> <Component Id="RUNAV" DiskId="1" Guid="398B0257-F78A-4F8C-B313-90D0F61581A9"> @@ -267,6 +235,43 @@ <File Id="JS_OVERRIDES.JS" Name="js-overrides.js" Source="release\owasp_crs\util\browser-tools\js-overrides.js" /> </Component> </Directory> + <Directory Id="DEBUG" Name="debug"> + <Component Id="DEBUG" DiskId="1" Guid="A81D4319-9C26-4E29-A0BD-FC2DED0045A8"> + <File Id="RESPONSE_981_DEBUG.CONF" Name="RESPONSE-981-DEBUG.conf" Source="release\owasp_crs\util\debug\RESPONSE-981-DEBUG.conf" /> + </Component> + </Directory> + <Directory Id="GEO_LOCATION" Name="geo-location"> + <Component Id="GEO_LOCATION" DiskId="1" Guid="A81D4319-9C26-4E29-A0BD-FC2DED0045A9"> + <File Id="README_2" Name="README" Source="release\owasp_crs\util\geo-location\README" /> + </Component> + </Directory> + <Directory Id="INTEGRATION" Name="integration"> + <Component Id="INTEGRATION" DiskId="1" Guid="A81D4319-9C26-4E29-A0BD-FC2DED0045B0"> + <File Id="FORMAT_TESTS.PY" Name="format_tests.py" Source="release\owasp_crs\util\integration\format_tests.py" /> + <File Id="REQUIREMENTS.TXT" Name="requirements.txt" Source="release\owasp_crs\util\integration\requirements.txt" /> + </Component> + </Directory> + <Directory Id="JOIN_MULTILINE_RULES" Name="join-multiline-rules"> + <Component Id="JOIN_MULTILINE_RULES" DiskId="1" Guid="A81D4319-9C26-4E29-A0BD-FC2DED0045B1"> + <File Id="JOIN.PY" Name="join.py" Source="release\owasp_crs\util\join-multiline-rules\join.py" /> + </Component> + </Directory> + <Directory Id="REGEXP_ASSEMBLE" Name="regexp-assemble"> + <Component Id="REGEXP_ASSEMBLE" DiskId="1" Guid="A81D4319-9C26-4E29-A0BD-FC2DED0045B2"> + <File Id="REGEXP_932130.DATA" Name="regexp-932130.data" Source="release\owasp_crs\util\regexp-assemble\regexp-932130.data" /> + <File Id="REGEXP_932140.DATA" Name="regexp-932140.data" Source="release\owasp_crs\util\regexp-assemble\regexp-932140.data" /> + <File Id="REGEXP_933131.DATA" Name="regexp-933131.data" Source="release\owasp_crs\util\regexp-assemble\regexp-933131.data" /> + <File Id="REGEXP_933160.DATA" Name="regexp-933160.data" Source="release\owasp_crs\util\regexp-assemble\regexp-933160.data" /> + <File Id="REGEXP_933161.DATA" Name="regexp-933161.data" Source="release\owasp_crs\util\regexp-assemble\regexp-933161.data" /> + <File Id="REGEXP_ASSEMBLE.PL" Name="regexp-assemble.pl" Source="release\owasp_crs\util\regexp-assemble\regexp-assemble.pl" /> + <File Id="REGEXP_932100.TXT" Name="regexp-932100.txt" Source="release\owasp_crs\util\regexp-assemble\regexp-932100.txt" /> + <File Id="REGEXP_932105.TXT" Name="regexp-932105.txt" Source="release\owasp_crs\util\regexp-assemble\regexp-932105.txt" /> + <File Id="REGEXP_932110.TXT" Name="regexp-932110.txt" Source="release\owasp_crs\util\regexp-assemble\regexp-932110.txt" /> + <File Id="REGEXP_932115.TXT" Name="regexp-932115.txt" Source="release\owasp_crs\util\regexp-assemble\regexp-932115.txt" /> + <File Id="REGEXP_932150.TXT" Name="regexp-932150.txt" Source="release\owasp_crs\util\regexp-assemble\regexp-932150.txt" /> + <File Id="REGEXP_CMDLINE.PY" Name="regexp-cmdline.py" Source="release\owasp_crs\util\regexp-assemble\regexp-cmdline.py" /> + </Component> + </Directory> <Directory Id="HONEYPOT_SENSOR" Name="honeypot-sensor"> <Component Id="HONEYPOT_SENSOR" DiskId="1" Guid="3D3DD51F-70FF-41CE-A756-2C2935A71BA8"> <File Id="MLOGC_HONEYPOT_SENSOR.CONF" Name="mlogc-honeypot-sensor.conf" Source="release\owasp_crs\util\honeypot-sensor\mlogc-honeypot-sensor.conf" /> @@ -276,35 +281,11 @@ </Directory> <Directory Id="REGRESSION_TESTS" Name="regression-tests"> <Component Id="REGRESSION_TESTS" DiskId="1" Guid="02AF3C5A-DCF9-4DB6-A1C8-B1EF140C8EBC"> - <File Id="INSTALL_1" Name="INSTALL" Source="release\owasp_crs\util\regression-tests\INSTALL" /> - <File Id="MODSECURITY_CRS_59_HEADER_TAGGING.CONF" Name="modsecurity_crs_59_header_tagging.conf" Source="release\owasp_crs\util\regression-tests\modsecurity_crs_59_header_tagging.conf" /> - <File Id="README_2" Name="README" Source="release\owasp_crs\util\regression-tests\README" /> - <File Id="RULESTEST.CONF" Name="rulestest.conf" Source="release\owasp_crs\util\regression-tests\rulestest.conf" /> - <File Id="RULESTEST.PL" Name="rulestest.pl" Source="release\owasp_crs\util\regression-tests\rulestest.pl" /> - <File Id="TESTSERVER.CGI" Name="testserver.cgi" Source="release\owasp_crs\util\regression-tests\testserver.cgi" /> + <File Id="README_3" Name="README" Source="release\owasp_crs\util\regression-tests\README" /> </Component> - <Directory Id="TESTS" Name="tests"> - <Component Id="TESTS" DiskId="1" Guid="FCCBB8FE-4327-4AF0-AB5C-3120858EBB16"> - <File Id="MODSECURITY_CRS_20_PROTOCOL_VIOLATIONS.TESTS" Name="modsecurity_crs_20_protocol_violations.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_20_protocol_violations.tests" /> - <File Id="MODSECURITY_CRS_21_PROTOCOL_ANOMALIES.TESTS" Name="modsecurity_crs_21_protocol_anomalies.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_21_protocol_anomalies.tests" /> - <File Id="MODSECURITY_CRS_23_REQUEST_LIMITS.TESTS" Name="modsecurity_crs_23_request_limits.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_23_request_limits.tests" /> - <File Id="MODSECURITY_CRS_30_HTTP_POLICY.TESTS" Name="modsecurity_crs_30_http_policy.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_30_http_policy.tests" /> - <File Id="MODSECURITY_CRS_35_BAD_ROBOTS.TESTS" Name="modsecurity_crs_35_bad_robots.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_35_bad_robots.tests" /> - <File Id="MODSECURITY_CRS_40_GENERIC_ATTACKS.TESTS" Name="modsecurity_crs_40_generic_attacks.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_40_generic_attacks.tests" /> - <File Id="MODSECURITY_CRS_41_SQL_INJECTION_ATTACKS.TESTS" Name="modsecurity_crs_41_sql_injection_attacks.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_41_sql_injection_attacks.tests" /> - <File Id="MODSECURITY_CRS_41_XSS_ATTACKS.TESTS" Name="modsecurity_crs_41_xss_attacks.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_41_xss_attacks.tests" /> - <File Id="MODSECURITY_CRS_50_OUTBOUND.TESTS" Name="modsecurity_crs_50_outbound.tests" Source="release\owasp_crs\util\regression-tests\tests\modsecurity_crs_50_outbound.tests" /> - <File Id="RUBY.TESTS" Name="ruby.tests" Source="release\owasp_crs\util\regression-tests\tests\ruby.tests" /> - </Component> + <Directory Id="OWASP_CRS_REGRESSIONS" Name="OWASP-CRS-regressions"> </Directory> </Directory> - <Directory Id="RULE_MANAGEMENT" Name="rule-management"> - <Component Id="RULE_MANAGEMENT" DiskId="1" Guid="0368949F-5721-4648-A789-1D5598F327F5"> - <File Id="ID_RANGE" Name="id-range" Source="release\owasp_crs\util\rule-management\id-range" /> - <File Id="REMOVE_2.7_ACTIONS.PL" Name="remove-2.7-actions.pl" Source="release\owasp_crs\util\rule-management\remove-2.7-actions.pl" /> - <File Id="VERIFY.RB" Name="verify.rb" Source="release\owasp_crs\util\rule-management\verify.rb" /> - </Component> - </Directory> <Directory Id="VIRTUAL_PATCHING" Name="virtual-patching"> <Component Id="VIRTUAL_PATCHING" DiskId="1" Guid="DDDD3A2B-CEC1-42B3-9984-2987CA5BA311"> <File Id="ARACHNI2MODSEC.PL" Name="arachni2modsec.pl" Source="release\owasp_crs\util\virtual-patching\arachni2modsec.pl" /> @@ -340,6 +321,7 @@ <File Id="EULA.RTF" Name="EULA.rtf" Source="wix\EULA.rtf" /> <File Id="modsecurity.conf" Name="modsecurity.conf" Source="wix\modsecurity.conf" /> <File Id="modsecurity_iis.conf" Name="modsecurity_iis.conf" Source="wix\modsecurity_iis.conf" /> + <File Id="unicode.mapping" Name="unicode.mapping" Source="wix\unicode.mapping" /> <!-- <File Id="modsecurity_crs_10_setup.conf" Name="modsecurity_crs_10_setup.conf" Source="wix\modsecurity_crs_10_setup.conf" /> --> <File Id="LIST_DEPENDENCIES.BAT" Name="list_dependencies.bat" Source="wix\list_dependencies.bat" /> <File Id="ModSecurity.xml" Name="ModSecurity.xml" Source="ModSecurity.xml" /> @@ -428,24 +410,24 @@ <ComponentRef Id="ConfigSchema64" /> <?endif ?> <ComponentRef Id="StartMenuShortcuts" /> - <Feature Id="OWASP_ModSecurity_CRS_v2.2.9" Level="1" Title="OWASP ModSecurity CRS v2.2.9" InstallDefault="local" Display="expand" AllowAdvertise="no" Description="Install OWASP CRS v2.2.9"> - <ComponentRef Id="OWASP_CRS_V_2_2_9" /> - <ComponentRef Id="OWASP_CRS_V_2_2_9_SETUP" /> + <Feature Id="OWASP_ModSecurity_CRS_v3.0.2" Level="1" Title="OWASP ModSecurity CRS v3.0.2" InstallDefault="local" Display="expand" AllowAdvertise="no" Description="Install OWASP CRS v3.0.2"> + <ComponentRef Id="OWASP_CRS_V_3_0_2" /> + <ComponentRef Id="OWASP_CRS_V_3_0_2_SETUP" /> + <ComponentRef Id="ID_NUMBERING" /> <ComponentRef Id="README" /> - <ComponentRef Id="BASE_RULES" /> - <ComponentRef Id="EXPERIMENTAL_RULES" /> - <ComponentRef Id="LUA" /> - <ComponentRef Id="OPTIONAL_RULES" /> - <ComponentRef Id="SLR_RULES" /> + <ComponentRef Id="RULES" /> <ComponentRef Id="UTIL" /> <ComponentRef Id="RUNAV" /> <ComponentRef Id="RUNAV_RUNAV" /> <ComponentRef Id="BROWSER_TOOLS" /> + <ComponentRef Id="DEBUG" /> + <ComponentRef Id="GEO_LOCATION" /> + <ComponentRef Id="INTEGRATION" /> + <ComponentRef Id="JOIN_MULTILINE_RULES" /> + <ComponentRef Id="REGEXP_ASSEMBLE" /> <ComponentRef Id="HONEYPOT_SENSOR" /> <ComponentRef Id="REGRESSION_TESTS" /> - <ComponentRef Id="TESTS" /> - <ComponentRef Id="RULE_MANAGEMENT" /> <ComponentRef Id="VIRTUAL_PATCHING" /> </Feature> </Feature> diff --git a/iis/wix/modsecurity_iis.conf b/iis/wix/modsecurity_iis.conf index 85d20ba74f..7cd9cff49f 100644 --- a/iis/wix/modsecurity_iis.conf +++ b/iis/wix/modsecurity_iis.conf @@ -1,3 +1,3 @@ Include modsecurity.conf -Include modsecurity_crs_10_setup.conf -Include owasp_crs\base_rules\*.conf +Include crs-setup.conf.example +Include owasp_crs\rules\*.conf From a21f97066b0ab63a661de8793f14c0a4bfa005dc Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Mon, 12 Nov 2018 15:54:36 -0500 Subject: [PATCH 217/477] Fix modsecurity.conf for IIS update CHANGES file --- CHANGES | 2 ++ iis/wix/modsecurity.conf | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index df79fcd30e..4d693420bd 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * IIS: Update Wix installer to bundle a supported CRS version (3.0) + [@victorhora, @zimmerle] * IIS: Update dependencies for Windows build [Issue #1848 - @victorhora, @hsluoyz] * IIS: Set SecStreamInBodyInspection by default on IIS builds (#1299) diff --git a/iis/wix/modsecurity.conf b/iis/wix/modsecurity.conf index 42e6b55399..fcce635963 100644 --- a/iis/wix/modsecurity.conf +++ b/iis/wix/modsecurity.conf @@ -194,10 +194,10 @@ SecAuditLogParts ABIJDEFHZ # assumes that you will use the audit log only ocassionally. # SecAuditLogType Serial -SecAuditLog c:\inetpub\log\modsec_audit.log +#SecAuditLog c:\inetpub\logs\modsec_audit.log # Specify the path for concurrent audit logging. -#SecAuditLogStorageDir c:\inetpub\log\ +#SecAuditLogStorageDir c:\inetpub\logs\ # -- Miscellaneous ----------------------------------------------------------- From d8c711257bfcca2845108190900eb6cd194c7d0b Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Mon, 12 Nov 2018 19:54:18 -0500 Subject: [PATCH 218/477] CHANGES: Adds info about: #1714 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 4d693420bd..588860bf5e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix sanitizing JSON request bodies in native audit log format + [p0pr0ck5, @victorhora] * IIS: Update Wix installer to bundle a supported CRS version (3.0) [@victorhora, @zimmerle] * IIS: Update dependencies for Windows build From b600669d02d2344089c8b024f75c806619cb3135 Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Tue, 13 Nov 2018 20:03:41 -0500 Subject: [PATCH 219/477] Fix buffer size for utf8toUnicode transformation --- CHANGES | 2 ++ apache2/msc_util.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 588860bf5e..6805665acb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Fix buffer size for utf8toUnicode transformation + [Issue #1208 - @katef, @victorhora] * Fix sanitizing JSON request bodies in native audit log format [p0pr0ck5, @victorhora] * IIS: Update Wix installer to bundle a supported CRS version (3.0) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 9781d2d60d..d687ac4de3 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -113,8 +113,9 @@ char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int inp unsigned char *unicode = NULL; *changed = 0; - - len = input_len * 7 + 1; + /* RFC3629 states that UTF-8 are encoded using sequences of 1 to 4 octets. */ + /* Max size per character should fit in 4 bytes */ + len = input_len * 4 + 1; data = rval = apr_palloc(mp, len); if (rval == NULL) return NULL; From 7af8363fd46fd5a0bb21cc6b623d6b344f27be2a Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Fri, 16 Jun 2017 17:42:24 -0700 Subject: [PATCH 220/477] Less strict multipart parsing --- apache2/msc_multipart.c | 53 ++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 45c18e3444..880b13c579 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -695,42 +695,29 @@ static int multipart_boundary_characters_valid(char *boundary) { if (p == NULL) return -1; - while((c = *p) != '\0') { - /* Control characters and space not allowed. */ - if (c < 32) { + while ((c = *p) != '\0') { + // Check against allowed list defined in RFC2046 page 21 + if (!( + ('0' <= c && c <= '9') + || ('A' <= c && c <= 'Z') + || ('a' <= c && c <= 'z') + || (c == ' ' && *(p + 1) != '\0') // space allowed, but not as last character + || c == '\'' + || c == '(' + || c == ')' + || c == '+' + || c == '_' + || c == ',' + || c == '-' + || c == '.' + || c == '/' + || c == ':' + || c == '=' + || c == '?' + )) { return 0; } - /* Non-ASCII characters not allowed. */ - if (c > 126) { - return 0; - } - - switch(c) { - /* Special characters not allowed. */ - case '(' : - case ')' : - case '<' : - case '>' : - case '@' : - case ',' : - case ';' : - case ':' : - case '\\' : - case '"' : - case '/' : - case '[' : - case ']' : - case '?' : - case '=' : - return 0; - break; - - default : - /* Do nothing. */ - break; - } - p++; } From 25e5543c7f66c97871d9202cd15b9945de90faf1 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Fri, 23 Nov 2018 22:33:01 -0300 Subject: [PATCH 221/477] Allow empty arrays in JSON parser Issue #1576 --- apache2/msc_json.c | 58 ++++++++++++++- tests/regression/rule/15-json.t | 121 ++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 2 deletions(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 3a7a03d728..c30660325a 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -150,6 +150,60 @@ static int yajl_number(void *ctx, const char *value, size_t length) return json_add_argument(msr, value, length); } +static int yajl_start_array(void *ctx) { + modsec_rec *msr = (modsec_rec *) ctx; + + if (!msr->json->current_key && !msr->json->prefix) { + msr->json->prefix = apr_pstrdup(msr->mp, "array"); + msr->json->current_key = apr_pstrdup(msr->mp, "array"); + } + else if (msr->json->prefix) { + msr->json->prefix = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix, + msr->json->current_key); + } + else { + msr->json->prefix = apr_pstrdup(msr->mp, msr->json->current_key); + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "New JSON hash context (prefix '%s')", msr->json->prefix); + } + + + return 1; +} + + +static int yajl_end_array(void *ctx) { + modsec_rec *msr = (modsec_rec *) ctx; + unsigned char *separator = (unsigned char *) NULL; + + /** + * If we have no prefix, then this is the end of a top-level hash and + * we don't do anything + */ + if (msr->json->prefix == NULL) return 1; + + /** + * Current prefix might or not include a separator character; top-level + * hash keys do not have separators in the variable name + */ + separator = strrchr(msr->json->prefix, '.'); + + if (separator) { + msr->json->prefix = apr_pstrmemdup(msr->mp, msr->json->prefix, + separator - msr->json->prefix); + } + else { + /** + * TODO: Check if it is safe to do this kind of pointer tricks + */ + msr->json->prefix = (unsigned char *) NULL; + } + + return 1; +} + /** * Callback for a new hash, which indicates a new subtree, labeled as the current * argument name, is being created @@ -237,8 +291,8 @@ int json_init(modsec_rec *msr, char **error_msg) { yajl_start_map, yajl_map_key, yajl_end_map, - NULL /* yajl_start_array */, - NULL /* yajl_end_array */ + yajl_start_array, + yajl_end_array }; if (error_msg == NULL) return -1; diff --git a/tests/regression/rule/15-json.t b/tests/regression/rule/15-json.t index e75f89c154..181df9e076 100644 --- a/tests/regression/rule/15-json.t +++ b/tests/regression/rule/15-json.t @@ -35,5 +35,126 @@ ), ), ), +}, +{ + type => "rule", + comment => "json parser - issue #1576 - 1", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule ARGS "bar" "id:'200441',phase:3,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Pattern match "bar" at ARGS:foo.|ModSecurity: JSON support was not enabled/s, 1 ], + debug => [ qr/ARGS:foo|ARGS:mod|ARGS:ops.ops.ops|ARGS:ops.ops.ops|ARGS:ops.ops|ARGS:ops.ops|ARGS:ops.ops.eins.eins|ARGS:ops.ops.eins.eins|ARGS:whee/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + { + "foo":"bar", + "mod":"sec", + "ops":[ + [ + "um", + "um e meio" + ], + "dois", + "tres", + { + "eins":[ + "zwei", + "drei" + ] + } + ], + "whee":"lhebs" + } + ), + ), + ), +}, +{ + type => "rule", + comment => "json parser - issue #1576 - 2", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule ARGS "um" "id:'200441',phase:3,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Pattern match "um" at ARGS:array.array|ModSecurity: JSON support was not enabled/s, 1 ], + debug => [ qr/ARGS:array.array|ARGS:array.array/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + [ + "um", + "um e meio" + ] + ), + ), + ), +}, +{ + type => "rule", + comment => "json parser - issue #1576 - 3", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule ARGS "seis" "id:'200441',phase:3,log" + ), + match_log => { + error => [ qr/ModSecurity: Warning. Pattern match "seis" at ARGS:array.array.cinco.|ModSecurity: JSON support was not enabled/s, 1 ], + debug => [ qr/ARGS:array.array|ARGS:array.array|ARGS:array.array.tres|ARGS:array.array.cinco/, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + [ + "um", + "um e meio", + { + "tres": "quatro", + "cinco": "seis" + } + ] + ), + ), + ), } From 9b6d4b2bb9887e6647be585db1dfb03bd7114925 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 26 Nov 2018 10:48:49 -0300 Subject: [PATCH 222/477] CHANGES: Adds info about: #1576 and #1577 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 6805665acb..3ccf7cc314 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Include unanmed JSON values in unnamed ARGS + [Issue #1577, #1576 - @marcstern, @victorhora, @zimmerle] * Fix buffer size for utf8toUnicode transformation [Issue #1208 - @katef, @victorhora] * Fix sanitizing JSON request bodies in native audit log format From f15976f68f002520279856a48a5d96bf74dfa81c Mon Sep 17 00:00:00 2001 From: Allan Boll <allanbo@microsoft.com> Date: Mon, 20 Nov 2017 12:17:42 -0800 Subject: [PATCH 223/477] Allow 0 length JSON requests. 0 len XML and multipart already allowed. --- CHANGES | 2 ++ apache2/msc_reqbody.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 3ccf7cc314..6ccec1c233 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Allow 0 length JSON requests. + [Issue #1822 - @allanbomsft, @zimmerle, @victorhora, @marcstern] * Include unanmed JSON values in unnamed ARGS [Issue #1577, #1576 - @marcstern, @victorhora, @zimmerle] * Fix buffer size for utf8toUnicode transformation diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index 337343735a..e84c33a391 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -710,7 +710,7 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { } else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) { #ifdef WITH_YAJL - if (json_complete(msr, &my_error_msg) < 0) { + if (json_complete(msr, &my_error_msg) < 0 && msr->msc_reqbody_length > 0) { *error_msg = apr_psprintf(msr->mp, "JSON parser error: %s", my_error_msg); msr->msc_reqbody_error = 1; msr->msc_reqbody_error_msg = *error_msg; From 780f9ddf0f8488a6f2e5c082b3205c6e331bc537 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Fri, 30 Nov 2018 10:27:18 -0300 Subject: [PATCH 224/477] Update issue templates --- .../bug-report-for-version-2-x.md | 46 +++++++++++++++++++ ...eport.md => bug-report-for-version-3-x.md} | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/bug-report-for-version-2-x.md rename .github/ISSUE_TEMPLATE/{bug_report.md => bug-report-for-version-3-x.md} (97%) diff --git a/.github/ISSUE_TEMPLATE/bug-report-for-version-2-x.md b/.github/ISSUE_TEMPLATE/bug-report-for-version-2-x.md new file mode 100644 index 0000000000..b39db8633f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report-for-version-2-x.md @@ -0,0 +1,46 @@ +--- +name: Bug report for version 2.x +about: Create a report to help us improve + +--- + +**Describe the bug** + +A clear and concise description of what the bug is. + +**Logs and dumps** + +Output of: + 1. DebugLogs (level 9) + 2. AuditLogs + 3. Error logs + 4. If there is a crash, the core dump file. + +_Notice:_ Be carefully to not leak any confidential information. + +**To Reproduce** + +Steps to reproduce the behavior: + +A **curl** command line that mimics the original request and reproduces the problem. Or a ModSecurity v3 test case. + +[e.g: curl "modsec-full/ca/..\\..\\..\\..\\..\\..\\/\\etc/\\passwd" or [issue-394.json](https://github.com/SpiderLabs/ModSecurity/blob/v3/master/test/test-cases/regression/issue-394.json)] + + +**Expected behavior** + +A clear and concise description of what you expected to happen. + +**Server (please complete the following information):** + - ModSecurity version (and connector): [e.g. ModSecurity v3.0.1 with nginx-connector v1.0.0] + - WebServer: [e.g. nginx-1.15.5] + - OS (and distro): [e.g. Linux, archlinux] + + +**Rule Set (please complete the following information):** + - Running any public or commercial rule set? [e.g. SpiderLabs commercial rules] + - What is the version number? [e.g. 2018-08-11] + +**Additional context** + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug-report-for-version-3-x.md similarity index 97% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .github/ISSUE_TEMPLATE/bug-report-for-version-3-x.md index 5346d6b738..58874dfb42 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug-report-for-version-3-x.md @@ -1,5 +1,5 @@ --- -name: Bug report +name: Bug report for version 3.x about: Create a report to help us improve. If you don't know a specific detail or piece of information leave it blank, if necessary we will help you to figure out. From cc97550b71517f6f0967d5a39bdc82ef0bc1774a Mon Sep 17 00:00:00 2001 From: Victor Hora <vhora@trustwave.com> Date: Tue, 4 Dec 2018 11:44:40 -0500 Subject: [PATCH 225/477] Enable optimization for large stream input by default on IIS --- CHANGES | 2 ++ iis/Makefile.win | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/CHANGES b/CHANGES index 6ccec1c233..0c04a547e1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD MMM YYYY - 2.9.3 - To be released ------------------------------------ + * Enable optimization for large stream input by default on IIS + [Issue #1299 - @victorhora, @zimmerle] * Allow 0 length JSON requests. [Issue #1822 - @allanbomsft, @zimmerle, @victorhora, @marcstern] * Include unanmed JSON values in unnamed ARGS diff --git a/iis/Makefile.win b/iis/Makefile.win index 8c2cdbd7ee..d07f795ad9 100644 --- a/iis/Makefile.win +++ b/iis/Makefile.win @@ -10,12 +10,12 @@ LIBS = $(APACHE)\lib\libapr-1.lib \ $(APACHE)\lib\libaprutil-1.lib \ $(PCRE)\pcre.lib \ - $(CURL)\libcurl.lib \ + $(CURL)\libcurl.lib \ $(LIBXML2)\win32\bin.msvc\libxml2.lib \ "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" \ "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" "ws2_32.lib" \ "iphlpapi.lib" -# $(SSDEEP)\fuzzy.lib \ +# $(SSDEEP)\fuzzy.lib \ ########################################################################### ########################################################################### @@ -24,12 +24,12 @@ LINK = link.exe MT = mt -DEFS = /nologo /O2 /LD /W3 /wd4244 /wd4018 -DWITH_YAJL -DWIN32 -DWINNT -Dinline=APR_INLINE -DAP_DECLARE_STATIC -D_MBCS -D$(VERSION) +DEFS = /nologo /O2 /LD /W3 /wd4244 /wd4018 -DWITH_YAJL -DWIN32 -DWINNT -Dinline=APR_INLINE -DAP_DECLARE_STATIC -D_MBCS -D$(VERSION) DLL = ModSecurityIIS.dll INCLUDES = -I. -I.. \ - -I$(YAJL)\.. \ + -I$(YAJL)\.. \ -I$(PCRE)\include -I$(PCRE) \ -I$(LIBXML2)\include \ -I$(CURL)\include -I$(CURL) \ @@ -37,10 +37,10 @@ INCLUDES = -I. -I.. \ -I..\apache2 \ -I..\standalone -# Enables support for SecRemoteRules and external resources. -DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES - -# -I$(SSDEEP) \ +# Enables support for SecRemoteRules, external resources and enable optimization for large stream input by default on IIS. +DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES -DMSC_LARGE_STREAM_INPUT + +# -I$(SSDEEP) \ # Lua is optional !IF "$(LUA)" != "" LIBS = $(LIBS) $(LUA)\lua5.1.lib @@ -54,16 +54,16 @@ LIBS = $(LIBS) $(YAJL)\lib\yajl.lib DEFS=$(DEFS) -DWITH_YAJL INCLUDES = $(INCLUDES) -I$(YAJL)\include -I$(YAJL) \ !ENDIF - + # ssdeep is optional # !IF "$(SSDEEP)" != "" # LIBS = $(LIBS) $(SSDEEP)\fuzzy.lib # DEFS=$(DEFS) -DWITH_SSDEEP # INCLUDES = $(INCLUDES) -I$(SSDEEP)\include -I$(SSDEEP) \ # !ENDIF - - - + + + CFLAGS= -MD /Zi $(INCLUDES) $(DEFS) @@ -75,10 +75,10 @@ OBJS1 = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \ msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \ msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_unicode.obj acmp.obj msc_lua.obj \ msc_release.obj msc_crypt.obj msc_tree.obj \ - msc_status_engine.obj \ + msc_status_engine.obj \ msc_json.obj \ - msc_remote_rules.obj - + msc_remote_rules.obj + OBJS2 = api.obj buckets.obj config.obj filters.obj hooks.obj regex.obj server.obj OBJS3 = main.obj moduleconfig.obj mymodule.obj OBJS4 = libinjection_html5.obj \ From 2c400951a59ca770c370f2f02c85e9c808c0491d Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 3 Dec 2018 09:15:49 -0300 Subject: [PATCH 226/477] Version 2.9.3 Increasing version to 2.9.3 --- CHANGES | 4 ++-- apache2/msc_release.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 0c04a547e1..9fbd3306e2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -DD MMM YYYY - 2.9.3 - To be released ------------------------------------- +05 Dec 2018 - 2.9.3 +------------------- * Enable optimization for large stream input by default on IIS [Issue #1299 - @victorhora, @zimmerle] diff --git a/apache2/msc_release.h b/apache2/msc_release.h index dcfde11c89..49d928702c 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "2" +#define MODSEC_VERSION_MAINT "3" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From cb33bb4faafc89e28611c23132801cc09897770f Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 10 Dec 2018 15:16:04 -0300 Subject: [PATCH 227/477] CHANGES: After 2.9.3 --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 9fbd3306e2..522fecf716 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +DD mmm YYYY - 2.9.x (to be released) +------------------------------------ + + + 05 Dec 2018 - 2.9.3 ------------------- From 0dcbb8b08796a08fc043fa53134e85fc9d207cba Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sun, 9 Dec 2018 20:26:40 +0000 Subject: [PATCH 228/477] Fix inet addr handling on 64 bit big endian systems Back port from v3. @zimmerle. --- apache2/msc_tree.c | 17 +++++++---------- apache2/msc_util.c | 8 ++++---- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index 07c76a0060..232a363e2c 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -832,7 +832,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { switch(type) { case IPV4_TREE: - memset(&addr4, 0, sizeof(addr4)); + memset(&(addr4.s_addr), 0, sizeof(addr4.s_addr)); memset(ip_strv4, 0x0, NETMASK_32); strncpy(ip_strv4, buffer, sizeof(ip_strv4)); @@ -859,20 +859,16 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { ip_strv4[pos] = '\0'; } - ret = inet_pton(AF_INET, ip_strv4, &addr4); + ret = inet_pton(AF_INET, ip_strv4, &(addr4.s_addr)); if (ret <= 0) { return NULL; } - - ip = addr4.s_addr; - tree->count++; - - return CPTAddElement((unsigned char *)&ip, NETMASK_32, tree, netmask_v4); + return CPTAddElement((unsigned char *)&(addr4.s_addr), NETMASK_32, tree, netmask_v4); case IPV6_TREE: - memset(&addr6, 0, sizeof(addr6)); + memset(&(addr6.s6_addr), 0, sizeof(addr6.s6_addr)); memset(ip_strv6, 0x0, NETMASK_128); strncpy(ip_strv6, buffer, sizeof(ip_strv6)); @@ -899,7 +895,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { ip_strv6[pos] = '\0'; } - ret = inet_pton(AF_INET6, ip_strv6, &addr6); + ret = inet_pton(AF_INET6, ip_strv6, &(addr6.s6_addr)); if (ret <= 0) { @@ -908,10 +904,11 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { tree->count++; - return CPTAddElement((unsigned char *)&addr6.s6_addr, NETMASK_128, tree, netmask_v6); + return CPTAddElement((unsigned char *)&(addr6.s6_addr), NETMASK_128, tree, netmask_v6); default: return NULL; } return NULL; } + diff --git a/apache2/msc_util.c b/apache2/msc_util.c index d687ac4de3..501c24e509 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2712,26 +2712,26 @@ int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, } if (strchr(value, ':') == NULL) { - if (inet_pton(AF_INET, value, &in) <= 0) { + if (inet_pton(AF_INET, value, &(in.s_addr)) <= 0) { *error_msg = apr_psprintf(mp, "IPmatch: bad IPv4 " \ "specification \"%s\".", value); return -1; } - if (CPTIpMatch(msr, (unsigned char *)&in.s_addr, rtree->ipv4_tree, + if (CPTIpMatch(msr, (unsigned char *)&(in.s_addr), rtree->ipv4_tree, IPV4_TREE) != NULL) { return 1; } } #if APR_HAVE_IPV6 else { - if (inet_pton(AF_INET6, value, &in6) <= 0) { + if (inet_pton(AF_INET6, value, &(in6.s6_addr)) <= 0) { *error_msg = apr_psprintf(mp, "IPmatch: bad IPv6 " \ "specification \"%s\".", value); return -1; } - if (CPTIpMatch(msr, (unsigned char *)&in6.s6_addr, rtree->ipv6_tree, + if (CPTIpMatch(msr, (unsigned char *)&(in6.s6_addr), rtree->ipv6_tree, IPV6_TREE) != NULL) { return 1; } From f5dbaae4fbb88f29e919863d2029bb5de4428ac9 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 10 Dec 2018 15:41:28 -0300 Subject: [PATCH 229/477] CHANGES: Adds info on #1980 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 522fecf716..c92499527d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Fix inet addr handling on 64 bit big endian systems + [Issue #1980 - @zimmerle, @airween] 05 Dec 2018 - 2.9.3 From b90fa2d063400768b959e24f2e15376565bcf49c Mon Sep 17 00:00:00 2001 From: "Martin.Blapp" <martin.blapp@nashire.com> Date: Thu, 15 Nov 2018 12:41:57 +0100 Subject: [PATCH 230/477] Use tempfiles for apr_global_mutex_create() to fix segfaults with Apache 2.2. Call modsecurity_init() for the first invocation too. --- apache2/modsecurity.c | 9 ++++++--- apache2/modsecurity.h | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index dcdb48590c..09b5caa21f 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -133,7 +133,8 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { curl_global_init(CURL_GLOBAL_ALL); #endif /* Serial audit log mutext */ - rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp); + tmpnam(auditlog_lock_name); + rc = apr_global_mutex_create(&msce->auditlog_lock, auditlog_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { //ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock"); //return HTTP_INTERNAL_SERVER_ERROR; @@ -154,7 +155,8 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { } #endif /* SET_MUTEX_PERMS */ - rc = apr_global_mutex_create(&msce->geo_lock, NULL, APR_LOCK_DEFAULT, mp); + tmpnam(geo_lock_name); + rc = apr_global_mutex_create(&msce->geo_lock, geo_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { return -1; } @@ -171,7 +173,8 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { #endif /* SET_MUTEX_PERMS */ #ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_create(&msce->dbm_lock, NULL, APR_LOCK_DEFAULT, mp); + tmpnam(dbm_lock_name); + rc = apr_global_mutex_create(&msce->dbm_lock, dbm_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { return -1; } diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index f24bc756a4..11313b9b48 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -133,6 +133,12 @@ typedef struct msc_parm msc_parm; #define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!" +static char auditlog_lock_name[L_tmpnam]; +static char geo_lock_name[L_tmpnam]; +#ifdef GLOBAL_COLLECTION_LOCK +static char dbm_lock_name[L_tmpnam]; +#endif + extern DSOLOCAL char *new_server_signature; extern DSOLOCAL char *real_server_signature; extern DSOLOCAL char *chroot_dir; From c08d3edb131e5218c96bf7bd83b847d1e9c0bcd5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 10 Dec 2018 16:55:48 -0300 Subject: [PATCH 231/477] CHANGES: Adds info on #1957 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index c92499527d..8b09bb0fc7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Fix for apr_global_mutex_create() crashes with mod_security + [Issue #1957 - @blappm] * Fix inet addr handling on 64 bit big endian systems [Issue #1980 - @zimmerle, @airween] From 52532a1bce0b705c0aa4365fecf727b836d37f00 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Fri, 14 Dec 2018 23:53:05 -0300 Subject: [PATCH 232/477] Fix curl callback function --- apache2/msc_util.c | 12 +++--------- apache2/msc_util.h | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 501c24e509..7a95e078dc 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2780,8 +2780,8 @@ int ip_tree_from_param(apr_pool_t *mp, } #ifdef WITH_CURL -size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size, - size_t nmemb, void *userp, char **error_msg) +size_t msc_curl_write_memory_cb(void *contents, size_t size, + size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct msc_curl_memory_buffer_t *mem = (struct msc_curl_memory_buffer_t *)userp; @@ -2790,19 +2790,13 @@ size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size, { mem->memory = malloc(realsize + 1); if (mem->memory == NULL) { - *error_msg = apr_psprintf(mp, "Unable to allocate buffer for mem->memory"); return 0; } memset(mem->memory, '\0', sizeof(realsize + 1)); } else { - void *tmp; - tmp = mem->memory; - tmp = realloc(mem->memory, mem->size + realsize + 1); - if (tmp != NULL) { - mem->memory = tmp; - } + mem->memory = realloc(mem->memory, mem->size + realsize + 1); memset(mem->memory + mem->size, '\0', sizeof(realsize + 1)); } diff --git a/apache2/msc_util.h b/apache2/msc_util.h index d69b62ac27..f7e1280f21 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -166,8 +166,8 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, int read_line(char *buff, int size, FILE *fp); -size_t msc_curl_write_memory_cb(apr_pool_t *mp, void *contents, size_t size, - size_t nmemb, void *userp, char **error_msg); +size_t msc_curl_write_memory_cb(void *contents, size_t size, + size_t nmemb, void *userp); struct msc_curl_memory_buffer_t { From 46c6cb2759327d94e619454dbe61f1e7639dd607 Mon Sep 17 00:00:00 2001 From: Armin Abfalterer <armin.abfalterer@united-security-providers.ch> Date: Tue, 12 Mar 2019 16:29:43 +0100 Subject: [PATCH 233/477] use uid if user name is not available --- apache2/msc_logging.c | 10 +++++++--- apache2/persist_dbm.c | 29 +++++++++++++++++++---------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index d50f709e97..d1a867c35d 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -234,16 +234,20 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations * It also changes the return statement. */ - char *username; + char *userinfo; + apr_status_t rc; apr_uid_t uid; apr_gid_t gid; apr_uid_current(&uid, &gid, mp); - apr_uid_name_get(&username, uid, mp); + rc = apr_uid_name_get(&userinfo, uid, mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(mp, "%u", uid); + } apr_time_exp_lt(&t, apr_time_now()); apr_strftime(tstr, &len, 299, "/%Y%m%d/%Y%m%d-%H%M/%Y%m%d-%H%M%S", &t); - return apr_psprintf(mp, "/%s%s-%s", username, tstr, uniqueid); + return apr_psprintf(mp, "/%s%s-%s", userinfo, tstr, uniqueid); } /** diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index efbbf6ebd9..e4f8036f6f 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -104,11 +104,14 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec /** * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations */ - char *username; + char *userinfo; apr_uid_t uid; apr_gid_t gid; apr_uid_current(&uid, &gid, msr->mp); - apr_uid_name_get(&username, uid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } if (msr->txcfg->data_dir == NULL) { msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " @@ -117,7 +120,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec goto cleanup; } - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), @@ -385,11 +388,14 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { /** * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations */ - char *username; + char *userinfo; apr_uid_t uid; apr_gid_t gid; apr_uid_current(&uid, &gid, msr->mp); - apr_uid_name_get(&username, uid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } var_name = (msc_string *)apr_table_get(col, "__name"); if (var_name == NULL) { @@ -409,7 +415,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { } // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", var_name->value, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), @@ -675,11 +681,14 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { /** * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations */ - char *username; + char *userinfo; apr_uid_t uid; apr_gid_t gid; apr_uid_current(&uid, &gid, msr->mp); - apr_uid_name_get(&username, uid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } if (msr->txcfg->data_dir == NULL) { /* The user has been warned about this problem enough times already by now. @@ -690,9 +699,9 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", msr->txcfg->webappid, "_", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", username, "-", col_name, NULL); + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), From 774ff40c96be9359c6bbfcdd5f29c906b0a5bd0e Mon Sep 17 00:00:00 2001 From: Nao YONASHIRO <yonashiro@r.recruit.co.jp> Date: Fri, 17 May 2019 15:19:09 +0900 Subject: [PATCH 234/477] fix: care non-null terminated chunk data --- apache2/msc_logging.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index d50f709e97..61d1a54b7d 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -992,6 +992,7 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Write the sanitized chunk to the log * and advance to the next chunk. */ + chunk->data[chunk->length] = 0; yajl_string(g, chunk->data); chunk_offset += chunk->length; } From 0d663616f7c31a684684b617231fc74c7887ed9b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 27 May 2019 10:33:56 -0300 Subject: [PATCH 235/477] CHANGES: Adds info on --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 8b09bb0fc7..0dcd6c5429 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * fix: care non-null terminated chunk data + [Issue #2097 - @orisano] * Fix for apr_global_mutex_create() crashes with mod_security [Issue #1957 - @blappm] * Fix inet addr handling on 64 bit big endian systems From 32e185c2ca4d12743f1fc2f8b6e0f1833f84aa17 Mon Sep 17 00:00:00 2001 From: Rainer Jung <rainer.jung@kippdata.de> Date: Wed, 15 May 2019 01:31:43 +0200 Subject: [PATCH 236/477] When the input filter finishes, check whether we returned data during the last read and if not, delegate to the remaining filter chain. Without that, ProcessPartial for the request body breaks forwarding of uploaded files using mod_proxy_ajp and mod_wl. See issue #2091. --- apache2/apache2_io.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 66b865f37e..f6c785e8d2 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -36,6 +36,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, msc_data_chunk *chunk = NULL; apr_bucket *bucket; apr_status_t rc; + int no_data = 1; char *my_error_msg = NULL; if (msr == NULL) { @@ -110,6 +111,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, if (bucket == NULL) return APR_EGENERAL; APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + no_data = 0; if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); @@ -130,6 +132,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, if (bucket == NULL) return APR_EGENERAL; APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + no_data = 0; if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length); @@ -145,6 +148,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); if (bucket == NULL) return APR_EGENERAL; APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + no_data = 0; if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Sent EOS."); @@ -158,6 +162,10 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Input forwarding complete."); } + + if (no_data) { + return ap_get_brigade(f->next, bb_out, mode, block, nbytes); + } } return APR_SUCCESS; From ca8e2db5a70de9b059ffb58eb468224d3d55b7e8 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 27 May 2019 14:34:08 -0300 Subject: [PATCH 237/477] CHANGES: Adds info on: 2092 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 0dcd6c5429..d4142e9707 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * When the input filter finishes, check whether we returned data + [Issue #2091, #2092 - @rainerjung] * fix: care non-null terminated chunk data [Issue #2097 - @orisano] * Fix for apr_global_mutex_create() crashes with mod_security From f7e4d01b010c218057e4cac37c62cc13528d4739 Mon Sep 17 00:00:00 2001 From: emphazer <Christoph.Hansen83@gmail.com> Date: Wed, 26 Jun 2019 09:17:46 +0200 Subject: [PATCH 238/477] added missing Geo Countries --- apache2/msc_geo.c | 12 ++++++++---- apache2/msc_geo.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index 134f40fa21..a849b4f9e2 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -43,7 +43,8 @@ static const char geo_country_code[GEO_COUNTRY_LAST + 1][4] = { "TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW", "TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE", "VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA", - "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE" + "ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE", + "BL","BQ","CW","MF","SS","SX" }; static const char geo_country_code3[GEO_COUNTRY_LAST + 1][4] = { @@ -72,7 +73,8 @@ static const char geo_country_code3[GEO_COUNTRY_LAST + 1][4] = { "TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN", "TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN", "VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF", - "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY" + "ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY", + "BLM","BES","CUW","MAF","SSD","SXM" }; static const char *const geo_country_name[GEO_COUNTRY_LAST + 1] = { @@ -101,7 +103,8 @@ static const char *const geo_country_name[GEO_COUNTRY_LAST + 1] = { "Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan", "Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela", "Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa", - "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey" + "Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey", + "Saint Barthélemy","Bonaire, Sint Eustatius and Saba","Curaçao","Saint Martin (French part)","South Sudan","Sint Maarten (Dutch part)" }; static const char geo_country_continent[GEO_COUNTRY_LAST + 1][4] = { @@ -130,7 +133,8 @@ static const char geo_country_continent[GEO_COUNTRY_LAST + 1][4] = { "AS","OC","AS","AF","OC","AS","AS","SA","OC","AS", "AF","EU","AF","OC","NA","SA","AS","EU","SA","SA", "SA","SA","AS","OC","OC","OC","AS","AF","EU","AF", - "AF","EU","AF","--","--","--","EU","EU","EU","EU" + "AF","EU","AF","--","--","--","EU","EU","EU","EU", + "--","--","--","--","AF","--" }; typedef enum { diff --git a/apache2/msc_geo.h b/apache2/msc_geo.h index 1293614608..afc8e72c74 100644 --- a/apache2/msc_geo.h +++ b/apache2/msc_geo.h @@ -25,7 +25,7 @@ #define GEO_COUNTRY_DATABASE 1 #define GEO_CITY_DATABASE_0 6 #define GEO_CITY_DATABASE_1 2 -#define GEO_COUNTRY_LAST 250 +#define GEO_COUNTRY_LAST 256 #define GEO_SEGMENT_RECORD_LENGTH 3 #define GEO_STATE_BEGIN_REV0 16700000 #define GEO_STATE_BEGIN_REV1 16000000 From 28b4be670fc7d02bb6388034032d0061b56c8b64 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 26 Jun 2019 13:03:35 -0300 Subject: [PATCH 239/477] CHANGES: Adds info on: #2123, #2124 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index d4142e9707..740a56dbf7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Added missing Geo Countries + [Issue #2123, #2124 - @emphazer] * When the input filter finishes, check whether we returned data [Issue #2091, #2092 - @rainerjung] * fix: care non-null terminated chunk data From 176276a931a6d61db38b908237c9aad1cea0d6ad Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Wed, 10 Jul 2019 14:41:32 -0300 Subject: [PATCH 240/477] Fix the order of error_msg validation Reported by @marcstern at #2128 --- CHANGES | 2 ++ apache2/re_operators.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 740a56dbf7..739ed2b51a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Fix the order of error_msg validation + [Issue #2128 - @marcstern, @zimmerle] * Added missing Geo Countries [Issue #2123, #2124 - @emphazer] * When the input filter finishes, check whether we returned data diff --git a/apache2/re_operators.c b/apache2/re_operators.c index e0ef2f201d..b639ae4f6e 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1993,6 +1993,9 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va unsigned int target_length = 0; unsigned int i, i_max; + if (error_msg == NULL) return -1; + *error_msg = NULL; + str->value = (char *)rule->op_param; if (str->value == NULL) { @@ -2002,9 +2005,6 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; - *error_msg = NULL; - expand_macros(msr, str, rule, msr->mp); match = (const char *)str->value; From 12cefbd70f2aab802e1bff53c50786f3b8b89359 Mon Sep 17 00:00:00 2001 From: studersi <mail@studer.si> Date: Wed, 23 Oct 2019 15:01:10 +0200 Subject: [PATCH 241/477] Adds a sanity check before use ctl:ruleRemove(TargetById|TargetByMsg) This commit closes the issue #2033. --- CHANGES | 2 ++ apache2/re_actions.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 739ed2b51a..2daedef723 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Adds a sanity check before use ctl:ruleRemoveTargetById and ctl:ruleRemoveTargetByMsg. + [Issue #2033 - @studersi] * Fix the order of error_msg validation [Issue #2128 - @marcstern, @zimmerle] * Added missing Geo Countries diff --git a/apache2/re_actions.c b/apache2/re_actions.c index f81ddc87c7..02ec07d222 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1235,6 +1235,11 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Ctl: ruleRemoveTargetById id=%s targets=%s", p1, p2); } + if (p2 == NULL) { + msr_log(msr, 1, "ModSecurity: Missing target for id \"%s\"", p1); + return -1; + } + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_ID; re->param = (const char *)apr_pstrdup(msr->mp, p1); @@ -1253,10 +1258,10 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Ctl: ruleRemoveTargetByTag tag=%s targets=%s", p1, p2); } - if (p2 == NULL) { + if (p2 == NULL) { msr_log(msr, 1, "ModSecurity: Missing target for tag \"%s\"", p1); - return -1; - } + return -1; + } re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_TAG; @@ -1281,6 +1286,10 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Ctl: ruleRemoveTargetByMsg msg=%s targets=%s", p1, p2); } + if (p2 == NULL) { + msr_log(msr, 1, "ModSecurity: Missing target for msg \"%s\"", p1); + return -1; + } re = apr_pcalloc(msr->mp, sizeof(rule_exception)); re->type = RULE_EXCEPTION_REMOVE_MSG; From 6a5ec1ff7bd5a4a653da417f9a49a50cf5b2429d Mon Sep 17 00:00:00 2001 From: Vladimir Krivopalov <vlkrivop@microsoft.com> Date: Mon, 13 Jan 2020 16:36:09 -0800 Subject: [PATCH 242/477] Properly cleanup XML parser contexts upon completion It is currently possible that the XML parsing context is not properly cleaned up if a parsed XML document is malformed. This fix makes sure that the context is taken care of. Signed-off-by: Vladimir Krivopalov <vlkrivop@microsoft.com> --- apache2/msc_xml.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index a31decb5e1..9cc4da65b8 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -137,6 +137,13 @@ int xml_complete(modsec_rec *msr, char **error_msg) { * Frees the resources used for XML parsing. */ apr_status_t xml_cleanup(modsec_rec *msr) { + if (msr->xml->parsing_ctx != NULL) { + if (msr->xml->parsing_ctx->myDoc) { + xmlFreeDoc(msr->xml->parsing_ctx->myDoc); + } + xmlFreeParserCtxt(msr->xml->parsing_ctx); + msr->xml->parsing_ctx = NULL; + } if (msr->xml->doc != NULL) { xmlFreeDoc(msr->xml->doc); msr->xml->doc = NULL; From e419b50fe7051245adc7d5d230eb2dd951343df8 Mon Sep 17 00:00:00 2001 From: John Lightsey <john@nixnuts.net> Date: Tue, 19 Mar 2019 13:10:53 -0500 Subject: [PATCH 243/477] Store temporaries in the request pool for regexes compiled per-request. The code for testing regexes with embedded Apache variables (rule->re_precomp == 1) during request processing was utilizing the global engine pool for the storage of temporary values. This approach is not threadsafe, retains the temporary variables longer than they are usable, and causes corruption of the global pool's "cleanups" linked-lists when Apache is configured with a threaded MPM. --- apache2/re_operators.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b639ae4f6e..6229145848 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -784,10 +784,10 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v msr_log(msr, 6, "Escaping pattern [%s]",pattern); } - regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, + regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { - *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", + *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); return 0; } @@ -797,7 +797,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v if (msr->txcfg->debuglog_level >= 4) { rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); if ((rc != 0) || (jit != 1)) { - *error_msg = apr_psprintf(rule->ruleset->mp, + *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " "Execution error - " "Does not support JIT (%d)", @@ -1018,9 +1018,9 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msr_log(msr, 6, "Escaping pattern [%s]",pattern); } - regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { - *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", + *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); return 0; } @@ -1030,7 +1030,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c if (msr->txcfg->debuglog_level >= 4) { rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); if ((rc != 0) || (jit != 1)) { - *error_msg = apr_psprintf(rule->ruleset->mp, + *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " "Execution error - " "Does not support JIT (%d)", From 039b35029c9241dc3fe8dad1bb060abd52eef6af Mon Sep 17 00:00:00 2001 From: John Lightsey <john@nixnuts.net> Date: Tue, 19 Mar 2019 13:40:50 -0500 Subject: [PATCH 244/477] Fix other usage of the global pool for request temporaries in re_operators.c --- apache2/re_operators.c | 54 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 6229145848..7eb1bf2649 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1684,7 +1684,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var return 0; } - data = apr_pcalloc(rule->ruleset->mp, var->value_len+1); + data = apr_pcalloc(msr->mp, var->value_len+1); if(data == NULL) { *error_msg = "Internal Error: cannot allocate memory for data."; @@ -1699,18 +1699,18 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var { for(i = 0; i < rv; ++i) { - match = apr_psprintf(rule->ruleset->mp, "%.*s", ovector[2*i+1] - ovector[2*i], data + ovector[2*i]); + match = apr_psprintf(msr->mp, "%.*s", ovector[2*i+1] - ovector[2*i], data + ovector[2*i]); if (match == NULL) { *error_msg = "Internal Error: cannot allocate memory for match."; return -1; } - match = remove_escape(rule->ruleset->mp, match, strlen(match)); + match = remove_escape(msr->mp, match, strlen(match)); - match = gsb_replace_tpath(rule->ruleset->mp, match, strlen(match)); + match = gsb_replace_tpath(msr->mp, match, strlen(match)); - match = gsb_reduce_char(rule->ruleset->mp, match); + match = gsb_reduce_char(msr->mp, match); match_length = strlen(match); @@ -1732,7 +1732,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var log_escape_nq(msr->mp, match)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1744,7 +1744,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var /* append / in the end of full url */ if ((match[match_length -1] != '/') && (strchr(match,'?') == NULL)) { - canon = apr_psprintf(rule->ruleset->mp, "%s/", match); + canon = apr_psprintf(msr->mp, "%s/", match); if (canon != NULL) { canon_length = strlen(canon); @@ -1757,7 +1757,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1770,7 +1770,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var /* Parsing full url */ - domain = apr_pstrdup(rule->ruleset->mp, match); + domain = apr_pstrdup(msr->mp, match); domain_len = strlen(domain); @@ -1785,7 +1785,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var dot = strchr(domain,'.'); if(dot != NULL) { - canon = apr_pstrdup(rule->ruleset->mp, domain); + canon = apr_pstrdup(msr->mp, domain); ret = verify_gsb(gsb, msr, canon, strlen(canon)); @@ -1796,7 +1796,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1818,7 +1818,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var log_escape_nq(msr->mp, base)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1829,13 +1829,13 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var } - url = apr_palloc(rule->ruleset->mp, strlen(canon)); + url = apr_palloc(msr->mp, strlen(canon)); count_slash = 0; while(*canon != '\0') { switch (*canon) { case '/': - ptr = apr_psprintf(rule->ruleset->mp,"%s/",url); + ptr = apr_psprintf(msr->mp,"%s/",url); ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); if(ret > 0) { set_match_to_tx(msr, capture, ptr, 0); @@ -1844,7 +1844,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var log_escape_nq(msr->mp, ptr)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1871,7 +1871,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var } - str = apr_pstrdup(rule->ruleset->mp, match); + str = apr_pstrdup(msr->mp, match); while (*str != '\0') { @@ -1896,7 +1896,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var dot = strchr(domain,'.'); if(dot != NULL) { - canon = apr_pstrdup(rule->ruleset->mp, domain); + canon = apr_pstrdup(msr->mp, domain); ret = verify_gsb(gsb, msr, canon, strlen(canon)); @@ -1906,7 +1906,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1926,7 +1926,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", log_escape_nq(msr->mp, base)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -1936,13 +1936,13 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var } - url = apr_palloc(rule->ruleset->mp, strlen(canon)); + url = apr_palloc(msr->mp, strlen(canon)); count_slash = 0; while(*canon != '\0') { switch (*canon) { case '/': - ptr = apr_psprintf(rule->ruleset->mp,"%s/",url); + ptr = apr_psprintf(msr->mp,"%s/",url); ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); if(ret > 0) { set_match_to_tx(msr, capture, ptr, 0); @@ -1950,7 +1950,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", log_escape_nq(msr->mp, ptr)); } - str = apr_pstrdup(rule->ruleset->mp,match); + str = apr_pstrdup(msr->mp,match); base = apr_strtok(str,"/",&savedptr); if(base != NULL) @@ -2781,7 +2781,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * if (msr->txcfg->debuglog_level >= 4) { rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); if ((rc != 0) || (jit != 1)) { - *error_msg = apr_psprintf(rule->ruleset->mp, + *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " "Execution error - " "Does not support JIT (%d)", @@ -3092,7 +3092,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var if (msr->txcfg->debuglog_level >= 4) { rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); if ((rc != 0) || (jit != 1)) { - *error_msg = apr_psprintf(rule->ruleset->mp, + *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " "Execution error - " "Does not support JIT (%d)", @@ -3386,7 +3386,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var if (msr->txcfg->debuglog_level >= 4) { rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); if ((rc != 0) || (jit != 1)) { - *error_msg = apr_psprintf(rule->ruleset->mp, + *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " "Execution error - " "Does not support JIT (%d)", @@ -3967,7 +3967,7 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, #ifdef WITH_SSDEEP if (fuzzy_hash_buf(var->value, var->value_len, result)) { - *error_msg = apr_psprintf(rule->ruleset->mp, "Problems generating " \ + *error_msg = apr_psprintf(msr->mp, "Problems generating " \ "fuzzy hash."); return -1; @@ -3987,7 +3987,7 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, chunk = chunk->next; } #else - *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ + *error_msg = apr_psprintf(msr->mp, "ModSecurity was not " \ "compiled with ssdeep support."); return -1; From 40b98970c4a887a3969eb8f4e5c4dde0549c5608 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Thu, 14 Jan 2021 14:27:14 -0300 Subject: [PATCH 245/477] CHANGES: Adds info on: #890, #2049 --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 2daedef723..dd1e3148a3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Store temporaries in the request pool for regexes compiled per-request. + [Issue #890, #2049 - @lightsey] + * Fix other usage of the global pool for request temporaries in re_operators.c + [Issue #890, #2049 - @lightsey] * Adds a sanity check before use ctl:ruleRemoveTargetById and ctl:ruleRemoveTargetByMsg. [Issue #2033 - @studersi] * Fix the order of error_msg validation From f80114a906e65c55153016c242c3ab58148284e3 Mon Sep 17 00:00:00 2001 From: Rainer Jung <rainer.jung@kippdata.de> Date: Wed, 15 May 2019 01:50:20 +0200 Subject: [PATCH 246/477] Add microsec timestamp resolution to the formatted log timestamp. --- apache2/msc_util.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 7a95e078dc..2fdfd57c32 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -1129,10 +1129,12 @@ char *current_logtime(apr_pool_t *mp) { char tstr[100]; apr_size_t len; - apr_time_exp_lt(&t, apr_time_now()); + apr_time_t now = apr_time_now(); + apr_time_exp_lt(&t, now); - apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S ", &t); - apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%c%.2d%.2d", + apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S.", &t); + apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%06ld %c%.2d%.2d", + ((long)now) % 1000000L, t.tm_gmtoff < 0 ? '-' : '+', t.tm_gmtoff / (60 * 60), (t.tm_gmtoff / 60) % 60); return apr_pstrdup(mp, tstr); From ba8119984a724328e8636d71ccc6883b9b0c5c2b Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Fri, 15 Jan 2021 15:15:11 -0300 Subject: [PATCH 247/477] CHANGES: Adds info on: #2095 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index dd1e3148a3..afcbf9c2b0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------------------------ + * Add microsec timestamp resolution to the formatted log timestamp + [Issue #2095 - @rainerjung] * Store temporaries in the request pool for regexes compiled per-request. [Issue #890, #2049 - @lightsey] * Fix other usage of the global pool for request temporaries in re_operators.c From 29fd4a2856f8eb7053d53012173fa52ef0708fa1 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <felipe@zimmerle.org> Date: Wed, 17 Mar 2021 12:45:17 -0300 Subject: [PATCH 248/477] Update README.md --- README.md | 55 ++----------------------------------------------------- 1 file changed, 2 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index a40c07e8a0..00c8cd3145 100644 --- a/README.md +++ b/README.md @@ -14,57 +14,6 @@ If any of the files related to licensing are missing or if you have any other qu Please refer to: [the documentation folder](https://github.com/SpiderLabs/ModSecurity/tree/v2/master/doc) for the reference manual. -## OWASP ModSecurity Core Rule Set (CRS) +## Sponsor Note -Project Site: https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project - -Download: https://github.com/SpiderLabs/owasp-modsecurity-crs - -ModSecurityâ„¢ is a web application firewall engine that provides very little protection on its own. In order to become useful, ModSecurityâ„¢ must be configured with rules. In order to enable users to take full advantage of ModSecurityâ„¢ out of the box, Trustwave's SpiderLabs is providing a free certified rule set for ModSecurityâ„¢ 2.x. - -Unlike intrusion detection and prevention systems, which rely on signatures specific to known vulnerabilities, the Core Rules provide generic protection from unknown vulnerabilities often found in web applications, which are in most cases custom coded. The Core Rules are heavily commented to allow it to be used as a step-by-step deployment guide for ModSecurityâ„¢. - -### Core Rules Content - -In order to provide generic web applications protection, the Core Rules use the following techniques: - -* **HTTP Protection** - detecting violations of the HTTP protocol and a locally defined usage policy. -* **Real-time Blacklist Lookups** - utilizes 3rd Party IP Reputation -* **Web-based Malware Detection** - identifies malicious web content by check against the Google Safe Browsing API. -* **HTTP Denial of Service Protections** - defense against HTTP Flooding and Slow HTTP DoS Attacks. -* **Common Web Attacks Protection** - detecting common web application security attack. -* **Automation Detection** - Detecting bots, crawlers, scanners and other surface malicious activity. -* **Integration with AV Scanning for File Uploads** - detects malicious files uploaded through the web application. -* **Tracking Sensitive Data** - Tracks Credit Card usage and blocks leakages. -* **Trojan Protection** - Detecting access to Trojans horses. -* **Identification of Application Defects** - alerts on application misconfigurations. -* **Error Detection and Hiding** - Disguising error messages sent by the server. - -## ModSecurity Rules from Trustwave SpiderLabs - -Project Site: https://www.trustwave.com/modsecurity-rules-support.php - -Download: https://ssl.trustwave.com/web-application-firewall - -Trustwave now provides a commercial certified rule set for ModSecurity 2.x that protects against known attacks that target vulnerabilities in public software and are based on intelligence gathered from real-world investigations, honeypot data and research. - -1. More than 16,000 specific rules, broken out into the following attack categories: - - * SQL injection - * Cross-site Scripting (XSS) - * Local File Include - * Remote File Include - -2. User option for application specific rules, covering the same vulnerability classes for applications such as: - - * WordPress - * cPanel - * osCommerce - * Joomla - * For a complete listing of application coverage, please refer to this link (which is updated daily): https://modsecurity.org/application_coverage.html - -3. Complements and integrates with the OWASP Core Rule Set - -4. IP Reputation capabilities which provide protection against malicious clients identified by the Trustwave SpiderLabs Distributed Web Honeypots - -5. Malware Detection capabilities which prevent your web site from distributing malicious code to clients. +ModSecurity is sponsored by Trustwave. Trustwave offers a range of commercial services related to ModSecurity, including a set of Rules, consultancy and customization of ModSecurity. Contact the Trustwave sales department for more information - sales@trustwave.com From 47a27fd3b766aad1090359ba5ffcf087fee8ecb6 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Mon, 14 Jun 2021 19:09:06 -0300 Subject: [PATCH 249/477] iis: Having build scripts up2date --- iis/build_dependencies.bat | 18 +- iis/build_msi.bat | 8 +- iis/dependencies/build_curl.bat | 7 +- iis/installer.wxs | 304 +++++++++++++++++++++----------- iis/wix/modsecurity_iis.conf | 2 - 5 files changed, 214 insertions(+), 125 deletions(-) diff --git a/iis/build_dependencies.bat b/iis/build_dependencies.bat index 61cffb6352..0908d51e37 100644 --- a/iis/build_dependencies.bat +++ b/iis/build_dependencies.bat @@ -10,15 +10,15 @@ @set CMAKE=cmake-3.12.4-win32-x86.zip @set PCRE=pcre-8.41.zip @set ZLIB=zlib-1.2.11.tar.gz -@set LIBXML2=libxml2-2.9.8.tar.gz -@set LUA=lua-5.3.5.tar.gz -@set CURL=curl-7.62.0.zip -@set APACHE_SRC=httpd-2.4.37.tar.gz -@set APACHE_BIN32=httpd-2.4.37-win32-VC11.zip -@set APACHE_BIN64=httpd-2.4.37-win64-VC11.zip +@set LIBXML2=libxml2-2.9.11.tar.gz +@set LUA=lua-5.3.6.tar.gz +@set CURL=curl-7.77.0.zip +@set APACHE_SRC=httpd-2.4.48.tar.gz +@set APACHE_BIN32=httpd-2.4.48-win32-VS16.zip +@set APACHE_BIN64=httpd-2.4.48-win64-VS16.zip @set YAJL=yajl-2.1.0.zip -@set SSDEEP=ssdeep-2.13.tar.gz -@set SSDEEP_BIN=ssdeep-2.13.zip +@set SSDEEP=ssdeep-2.14.1.tar.gz +@set SSDEEP_BIN=ssdeep-2.14.1.zip @set CMAKE_DIR=%WORK_DIR%\%CMAKE:~0,-4%\bin @@ -64,7 +64,7 @@ call cl 2>&1 | findstr /C:"x64" @echo # pcre. - %PCRE% @call dependencies/build_pcre.bat @if NOT (%ERRORLEVEL%) == (0) goto build_failed_pcre -@cd "%CURRENT_DIR%" +@cd "%CURRENT_DIR% @echo # zlib - %ZLIB% @call dependencies/build_zlib.bat diff --git a/iis/build_msi.bat b/iis/build_msi.bat index fde4022cd9..d3c020fdd7 100644 --- a/iis/build_msi.bat +++ b/iis/build_msi.bat @@ -5,16 +5,16 @@ set CURRENT_DIR=%cd% del installer.wix* -"candle.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wxs" -out "%CURRENT_DIR%\installer.wixobj" -arch x64 +"C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wxs" -out "%CURRENT_DIR%\installer.wixobj" -arch x64 @if NOT (%ERRORLEVEL%) == (0) goto build_failed -"light.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wixobj" -out "%CURRENT_DIR%\installer-64.msi" +"C:\Program Files (x86)\WiX Toolset v3.11\bin\light.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wixobj" -out "%CURRENT_DIR%\installer-64.msi" @if NOT (%ERRORLEVEL%) == (0) goto build_failed -"candle.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wxs" -out "%CURRENT_DIR%\installer.wixobj" -arch x86 +"C:\Program Files (x86)\WiX Toolset v3.11\bin\candle.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wxs" -out "%CURRENT_DIR%\installer.wixobj" -arch x86 @if NOT (%ERRORLEVEL%) == (0) goto build_failed -"light.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wixobj" -out "%CURRENT_DIR%\installer-32.msi" +"C:\Program Files (x86)\WiX Toolset v3.11\bin\light.exe" -ext WixUtilExtension -ext WixUIExtension "%CURRENT_DIR%\installer.wixobj" -out "%CURRENT_DIR%\installer-32.msi" @if NOT (%ERRORLEVEL%) == (0) goto build_failed exit /B 0 diff --git a/iis/dependencies/build_curl.bat b/iis/dependencies/build_curl.bat index 6d66a1d11c..be26ca9a43 100644 --- a/iis/dependencies/build_curl.bat +++ b/iis/dependencies/build_curl.bat @@ -20,9 +20,10 @@ nmake /f Makefile.vc mode=dll ENABLE_WINSSL=yes MACHINE=%ARCH% WITH_ZLIB=dll cd "%WORK_DIR%" -copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-winssl-obj-lib\libcurl.dll" "%OUTPUT_DIR%" -copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-winssl-obj-lib\libcurl.lib" "%OUTPUT_DIR%" -copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-winssl-obj-lib\libcurl.lib" "%WORK_DIR%\curl\libcurl.lib" +copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-schannel-obj-lib\libcurl.dll" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-schannel-obj-lib\libcurl.lib" "%OUTPUT_DIR%" +copy /y "%WORK_DIR%\curl\builds\libcurl-vc-%ARCH%-release-dll-zlib-dll-ipv6-sspi-schannel-obj-lib\libcurl.lib" "%WORK_DIR%\curl\libcurl.lib" + exit /B 0 diff --git a/iis/installer.wxs b/iis/installer.wxs index 4f6a1fffbf..06b1c97648 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.1" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.4" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> @@ -129,12 +129,15 @@ </Directory> </Directory> </Directory> - <?endif ?> + <?endif ?> <Directory Id="$(var.PlatformProgramFilesFolder)"> <Directory Id="INSTALLFOLDER" Name="ModSecurity IIS"> + <!-- <Component Id="OWASP_CRS_V_3_0_2_SETUP" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6500"> <File Id="CRS_SETUP.CONF.EXAMPLE" Name="crs-setup.conf.example" Source="release\owasp_crs\crs-setup.conf.example" /> - </Component> + </Component> + --> + <!-- <Directory Id="OWASP_CRS" Name="owasp_crs"> <Component Id="OWASP_CRS_V_3_0_2" DiskId="1" Guid="64629082-F6A2-4675-9E3E-4EA363CD6502"> <File Id="CHANGES" Name="CHANGES" Source="release\owasp_crs\CHANGES" /> @@ -208,7 +211,7 @@ <File Id="UNIX_SHELL.DATA" Name="unix-shell.data" Source="release\owasp_crs\rules\unix-shell.data" /> <File Id="WINDOWS_POWERSHELL_COMMANDS.DATA" Name="windows-powershell-commands.data" Source="release\owasp_crs\rules\windows-powershell-commands.data" /> </Component> - </Directory> + </Directory> <Directory Id="UTIL" Name="util"> <Component Id="UTIL" DiskId="1" Guid="A95D50D7-4E87-4A87-BAD1-12370B8F5B9B"> <File Id="ID_RANGE" Name="id-range" Source="release\owasp_crs\util\id-range" /> @@ -294,13 +297,14 @@ </Directory> </Directory> </Directory> + --> </Directory> - </Directory> + </Directory> <Directory Id="ProgramMenuFolder"> <Directory Id="ProgramMenuDir" Name="ModSecurity IIS"> <Component Id="StartMenuShortcuts" Guid="43C26B13-C4D8-42F8-8715-3AF78E66C902"> <util:InternetShortcut Id="WebsiteShortcut" Name="ModSecurity" Target="http://www.modsecurity.org/" /> - <util:InternetShortcut Id="CSR" Name="OWASP ModSecurity Core Rule Set" Target="http://spIderlabs.github.io/owasp-modsecurity-crs/" /> + <!--<util:InternetShortcut Id="CSR" Name="OWASP ModSecurity Core Rule Set" Target="http://spIderlabs.github.io/owasp-modsecurity-crs/" />--> <RemoveFolder Id="ProgramMenuDir" On="uninstall" /> <RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" /> <Shortcut Id="UninstallProduct" Name="Uninstall" Description="Uninstalls the ModSecurity IIS" Target="[System64Folder]msiexec.exe" Arguments="/x [ProductCode]" /> @@ -315,104 +319,189 @@ </Directory> </Directory> </Directory> - <DirectoryRef Id="INSTALLFOLDER"> - <Component Id="ModSecCommon" DiskId="1" Guid="980270DF-81AB-469B-AB0E-64FA3BA160B6" Location="local"> - <File Id="README.TXT" Name="README.TXT" Source="wix\README.TXT" /> - <File Id="EULA.RTF" Name="EULA.rtf" Source="wix\EULA.rtf" /> - <File Id="modsecurity.conf" Name="modsecurity.conf" Source="wix\modsecurity.conf" /> - <File Id="modsecurity_iis.conf" Name="modsecurity_iis.conf" Source="wix\modsecurity_iis.conf" /> - <File Id="unicode.mapping" Name="unicode.mapping" Source="wix\unicode.mapping" /> - <!-- <File Id="modsecurity_crs_10_setup.conf" Name="modsecurity_crs_10_setup.conf" Source="wix\modsecurity_crs_10_setup.conf" /> --> - <File Id="LIST_DEPENDENCIES.BAT" Name="list_dependencies.bat" Source="wix\list_dependencies.bat" /> - <File Id="ModSecurity.xml" Name="ModSecurity.xml" Source="ModSecurity.xml" /> - <!-- Modify ApplicationHost.config --> - <util:XmlConfig Id="appHostEntry" File="$(var.ConfigFile)" Action="create" ElementPath="//configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" VerifyPath="section[\[]@name='ModSecurity'[\]]" Name="section" Node="element" Sequence="1" On="install" /> - <util:XmlConfig Id="appHostEntryName" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="name" Value="ModSecurity" Sequence="2" /> - <util:XmlConfig Id="appHostEntryOverrideMode" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="overrideModeDefault" Value="Allow" Sequence="3" /> - <util:XmlConfig Id="appHostEntryAllowDefinition" File="$(var.ConfigFile)" ElementPath="appHostEntry" Name="allowDefinition" Value="Everywhere" Sequence="4" /> - <util:XmlConfig Id="removeAppHostEntry" File="$(var.ConfigFile)" Action="delete" ElementPath="/configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" Node="element" VerifyPath="section[\[]@name='ModSecurity'[\]]" On="uninstall" Sequence="1" /> - <util:XmlConfig Id="removeAppHostEntry2" File="$(var.ConfigFile)" Action="delete" ElementPath="/configuration/system.webServer" Node="element" VerifyPath="/configuration/system.webServer/ModSecurity" Name="section" On="uninstall" Sequence="2" /> - <RegistryKey Root="HKLM" Key="SOFTWARE\ModSecurity\ModSecurity" Action="createAndRemoveOnUninstall"> - <RegistryValue Type="string" Name="ModSecurityConfigureIIS" Value="[IIS_SETUP]" KeyPath="yes" /> - </RegistryKey> - </Component> - </DirectoryRef> - <?if $(var.Win64) = "yes" ?> - <DirectoryRef Id="inetsrv64"> - <Component Id="ModSec64" DiskId="1" Guid="514A81F0-2413-42EF-B19F-E2613125ECE0" Win64="yes" Location="local"> - <File Id="_64_LIBAPR_1" Name="libapr-1.dll" Source="Release\amd64\libapr-1.dll" /> - <File Id="_64_LIBAPRICONV_1" Name="libapriconv-1.dll" Source="Release\amd64\libapriconv-1.dll" /> - <File Id="_64_LIBAPRUTIL_1" Name="libaprutil-1.dll" Source="Release\amd64\libaprutil-1.dll" /> - <File Id="_64_LIBCURL" Name="libcurl.dll" Source="Release\amd64\libcurl.dll" /> - <File Id="_64_LIBXML2" Name="libxml2.dll" Source="Release\amd64\libxml2.dll" /> - <File Id="_64_LUA5.1" Name="lua5.1.dll" Source="Release\amd64\lua5.1.dll" /> - <File Id="_64_YAJL" Name="yajl.dll" Source="Release\amd64\yajl.dll" /> - <File Id="_64_MLOGC" Name="mlogc.exe" Source="Release\amd64\mlogc.exe" /> - <File Id="_64_MODSECURITYIIS" Name="ModSecurityIIS.dll" Source="Release\amd64\ModSecurityIIS.dll" /> - <File Id="_64_PCRE" Name="pcre.dll" Source="Release\amd64\pcre.dll" /> - <File Id="_64_ZLIB1" Name="zlib1.dll" Source="Release\amd64\zlib1.dll" /> - <File Id="_64_FUZZY" Name="fuzzy.dll" Source="Release\amd64\fuzzy.dll" /> - </Component> - </DirectoryRef> - <DirectoryRef Id="inetsrv32"> - <Component Id="ModSec32" DiskId="1" Guid="514A81F0-2413-42EF-B19F-E2613125ECE7" Win64="no" Location="local"> - <File Id="_32_LIBAPR_1" Name="libapr-1.dll" Source="Release\x86\libapr-1.dll" /> - <File Id="_32_LIBAPRICONV_1" Name="libapriconv-1.dll" Source="Release\x86\libapriconv-1.dll" /> - <File Id="_32_LIBAPRUTIL_1" Name="libaprutil-1.dll" Source="Release\x86\libaprutil-1.dll" /> - <File Id="_32_LIBCURL" Name="libcurl.dll" Source="Release\x86\libcurl.dll" /> - <File Id="_32_LIBXML2" Name="libxml2.dll" Source="Release\x86\libxml2.dll" /> - <File Id="_32_LUA5.1" Name="lua5.1.dll" Source="Release\x86\lua5.1.dll" /> - <File Id="_32_YAJL" Name="yajl.dll" Source="Release\x86\yajl.dll" /> - <File Id="_32_MLOGC" Name="mlogc.exe" Source="Release\x86\mlogc.exe" /> - <File Id="_32_MODSECURITYIIS" Name="ModSecurityIIS.dll" Source="Release\x86\ModSecurityIIS.dll" /> - <File Id="_32_PCRE" Name="pcre.dll" Source="Release\x86\pcre.dll" /> - <File Id="_32_ZLIB1" Name="zlib1.dll" Source="Release\x86\zlib1.dll" /> - <File Id="_32_FUZZY" Name="fuzzy.dll" Source="Release\x86\fuzzy.dll" /> - </Component> - </DirectoryRef> - <DirectoryRef Id="SystemFolderConfigSchema32"> - <Component Id="ConfigSchema32" Guid="514A81F0-2413-42EF-B19F-E2613125EC11" Location="local" Win64="no"> - <File Id="_32_ConfigSchema" Name="ModSecurity.xml" Source="ModSecurity.xml" /> - </Component> - </DirectoryRef> - <DirectoryRef Id="SystemFolderConfigSchema64"> - <Component Id="ConfigSchema64" Guid="514A81F0-2413-42EF-B19F-E2613125EC22" Location="local" Win64="yes"> - <File Id="_64_ConfigSchema" Name="ModSecurity.xml" Source="ModSecurity.xml" /> - </Component> - </DirectoryRef> - <?else ?> - <DirectoryRef Id="inetsrv32"> - <Component Id="ModSec32" DiskId="1" Guid="514A81F0-2413-42EF-B19F-E2613125ECE1" Win64="no" Location="local"> - <File Id="_32_LIBAPR_1" Name="libapr-1.dll" Source="Release\x86\libapr-1.dll" /> - <File Id="_32_LIBAPRICONV_1" Name="libapriconv-1.dll" Source="Release\x86\libapriconv-1.dll" /> - <File Id="_32_LIBAPRUTIL_1" Name="libaprutil-1.dll" Source="Release\x86\libaprutil-1.dll" /> - <File Id="_32_LIBCURL" Name="libcurl.dll" Source="Release\x86\libcurl.dll" /> - <File Id="_32_LIBXML2" Name="libxml2.dll" Source="Release\x86\libxml2.dll" /> - <File Id="_32_LUA5.1" Name="lua5.1.dll" Source="Release\x86\lua5.1.dll" /> - <File Id="_32_YAJL" Name="yajl.dll" Source="Release\x86\yajl.dll" /> - <File Id="_32_MLOGC" Name="mlogc.exe" Source="Release\x86\mlogc.exe" /> - <File Id="_32_MODSECURITYIIS" Name="ModSecurityIIS.dll" Source="Release\x86\ModSecurityIIS.dll" /> - <File Id="_32_PCRE" Name="pcre.dll" Source="Release\x86\pcre.dll" /> - <File Id="_32_ZLIB1" Name="zlib1.dll" Source="Release\x86\zlib1.dll" /> - <File Id="_32_FUZZY" Name="fuzzy.dll" Source="Release\x86\fuzzy.dll" /> - </Component> - </DirectoryRef> - <DirectoryRef Id="SystemFolderConfigSchema32"> - <Component Id="ConfigSchema32" Guid="514A81F0-2413-42EF-B19F-E2613125EC11" Location="local" Win64="no"> - <File Id="_32_ConfigSchema" Name="ModSecurity.xml" Source="ModSecurity.xml" /> - </Component> - </DirectoryRef> - <?endif ?> - <Feature Id="DefaultFeature" Title="ModSecurity IIS Common files" Level="1" InstallDefault="local" Absent="disallow" Display="expand" AllowAdvertise="no" Description="Configuration and common files"> - <ComponentRef Id="ModSecCommon" /> - <ComponentRef Id="ConfigSchema32" /> - <?if $(var.Win64) = "yes" ?> - <ComponentRef Id="ConfigSchema64" /> - <?endif ?> - <ComponentRef Id="StartMenuShortcuts" /> - <Feature Id="OWASP_ModSecurity_CRS_v3.0.2" Level="1" Title="OWASP ModSecurity CRS v3.0.2" InstallDefault="local" Display="expand" AllowAdvertise="no" Description="Install OWASP CRS v3.0.2"> - <ComponentRef Id="OWASP_CRS_V_3_0_2" /> - <ComponentRef Id="OWASP_CRS_V_3_0_2_SETUP" /> + <DirectoryRef Id="INSTALLFOLDER"> <Component Id="ModSecCommon" + DiskId="1" Guid="980270DF-81AB-469B-AB0E-64FA3BA160B6" + Location="local"> <File Id="README.TXT" + Name="README.TXT" Source="wix\README.TXT" /> + <File Id="EULA.RTF" Name="EULA.rtf" + Source="wix\EULA.rtf" /> <File + Id="modsecurity.conf" Name="modsecurity.conf" + Source="wix\modsecurity.conf" /> + <File Id="modsecurity_iis.conf" Name="modsecurity_iis.conf" + Source="wix\modsecurity_iis.conf" /> <File + Id="unicode.mapping" Name="unicode.mapping" + Source="wix\unicode.mapping" /> + <!-- <File Id="modsecurity_crs_10_setup.conf" + Name="modsecurity_crs_10_setup.conf" + Source="wix\modsecurity_crs_10_setup.conf" /> --> <File + Id="LIST_DEPENDENCIES.BAT" Name="list_dependencies.bat" + Source="wix\list_dependencies.bat" /> <File + Id="ModSecurity.xml" Name="ModSecurity.xml" + Source="ModSecurity.xml" /> + <!-- Modify ApplicationHost.config --> <util:XmlConfig + Id="appHostEntry" File="$(var.ConfigFile)" + Action="create" + ElementPath="//configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" + VerifyPath="section[\[]@name='ModSecurity'[\]]" + Name="section" Node="element" Sequence="1" On="install" + /> <util:XmlConfig Id="appHostEntryName" + File="$(var.ConfigFile)" ElementPath="appHostEntry" + Name="name" Value="ModSecurity" Sequence="2" /> + <util:XmlConfig Id="appHostEntryOverrideMode" + File="$(var.ConfigFile)" ElementPath="appHostEntry" + Name="overrideModeDefault" Value="Allow" Sequence="3" + /> <util:XmlConfig Id="appHostEntryAllowDefinition" + File="$(var.ConfigFile)" ElementPath="appHostEntry" + Name="allowDefinition" Value="Everywhere" Sequence="4" + /> <util:XmlConfig Id="removeAppHostEntry" + File="$(var.ConfigFile)" Action="delete" + ElementPath="/configuration/configSections/sectionGroup[\[]@name='system.webServer'[\]]" + Node="element" + VerifyPath="section[\[]@name='ModSecurity'[\]]" + On="uninstall" Sequence="1" /> <util:XmlConfig + Id="removeAppHostEntry2" File="$(var.ConfigFile)" + Action="delete" + ElementPath="/configuration/system.webServer" + Node="element" + VerifyPath="/configuration/system.webServer/ModSecurity" + Name="section" On="uninstall" Sequence="2" /> + <RegistryKey Root="HKLM" Key="SOFTWARE\ModSecurity\ModSecurity" + Action="createAndRemoveOnUninstall"> <RegistryValue + Type="string" Name="ModSecurityConfigureIIS" + Value="[IIS_SETUP]" KeyPath="yes" /> + </RegistryKey> </Component> </DirectoryRef> <?if $(var.Win64) = + "yes" ?> <DirectoryRef Id="inetsrv64"> <Component Id="ModSec64" + DiskId="1" + Guid="514A81F0-2413-42EF-B19F-E2613125ECE0" + Win64="yes" Location="local"> <File + Id="_64_LIBAPR_1" Name="libapr-1.dll" + Source="Release\amd64\libapr-1.dll" /> + <File Id="_64_LIBAPRICONV_1" + Name="libapriconv-1.dll" + Source="Release\amd64\libapriconv-1.dll" + /> <File Id="_64_LIBAPRUTIL_1" + Name="libaprutil-1.dll" + Source="Release\amd64\libaprutil-1.dll" + /> <File Id="_64_LIBCURL" + Name="libcurl.dll" + Source="Release\amd64\libcurl.dll" /> + <File Id="_64_LIBXML2" Name="libxml2.dll" + Source="Release\amd64\libxml2.dll" /> + <File Id="_64_LUA5.1" Name="lua5.1.dll" + Source="Release\amd64\lua5.1.dll" /> + <File Id="_64_YAJL" Name="yajl.dll" + Source="Release\amd64\yajl.dll" /> + <File Id="_64_MLOGC" Name="mlogc.exe" + Source="Release\amd64\mlogc.exe" /> + <File Id="_64_MODSECURITYIIS" + Name="ModSecurityIIS.dll" + Source="Release\amd64\ModSecurityIIS.dll" + /> <File Id="_64_PCRE" Name="pcre.dll" + Source="Release\amd64\pcre.dll" /> + <File Id="_64_ZLIB1" Name="zlib1.dll" + Source="Release\amd64\zlib1.dll" /> + <File Id="_64_FUZZY" Name="fuzzy.dll" + Source="Release\amd64\fuzzy.dll" /> + </Component> </DirectoryRef> <DirectoryRef + Id="inetsrv32"> <Component Id="ModSec32" DiskId="1" + Guid="514A81F0-2413-42EF-B19F-E2613125ECE7" + Win64="no" Location="local"> <File + Id="_32_LIBAPR_1" Name="libapr-1.dll" + Source="Release\x86\libapr-1.dll" /> + <File Id="_32_LIBAPRICONV_1" + Name="libapriconv-1.dll" + Source="Release\x86\libapriconv-1.dll" + /> <File Id="_32_LIBAPRUTIL_1" + Name="libaprutil-1.dll" + Source="Release\x86\libaprutil-1.dll" + /> <File Id="_32_LIBCURL" + Name="libcurl.dll" + Source="Release\x86\libcurl.dll" /> + <File Id="_32_LIBXML2" Name="libxml2.dll" + Source="Release\x86\libxml2.dll" /> + <File Id="_32_LUA5.1" Name="lua5.1.dll" + Source="Release\x86\lua5.1.dll" /> + <File Id="_32_YAJL" Name="yajl.dll" + Source="Release\x86\yajl.dll" /> <File + Id="_32_MLOGC" Name="mlogc.exe" + Source="Release\x86\mlogc.exe" /> <File + Id="_32_MODSECURITYIIS" + Name="ModSecurityIIS.dll" + Source="Release\x86\ModSecurityIIS.dll" + /> <File Id="_32_PCRE" Name="pcre.dll" + Source="Release\x86\pcre.dll" /> <File + Id="_32_ZLIB1" Name="zlib1.dll" + Source="Release\x86\zlib1.dll" /> <File + Id="_32_FUZZY" Name="fuzzy.dll" + Source="Release\x86\fuzzy.dll" /> + </Component> </DirectoryRef> <DirectoryRef + Id="SystemFolderConfigSchema32"> <Component + Id="ConfigSchema32" + Guid="514A81F0-2413-42EF-B19F-E2613125EC11" + Location="local" Win64="no"> <File + Id="_32_ConfigSchema" + Name="ModSecurity.xml" + Source="ModSecurity.xml" /> + </Component> </DirectoryRef> <DirectoryRef + Id="SystemFolderConfigSchema64"> <Component Id="ConfigSchema64" + Guid="514A81F0-2413-42EF-B19F-E2613125EC22" + Location="local" Win64="yes"> <File + Id="_64_ConfigSchema" Name="ModSecurity.xml" + Source="ModSecurity.xml" /> </Component> + </DirectoryRef> <?else ?> <DirectoryRef Id="inetsrv32"> + <Component Id="ModSec32" DiskId="1" + Guid="514A81F0-2413-42EF-B19F-E2613125ECE1" + Win64="no" Location="local"> <File + Id="_32_LIBAPR_1" Name="libapr-1.dll" + Source="Release\x86\libapr-1.dll" /> + <File Id="_32_LIBAPRICONV_1" + Name="libapriconv-1.dll" + Source="Release\x86\libapriconv-1.dll" + /> <File Id="_32_LIBAPRUTIL_1" + Name="libaprutil-1.dll" + Source="Release\x86\libaprutil-1.dll" + /> <File Id="_32_LIBCURL" + Name="libcurl.dll" + Source="Release\x86\libcurl.dll" /> + <File Id="_32_LIBXML2" Name="libxml2.dll" + Source="Release\x86\libxml2.dll" /> + <File Id="_32_LUA5.1" Name="lua5.1.dll" + Source="Release\x86\lua5.1.dll" /> + <File Id="_32_YAJL" Name="yajl.dll" + Source="Release\x86\yajl.dll" /> <File + Id="_32_MLOGC" Name="mlogc.exe" + Source="Release\x86\mlogc.exe" /> <File + Id="_32_MODSECURITYIIS" + Name="ModSecurityIIS.dll" + Source="Release\x86\ModSecurityIIS.dll" + /> <File Id="_32_PCRE" Name="pcre.dll" + Source="Release\x86\pcre.dll" /> <File + Id="_32_ZLIB1" Name="zlib1.dll" + Source="Release\x86\zlib1.dll" /> <File + Id="_32_FUZZY" Name="fuzzy.dll" + Source="Release\x86\fuzzy.dll" /> + </Component> </DirectoryRef> <DirectoryRef + Id="SystemFolderConfigSchema32"> <Component + Id="ConfigSchema32" + Guid="514A81F0-2413-42EF-B19F-E2613125EC11" + Location="local" Win64="no"> <File + Id="_32_ConfigSchema" + Name="ModSecurity.xml" + Source="ModSecurity.xml" /> + </Component> </DirectoryRef> <?endif ?> <Feature + Id="DefaultFeature" Title="ModSecurity IIS Common files" + Level="1" InstallDefault="local" Absent="disallow" + Display="expand" AllowAdvertise="no" Description="Configuration + and common files"> <ComponentRef Id="ModSecCommon" /> + <ComponentRef Id="ConfigSchema32" /> <?if $(var.Win64) = "yes" + ?> <ComponentRef Id="ConfigSchema64" /> <?endif ?> + <ComponentRef Id="StartMenuShortcuts" /> + <!-- + <Feature Id="OWASP_ModSecurity_CRS_v3.0.2" Level="1" Title="OWASP + ModSecurity CRS v3.0.2" InstallDefault="local" Display="expand" + AllowAdvertise="no" Description="Install OWASP CRS v3.0.2"> + <ComponentRef Id="OWASP_CRS_V_3_0_2" /> <ComponentRef + Id="OWASP_CRS_V_3_0_2_SETUP" /> <ComponentRef Id="ID_NUMBERING" /> <ComponentRef Id="README" /> @@ -430,7 +519,8 @@ <ComponentRef Id="REGRESSION_TESTS" /> <ComponentRef Id="VIRTUAL_PATCHING" /> </Feature> - </Feature> + --> + </Feature> <Feature Id="VCRedist" Title="Visual C++ 12.0 Runtime" AllowAdvertise="no" Display="hidden" Level="1"> <?if $(var.Win64) = "yes" ?> <MergeRef Id="VCRedist110_64" /> @@ -526,8 +616,8 @@ <Control Id="Title" Type="Text" X="15" Y="6" Width="210" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}IIS Setup" /> <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Choose to configure ModSecurity on IIS or not." /> <Control Id="Text" Type="Text" X="25" Y="55" Width="320" Height="50" Text="ModSecurityIIS needs to be configured under IIS as a module. It is recommended to perform this configuration during the installation. However, if you are facing problems in the installation, the recomendation is to disable this step. This will facilitate the debugging process since the files will be installed in place. Note that some scripts will be installed along with ModSecurity common files that can be later used to help this configuration/debugging process." /> - <Control Type="CheckBox" Id="ConfigureIIS" Width="200" Height="14" X="25" Y="124" CheckBoxValue="1" Property="IIS_SETUP" Text="Perform ModSecurityIIS configuration." /> - <Control Type="Text" Id="troubleshooting" Width="314" Height="37" X="26" Y="161" Text="For further information about problems during the installation, have a look at ModSecurityIIS Troubleshooting guide. Available at: https://github.com/SpiderLabs/ModSecurity/wiki/IIS-Troubleshooting" /> + <Control Type="CheckBox" Id="ConfigureIIS" Width="200" Height="14" X="25" Y="124" CheckBoxValue="1" Property="IIS_SETUP" Text="Perform ModSecurityIIS configuration." /> + <Control Type="Text" Id="troubleshooting" Width="314" Height="67" X="26" Y="161" Text="For further information about problems during the installation, have a look at ModSecurityIIS Troubleshooting guide. Available at: https://github.com/SpiderLabs/ModSecurity/wiki/IIS-Troubleshooting. ATTENTION: This installation process no longer install OWASP CRS. Please refer to the OWASP CRS Project to understand how to install it. " /> </Dialog> <Binary Id="bannrbmp" SourceFile="wix\banner.jpg" /> <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> diff --git a/iis/wix/modsecurity_iis.conf b/iis/wix/modsecurity_iis.conf index 7cd9cff49f..a18a4a6bca 100644 --- a/iis/wix/modsecurity_iis.conf +++ b/iis/wix/modsecurity_iis.conf @@ -1,3 +1 @@ Include modsecurity.conf -Include crs-setup.conf.example -Include owasp_crs\rules\*.conf From b32cc1680c8fa8d496981112970a38cdba6bac67 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle <fcosta@trustwave.com> Date: Tue, 1 Jun 2021 21:24:56 -0300 Subject: [PATCH 250/477] Version 2.9.4 Increasing version to 2.9.4 --- CHANGES | 4 ++-- apache2/msc_release.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index afcbf9c2b0..bd03641530 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -DD mmm YYYY - 2.9.x (to be released) ------------------------------------- +21 Jun 2021 - 2.9.4 +------------------- * Add microsec timestamp resolution to the formatted log timestamp [Issue #2095 - @rainerjung] diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 49d928702c..5ff3a8ec39 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "3" +#define MODSEC_VERSION_MAINT "4" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From 8b2c86927951c4400a79ece8d5e7e3060399cdc6 Mon Sep 17 00:00:00 2001 From: martinhsv <55407942+martinhsv@users.noreply.github.com> Date: Mon, 12 Jul 2021 09:29:38 -0700 Subject: [PATCH 251/477] Add commented-out sample rule to engage JSON Processor for more subtypes --- modsecurity.conf-recommended | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 60317acb74..f357d95cc1 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -29,6 +29,13 @@ SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ SecRule REQUEST_HEADERS:Content-Type "application/json" \ "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" +# Sample rule to enable JSON request body parser for more subtypes. +# Uncomment or adapt this rule if you want to engage the JSON +# Processor for "+json" subtypes +# +#SecRule REQUEST_HEADERS:Content-Type "^application/.+[+]json$" \ +# "id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + # Maximum request body size we will accept for buffering. If you support # file uploads then the value given on the first line has to be as large # as the largest file you are willing to accept. The second value refers From 199cf5da9172fe98e705237a296d633f115677c0 Mon Sep 17 00:00:00 2001 From: EarlRoth <EarlRoth@users.noreply.github.com> Date: Mon, 13 Sep 2021 16:30:50 -0600 Subject: [PATCH 252/477] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00c8cd3145..d489f846b7 100644 --- a/README.md +++ b/README.md @@ -16,4 +16,4 @@ Please refer to: [the documentation folder](https://github.com/SpiderLabs/ModSec ## Sponsor Note -ModSecurity is sponsored by Trustwave. Trustwave offers a range of commercial services related to ModSecurity, including a set of Rules, consultancy and customization of ModSecurity. Contact the Trustwave sales department for more information - sales@trustwave.com +Development of ModSecurity is sponsored by Trustwave. Sponsorship will end July 1, 2024. Additional information can be found here https://www.trustwave.com/en-us/resources/security-resources/software-updates/end-of-sale-and-trustwave-support-for-modsecurity-web-application-firewall/ From 41918335fa4c74fba46a986771a5a6cb457070c4 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Thu, 18 Nov 2021 17:35:40 -0800 Subject: [PATCH 253/477] Support configurable limit on depth of JSON parsing --- CHANGES | 6 +++ apache2/apache2_config.c | 30 ++++++++++++++ apache2/modsecurity.h | 2 + apache2/msc_json.c | 28 ++++++++++++- apache2/msc_json.h | 2 + tests/regression/rule/15-json.t | 69 +++++++++++++++++++++++++++++++++ 6 files changed, 135 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index bd03641530..2ae2c712d4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +DD mmm YYYY - 2.9.x (to be released) +------------------- + + * Support configurable limit on depth of JSON parsing + [@theMiddleBlue, @airween, @dune73, @martinhsv] + 21 Jun 2021 - 2.9.4 ------------------- diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 80f8f2b507..4ea098f3cc 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -50,6 +50,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) dcfg->reqbody_inmemory_limit = NOT_SET; dcfg->reqbody_limit = NOT_SET; dcfg->reqbody_no_files_limit = NOT_SET; + dcfg->reqbody_json_depth_limit = NOT_SET; dcfg->resbody_access = NOT_SET; dcfg->debuglog_name = NOT_SET_P; @@ -332,6 +333,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) ? parent->reqbody_limit : child->reqbody_limit); merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit); + merged->reqbody_json_depth_limit = (child->reqbody_json_depth_limit == NOT_SET + ? parent->reqbody_json_depth_limit : child->reqbody_json_depth_limit); merged->resbody_access = (child->resbody_access == NOT_SET ? parent->resbody_access : child->resbody_access); @@ -648,6 +651,7 @@ void init_directory_config(directory_config *dcfg) dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT; if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT; if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT; + if (dcfg->reqbody_json_depth_limit == NOT_SET) dcfg->reqbody_json_depth_limit = REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT; if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0; if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT; if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT; @@ -1920,6 +1924,24 @@ static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, return NULL; } +static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyJsonDepthLimit: %s", p1); + } + + dcfg->reqbody_json_depth_limit = limit; + + return NULL; +} + static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { @@ -3553,6 +3575,14 @@ const command_rec module_directives[] = { "maximum request body size ModSecurity will accept, but excluding the size of uploaded files." ), + AP_INIT_TAKE1 ( + "SecRequestBodyJsonDepthLimit", + cmd_request_body_json_depth_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body JSON parsing depth ModSecurity will accept." + ), + AP_INIT_TAKE1 ( "SecRequestEncoding", cmd_request_encoding, diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 11313b9b48..261151bae9 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -95,6 +95,7 @@ typedef struct msc_parm msc_parm; #define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072 #define REQUEST_BODY_DEFAULT_LIMIT 134217728 #define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576 +#define REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT 10000 #define RESPONSE_BODY_DEFAULT_LIMIT 524288 #define RESPONSE_BODY_HARD_LIMIT 1073741824L @@ -498,6 +499,7 @@ struct directory_config { long int reqbody_inmemory_limit; long int reqbody_limit; long int reqbody_no_files_limit; + long int reqbody_json_depth_limit; int resbody_access; long int of_limit; diff --git a/apache2/msc_json.c b/apache2/msc_json.c index c30660325a..d69e9eb7c1 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -164,6 +164,11 @@ static int yajl_start_array(void *ctx) { else { msr->json->prefix = apr_pstrdup(msr->mp, msr->json->current_key); } + msr->json->current_depth++; + if (msr->json->current_depth > msr->txcfg->reqbody_json_depth_limit) { + msr->json->depth_limit_exceeded = 1; + return 0; + } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "New JSON hash context (prefix '%s')", msr->json->prefix); @@ -200,6 +205,7 @@ static int yajl_end_array(void *ctx) { */ msr->json->prefix = (unsigned char *) NULL; } + msr->json->current_depth--; return 1; } @@ -229,6 +235,11 @@ static int yajl_start_map(void *ctx) else { msr->json->prefix = apr_pstrdup(msr->mp, msr->json->current_key); } + msr->json->current_depth++; + if (msr->json->current_depth > msr->txcfg->reqbody_json_depth_limit) { + msr->json->depth_limit_exceeded = 1; + return 0; + } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "New JSON hash context (prefix '%s')", msr->json->prefix); @@ -270,6 +281,7 @@ static int yajl_end_map(void *ctx) msr->json->current_key = msr->json->prefix; msr->json->prefix = (unsigned char *) NULL; } + msr->json->current_depth--; return 1; } @@ -308,6 +320,9 @@ int json_init(modsec_rec *msr, char **error_msg) { msr->json->prefix = (unsigned char *) NULL; msr->json->current_key = (unsigned char *) NULL; + msr->json->current_depth = 0; + msr->json->depth_limit_exceeded = 0; + /** * yajl initialization * @@ -337,7 +352,11 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char msr->json->status = yajl_parse(msr->json->handle, buf, size); if (msr->json->status != yajl_status_ok) { /* We need to free the yajl error message later, how to do this? */ - *error_msg = yajl_get_error(msr->json->handle, 0, buf, size); + if (msr->json->depth_limit_exceeded) { + *error_msg = "JSON depth limit exceeded"; + } else { + *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); + } return -1; } @@ -357,7 +376,12 @@ int json_complete(modsec_rec *msr, char **error_msg) { msr->json->status = yajl_complete_parse(msr->json->handle); if (msr->json->status != yajl_status_ok) { /* We need to free the yajl error message later, how to do this? */ - *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); + if (msr->json->depth_limit_exceeded) { + *error_msg = "JSON depth limit exceeded"; + } else { + *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); + } + return -1; } diff --git a/apache2/msc_json.h b/apache2/msc_json.h index 02326ec03d..7e3d72501c 100644 --- a/apache2/msc_json.h +++ b/apache2/msc_json.h @@ -40,6 +40,8 @@ struct json_data { /* prefix is used to create data hierarchy (i.e., 'parent.child.value') */ unsigned char *prefix; unsigned char *current_key; + long int current_depth; + int depth_limit_exceeded; }; /* Functions */ diff --git a/tests/regression/rule/15-json.t b/tests/regression/rule/15-json.t index 181df9e076..f84355a952 100644 --- a/tests/regression/rule/15-json.t +++ b/tests/regression/rule/15-json.t @@ -156,5 +156,74 @@ ), ), ), +}, +{ + type => "rule", + comment => "json parser - parsing depth not exceeded", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyJsonDepthLimit 5 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule REQBODY_ERROR "!\@eq 0" "id:'200442',phase:2,log,deny,status:403,msg:'Failed to parse request body'" + ), + match_log => { + debug => [ qr/key/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + { + "key1":{"key2":{"key3":{"key4":{"key5":"thevalue"}}}} + } + ), + ), + ), +}, +{ + type => "rule", + comment => "json parser - parsing depth exceeded", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecDebugLogLevel 9 + SecRequestBodyJsonDepthLimit 3 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule REQBODY_ERROR "!\@eq 0" "id:'200443',phase:2,log,deny,status:403,msg:'Failed to parse request body'" + ), + match_log => { + audit => [ qr/JSON parsing error: JSON depth limit exceeded/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + { + "key1":{"key2":{"key3":{"key4":{"key5":"thevalue"}}}} + } + ), + ), + ), } + From 860299971df990610943c2ff18c70e7e5716db8b Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 22 Nov 2021 11:22:12 -0800 Subject: [PATCH 254/477] Version 2.9.5 --- CHANGES | 2 +- apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 2ae2c712d4..8a2be8ef08 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -DD mmm YYYY - 2.9.x (to be released) +22 Nov 2021 - 2.9.5 ------------------- * Support configurable limit on depth of JSON parsing diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 5ff3a8ec39..5d185ab161 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "4" +#define MODSEC_VERSION_MAINT "5" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" diff --git a/iis/installer.wxs b/iis/installer.wxs index 06b1c97648..e88d9297c9 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.4" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.5" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> From df4bffcdc8960464022beb5f7cb1bc70706b2ae1 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 6 Dec 2021 14:27:04 -0800 Subject: [PATCH 255/477] IIS: Update dependencies for Windows build as of v2.9.5 --- CHANGES | 6 ++++++ iis/build_dependencies.bat | 20 ++++++++++---------- iis/build_release.bat | 5 +++-- 3 files changed, 19 insertions(+), 12 deletions(-) mode change 100644 => 100755 iis/build_dependencies.bat mode change 100644 => 100755 iis/build_release.bat diff --git a/CHANGES b/CHANGES index 8a2be8ef08..14f49ec8a1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +DD mmm YYYY - 2.9.x (to be released) +------------------- + + * IIS: Update dependencies for Windows build as of v2.9.5 + [@martinhsv] + 22 Nov 2021 - 2.9.5 ------------------- diff --git a/iis/build_dependencies.bat b/iis/build_dependencies.bat old mode 100644 new mode 100755 index 0908d51e37..7bca030183 --- a/iis/build_dependencies.bat +++ b/iis/build_dependencies.bat @@ -8,14 +8,14 @@ :: Dependencies @set CMAKE=cmake-3.12.4-win32-x86.zip -@set PCRE=pcre-8.41.zip +@set PCRE=pcre-8.45.zip @set ZLIB=zlib-1.2.11.tar.gz -@set LIBXML2=libxml2-2.9.11.tar.gz +@set LIBXML2=libxml2-2.9.12.tar.gz @set LUA=lua-5.3.6.tar.gz -@set CURL=curl-7.77.0.zip -@set APACHE_SRC=httpd-2.4.48.tar.gz -@set APACHE_BIN32=httpd-2.4.48-win32-VS16.zip -@set APACHE_BIN64=httpd-2.4.48-win64-VS16.zip +@set CURL=curl-7.79.0.zip +@set APACHE_SRC=httpd-2.4.51.tar.gz +@set APACHE_BIN32=httpd-2.4.51-win32-VS16.zip +@set APACHE_BIN64=httpd-2.4.51-win64-VS16.zip @set YAJL=yajl-2.1.0.zip @set SSDEEP=ssdeep-2.14.1.tar.gz @set SSDEEP_BIN=ssdeep-2.14.1.zip @@ -23,11 +23,11 @@ @set CMAKE_DIR=%WORK_DIR%\%CMAKE:~0,-4%\bin :: Aditional paths. -@set PATH=%PATH%;%CMAKE_DIR%;"c:\program files\7-zip" +@set "DIR_7ZIP=c:\program files\7-zip" +@set PATH=%PATH%;%CMAKE_DIR%;%DIR_7ZIP% - -:: @set VCARGS32="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat" -:: @set VCARGS64="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat" +:: @set VCARGS32="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" +:: @set VCARGS64="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsx86_amd64.bat" :: Do not edit bellow this line. diff --git a/iis/build_release.bat b/iis/build_release.bat old mode 100644 new mode 100755 index 68bc587130..c1d8e85eeb --- a/iis/build_release.bat +++ b/iis/build_release.bat @@ -14,8 +14,9 @@ mkdir "%AMD64%" mkdir "%X86%" -set VCARGS32="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\vcvars32.bat" -set VCARGS64="C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\x86_amd64\vcvarsx86_amd64.bat" +set VCARGS32="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat" +set VCARGS64="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsx86_amd64.bat" + set SSDEEP_ARCH="x64" call build_dependencies.bat %VCARGS64% From 60be05914ce3b23bc126cfa61face7b75650448f Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 21 Dec 2021 06:30:28 -0800 Subject: [PATCH 256/477] Add SecRequestBodyJsonDepthLimit to modsecurity.conf-recommended --- CHANGES | 2 ++ modsecurity.conf-recommended | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/CHANGES b/CHANGES index 14f49ec8a1..d006fa230d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Add SecRequestBodyJsonDepthLimit to modsecurity.conf-recommended + [Issue #2647 @theMiddleBlue, @airween, @877509395 ,@martinhsv] * IIS: Update dependencies for Windows build as of v2.9.5 [@martinhsv] diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index f357d95cc1..c84ddceab8 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -58,6 +58,11 @@ SecRequestBodyInMemoryLimit 131072 # SecRequestBodyLimitAction Reject +# Maximum parsing depth allowed for JSON objects. You want to keep this +# value as low as practical. +# +SecRequestBodyJsonDepthLimit 512 + # Verify that we've correctly processed the request body. # As a rule of thumb, when failing to process a request body # you should reject the request (when deployed in blocking mode) From 065dbe7e7686869e58623d0d27bbed4b1eef3fdd Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 22 Dec 2021 10:37:03 -0800 Subject: [PATCH 257/477] Multipart names may include single quote if double-quote enclosed --- CHANGES | 2 ++ apache2/msc_multipart.c | 15 +++++--- tests/regression/misc/00-multipart-parser.t | 39 +++++++++++++++++++++ 3 files changed, 52 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index d006fa230d..dde6150883 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Multipart names/filenames may include single quote if double-quote enclosed + [Issue #2352 @martinhsv] * Add SecRequestBodyJsonDepthLimit to modsecurity.conf-recommended [Issue #2647 @theMiddleBlue, @airween, @877509395 ,@martinhsv] * IIS: Update dependencies for Windows build as of v2.9.5 diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 880b13c579..d087c863e1 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -20,7 +20,7 @@ #include "msc_util.h" #include "msc_parsers.h" -void validate_quotes(modsec_rec *msr, char *data) { +void validate_quotes(modsec_rec *msr, char *data, char quote) { int i, len; if(msr == NULL) @@ -32,6 +32,12 @@ void validate_quotes(modsec_rec *msr, char *data) { if(data == NULL) return; + // if the value was enclosed in double quotes, then we don't care about + // a single quote character within the name. + if (quote == '"') { + return; + } + len = strlen(data); for(i = 0; i < len; i++) { @@ -123,9 +129,10 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) * set so the user can deal with it in the rules if they so wish. */ + char quote = '\0'; if ((*p == '"') || (*p == '\'')) { /* quoted */ - char quote = *p; + quote = *p; // remember which quote character was used for the value if (quote == '\'') { msr->mpd->flag_invalid_quoting = 1; @@ -182,7 +189,7 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) if (strcmp(name, "name") == 0) { - validate_quotes(msr, value); + validate_quotes(msr, value, quote); msr->multipart_name = apr_pstrdup(msr->mp, value); @@ -201,7 +208,7 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) else if (strcmp(name, "filename") == 0) { - validate_quotes(msr, value); + validate_quotes(msr, value, quote); msr->multipart_filename = apr_pstrdup(msr->mp, value); diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t index de39bf0864..ebdadee76d 100644 --- a/tests/regression/misc/00-multipart-parser.t +++ b/tests/regression/misc/00-multipart-parser.t @@ -736,6 +736,45 @@ ), }, +# Single quote within double quotes is ok +{ + type => "misc", + comment => "multipart parser (C-D uses single quote within double quotes)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_INVALID_QUOTING "!\@eq 0" "phase:2,deny,id:500169" + ), + match_log => { + debug => [ qr/Adding request argument \(BODY\): name "a'b/s, 1 ], + -debug => [ qr/Adding request argument \(BODY\): name "b/s, 1 ], + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646", + ], + normalize_raw_request_data( + q( + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="a'b" + + 1 + -----------------------------69343412719991675451336310646 + Content-Disposition: form-data; name="aaa"; filename="d'ummy" + + 2 + -----------------------------69343412719991675451336310646-- + ), + ), + ), +}, + # Invalid boundary separators { type => "misc", From c6582df2e5e3a92ba4b90e2a6cfaeb89f61bcadf Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 29 Dec 2021 06:46:25 -0800 Subject: [PATCH 258/477] Fix memory leak that occurs on JSON parsing error --- CHANGES | 2 ++ apache2/msc_json.c | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index dde6150883..e54a3d9892 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix memory leak that occurs on JSON parsing error + [Issue #2236 @argenet, @vloup, @martinhsv] * Multipart names/filenames may include single quote if double-quote enclosed [Issue #2352 @martinhsv] * Add SecRequestBodyJsonDepthLimit to modsecurity.conf-recommended diff --git a/apache2/msc_json.c b/apache2/msc_json.c index d69e9eb7c1..c781b3ae86 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -351,11 +351,12 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char /* Feed our parser and catch any errors */ msr->json->status = yajl_parse(msr->json->handle, buf, size); if (msr->json->status != yajl_status_ok) { - /* We need to free the yajl error message later, how to do this? */ if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; } else { - *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); + char *yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); + *error_msg = apr_pstrdup(msr->mp, yajl_err); + yajl_free_error(msr->json->handle, yajl_err); } return -1; } @@ -375,11 +376,12 @@ int json_complete(modsec_rec *msr, char **error_msg) { /* Wrap up the parsing process */ msr->json->status = yajl_complete_parse(msr->json->handle); if (msr->json->status != yajl_status_ok) { - /* We need to free the yajl error message later, how to do this? */ if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; } else { - *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0); + char *yajl_err = yajl_get_error(msr->json->handle, 0, NULL, 0); + *error_msg = apr_pstrdup(msr->mp, yajl_err); + yajl_free_error(msr->json->handle, yajl_err); } return -1; From 733427197e2fe4fabcbb0f43bd1e636ef923a6b4 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 19 Apr 2022 10:07:36 -0700 Subject: [PATCH 259/477] Set SecStatusEngine Off in modsecurity.conf-recommended --- CHANGES | 2 ++ modsecurity.conf-recommended | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index e54a3d9892..596d6af342 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Set SecStatusEngine Off in modsecurity.conf-recommended + [Issue #2717 - @un99known99, @martinhsv] * Fix memory leak that occurs on JSON parsing error [Issue #2236 @argenet, @vloup, @martinhsv] * Multipart names/filenames may include single quote if double-quote enclosed diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index c84ddceab8..203349ecd0 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -234,5 +234,7 @@ SecUnicodeMapFile unicode.mapping 20127 # The following information will be shared: ModSecurity version, # Web Server version, APR version, PCRE version, Lua version, Libxml2 # version, Anonymous unique id for host. -SecStatusEngine On +# NB: As of April 2022, there is no longer any advantage to turning this +# setting On, as there is no active receiver for the information. +SecStatusEngine Off From 4a98032b7f827c4edd2514ce2af29222bb2ba289 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 3 May 2022 12:34:03 -0700 Subject: [PATCH 260/477] Allow no-key, single-value JSON body --- CHANGES | 2 ++ apache2/msc_json.c | 3 +-- apache2/msc_json.h | 2 +- tests/regression/rule/15-json.t | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 596d6af342..225b6adf79 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Allow no-key, single-value JSON body + [Issue #2735 - @marcstern, @martinhsv] * Set SecStatusEngine Off in modsecurity.conf-recommended [Issue #2717 - @un99known99, @martinhsv] * Fix memory leak that occurs on JSON parsing error diff --git a/apache2/msc_json.c b/apache2/msc_json.c index c781b3ae86..737069b8d2 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -27,8 +27,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) * to reference this argument; for now we simply ignore these */ if (!msr->json->current_key) { - msr_log(msr, 3, "Cannot add scalar value without an associated key"); - return 1; + msr->json->current_key = ""; } arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg)); diff --git a/apache2/msc_json.h b/apache2/msc_json.h index 7e3d72501c..089dab4763 100644 --- a/apache2/msc_json.h +++ b/apache2/msc_json.h @@ -39,7 +39,7 @@ struct json_data { /* prefix is used to create data hierarchy (i.e., 'parent.child.value') */ unsigned char *prefix; - unsigned char *current_key; + const unsigned char *current_key; long int current_depth; int depth_limit_exceeded; }; diff --git a/tests/regression/rule/15-json.t b/tests/regression/rule/15-json.t index f84355a952..370ebba6a9 100644 --- a/tests/regression/rule/15-json.t +++ b/tests/regression/rule/15-json.t @@ -224,6 +224,40 @@ ), ), ), +}, +{ + type => "rule", + comment => "json parser - no-key single value", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecDebugLog $ENV{DEBUG_LOG} + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" + SecDebugLogLevel 9 + SecRequestBodyJsonDepthLimit 3 + SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" + SecRule REQBODY_ERROR "!\@eq 0" "id:'200444',phase:2,log,deny,status:403,msg:'Failed to parse request body'" + SecRule ARGS "\@streq 25" "id:'200445',phase:2,log,deny,status:403" + ), + match_log => { + audit => [ qr/200445/s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/json", + ], + normalize_raw_request_data( + q( + 25 + ), + ), + ), } From f71498ceff32c37228dd20a108f26078dee72885 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 27 May 2022 11:05:37 -0700 Subject: [PATCH 261/477] mlogc log-line parsing fails due to enhanced timestamp --- CHANGES | 2 ++ mlogc/mlogc.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 225b6adf79..7ba9e74dbc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * mlogc log-line parsing fails due to enhanced timestamp + [Issue #2682 - @bozhinov, @ABrauer-CPT, @martinhsv] * Allow no-key, single-value JSON body [Issue #2735 - @marcstern, @martinhsv] * Set SecStatusEngine Off in modsecurity.conf-recommended diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c index e650452dc4..ab0c06530a 100644 --- a/mlogc/mlogc.c +++ b/mlogc/mlogc.c @@ -96,7 +96,7 @@ do { \ static const char logline_pattern[] = "^(\\S+)" "\\ (\\S+)\\ (\\S+)\\ (\\S+)" - "\\ \\[([^:]+):(\\d+:\\d+:\\d+)\\ ([^\\]]+)\\]" + "\\ \\[([^:]+):(\\d+:\\d+:\\d+(?:[.]\\d+)?)\\ ([^\\]]+)\\]" "\\ \"(.*)\"" "\\ (\\d+)\\ (\\S+)" "\\ \"(.*)\"\\ \"(.*)\"" From bc8662b0d570fe18e17f2621a51b318ddfb06598 Mon Sep 17 00:00:00 2001 From: Vincent Loup <vincent.loup@elca.ch> Date: Thu, 14 Apr 2022 16:27:49 +0200 Subject: [PATCH 262/477] Fix memory leak in streams --- CHANGES | 2 ++ apache2/modsecurity.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/CHANGES b/CHANGES index 7ba9e74dbc..5a8864e43b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix memory leak in streams + [Issue #2208 - @marcstern, @vloup, @JamesColeman-LW] * mlogc log-line parsing fails due to enhanced timestamp [Issue #2682 - @bozhinov, @ABrauer-CPT, @martinhsv] * Allow no-key, single-value JSON body diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 09b5caa21f..2a37e4976a 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -325,6 +325,21 @@ static apr_status_t modsecurity_tx_cleanup(void *data) { #endif #endif + /* Streams cleanup. */ + if (msr->stream_input_data != NULL) { + free(msr->stream_input_data); + msr->stream_input_data = NULL; + msr->stream_input_length = 0; +#ifdef MSC_LARGE_STREAM_INPUT + msr->stream_input_allocated_length = 0; +#endif + } + if (msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + msr->stream_output_length = 0; + } + return APR_SUCCESS; } From b5b4e2fdd16b7cd5021c4942b0ba61fc67b7a6eb Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 1 Jun 2022 07:19:10 -0700 Subject: [PATCH 263/477] Fix: negative usec on log line when data type long is 32b --- CHANGES | 2 ++ apache2/msc_util.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 7ba9e74dbc..12efbd4c44 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix: negative usec on log line when data type long is 32b + [Issue #2753 - @ABrauer-CPT, @martinhsv] * mlogc log-line parsing fails due to enhanced timestamp [Issue #2682 - @bozhinov, @ABrauer-CPT, @martinhsv] * Allow no-key, single-value JSON body diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 2fdfd57c32..6b6d27f9c1 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -1134,7 +1134,7 @@ char *current_logtime(apr_pool_t *mp) { apr_strftime(tstr, &len, 80, "%d/%b/%Y:%H:%M:%S.", &t); apr_snprintf(tstr + strlen(tstr), 80 - strlen(tstr), "%06ld %c%.2d%.2d", - ((long)now) % 1000000L, + (long)apr_time_usec(now), t.tm_gmtoff < 0 ? '-' : '+', t.tm_gmtoff / (60 * 60), (t.tm_gmtoff / 60) % 60); return apr_pstrdup(mp, tstr); From dfbdaf8f316e44ced774dfc89848e9471cbd6970 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 8 Jun 2022 15:36:36 -0700 Subject: [PATCH 264/477] XML parser cleanup: NULL duplicate pointer --- apache2/msc_xml.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 9cc4da65b8..763ef399f4 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -140,6 +140,9 @@ apr_status_t xml_cleanup(modsec_rec *msr) { if (msr->xml->parsing_ctx != NULL) { if (msr->xml->parsing_ctx->myDoc) { xmlFreeDoc(msr->xml->parsing_ctx->myDoc); + if (msr->xml->parsing_ctx->myDoc == msr->xml->doc) { + msr->xml->doc = NULL; + } } xmlFreeParserCtxt(msr->xml->parsing_ctx); msr->xml->parsing_ctx = NULL; From 9cb9309fdd107726ee61539a50bdb6d8af8eb92f Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 8 Jun 2022 15:55:25 -0700 Subject: [PATCH 265/477] Add CHANGES entries for recent merges --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 6969ff521e..8d4ef09226 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * XML parser cleanup: NULL duplicate pointer + [Issue #2760 - @martinhsv] + * Properly cleanup XML parser contexts upon completion + [Issue #2239 - @argenet] * Fix memory leak in streams [Issue #2208 - @marcstern, @vloup, @JamesColeman-LW] * Fix: negative usec on log line when data type long is 32b From 45acae433088b447a32e3aa4d6a9bcdaa79c467b Mon Sep 17 00:00:00 2001 From: Erki Aring <erki@example.ee> Date: Thu, 4 Aug 2022 12:40:32 +0300 Subject: [PATCH 266/477] Add APLOG_USE_MODULE to correctly mark log messages --- apache2/mod_security2.c | 6 ------ apache2/modsecurity.h | 3 +++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 7bb215e2ed..9ed4bdc0a9 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -25,12 +25,6 @@ #include "apr_optional.h" #include "mod_log_config.h" -/* - * #ifdef APLOG_USE_MODULE - * APLOG_USE_MODULE(security2); - * #endif - */ - #include "msc_logging.h" #include "msc_util.h" diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 261151bae9..0a6ae4d478 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -145,6 +145,9 @@ extern DSOLOCAL char *real_server_signature; extern DSOLOCAL char *chroot_dir; extern module AP_MODULE_DECLARE_DATA security2_module; +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif extern DSOLOCAL const command_rec module_directives[]; From 159cb4e93cc29f0bf7ece57d916fa07f7380fc2e Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Sat, 20 Aug 2022 15:24:37 -0700 Subject: [PATCH 267/477] Fix a failing test. --- tests/regression/misc/00-multipart-parser.t | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t index ebdadee76d..3c1f41b7d2 100644 --- a/tests/regression/misc/00-multipart-parser.t +++ b/tests/regression/misc/00-multipart-parser.t @@ -1353,15 +1353,14 @@ SecDebugLog $ENV{DEBUG_LOG} SecDebugLogLevel 9 SecRequestBodyAccess On - SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,id:500134" - SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny,id:500135" - SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,id:500136" + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:400,id:500134" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,status:400,id:500136" ), match_log => { - debug => [ qr/boundary was quoted.*No boundaries found in payload/s, 1 ], + debug => [ qr/Multipart: Warning: boundary was quoted./s, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^400$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -1370,20 +1369,20 @@ ], normalize_raw_request_data( q( - --0000 + -- 0000 Content-Disposition: form-data; name="name" Brian Rectanus - --0000 + -- 0000 Content-Disposition: form-data; name="email" brian.rectanus@breach.com - --0000 + -- 0000 Content-Disposition: form-data; name="image"; filename="image.jpg" Content-Type: image/jpeg BINARYDATA - --0000-- + -- 0000-- ), ), ), From 46c1a0d62f11d4c182b261c2d9de9f59a89d337d Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 26 Aug 2022 11:35:43 -0700 Subject: [PATCH 268/477] IIS: Update dependencies for next planned release --- CHANGES | 2 ++ iis/build_dependencies.bat | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGES b/CHANGES index 8d4ef09226..aef85e9e66 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * IIS: Update dependencies for next planned release + [Issue #2792 - @martinhsv] * XML parser cleanup: NULL duplicate pointer [Issue #2760 - @martinhsv] * Properly cleanup XML parser contexts upon completion diff --git a/iis/build_dependencies.bat b/iis/build_dependencies.bat index 7bca030183..e131cd15cd 100755 --- a/iis/build_dependencies.bat +++ b/iis/build_dependencies.bat @@ -9,13 +9,13 @@ :: Dependencies @set CMAKE=cmake-3.12.4-win32-x86.zip @set PCRE=pcre-8.45.zip -@set ZLIB=zlib-1.2.11.tar.gz -@set LIBXML2=libxml2-2.9.12.tar.gz +@set ZLIB=zlib-1.2.12.tar.gz +@set LIBXML2=libxml2-2.9.14.tar.gz @set LUA=lua-5.3.6.tar.gz -@set CURL=curl-7.79.0.zip -@set APACHE_SRC=httpd-2.4.51.tar.gz -@set APACHE_BIN32=httpd-2.4.51-win32-VS16.zip -@set APACHE_BIN64=httpd-2.4.51-win64-VS16.zip +@set CURL=curl-7.83.1.zip +@set APACHE_SRC=httpd-2.4.54.tar.gz +@set APACHE_BIN32=httpd-2.4.54-win32-VS16.zip +@set APACHE_BIN64=httpd-2.4.54-win64-VS16.zip @set YAJL=yajl-2.1.0.zip @set SSDEEP=ssdeep-2.14.1.tar.gz @set SSDEEP_BIN=ssdeep-2.14.1.zip From 592519f45d255ce4cb6ce525d0eefdb6f62a63c5 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 26 Aug 2022 11:52:13 -0700 Subject: [PATCH 269/477] Correct previous CHANGES entry --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index aef85e9e66..5fb834a815 100644 --- a/CHANGES +++ b/CHANGES @@ -2,7 +2,7 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- * IIS: Update dependencies for next planned release - [Issue #2792 - @martinhsv] + [@martinhsv] * XML parser cleanup: NULL duplicate pointer [Issue #2760 - @martinhsv] * Properly cleanup XML parser contexts upon completion From d9df7f529e51be72d2105ea4ac2911ec8b4c9246 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 6 Sep 2022 05:29:38 -0700 Subject: [PATCH 270/477] Limit rsub null termination to where necessary --- CHANGES | 2 ++ apache2/re_operators.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 5fb834a815..e8a008ea73 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Limit rsub null termination to where necessary + [Issue #2794 - @marcstern, @martinhsv] * IIS: Update dependencies for next planned release [@martinhsv] * XML parser cleanup: NULL duplicate pointer diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 7eb1bf2649..01db9ade6f 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -656,7 +656,9 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->if_stream_changed = 1; memcpy(msr->stream_input_data, data, size); +#ifndef MSC_LARGE_STREAM_INPUT msr->stream_input_data[size] = '\0'; +#endif var->value_len = size; var->value = msr->stream_input_data; From 7a489bd07c66d3df19a320b4306e00c49716dbb0 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 7 Sep 2022 11:09:47 -0700 Subject: [PATCH 271/477] Multipart parsing fixes and new MULTIPART_PART_HEADERS collection --- CHANGES | 2 + apache2/msc_multipart.c | 148 ++++++++++++++------ apache2/msc_multipart.h | 19 +++ apache2/re_variables.c | 57 ++++++++ tests/regression/misc/00-multipart-parser.t | 45 ++++++ 5 files changed, 230 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index e8a008ea73..6a9804a7da 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Multipart parsing fixes and new MULTIPART_PART_HEADERS collection + [Issue #2797 - @terjanq, @martinhsv] * Limit rsub null termination to where necessary [Issue #2794 - @marcstern, @martinhsv] * IIS: Update dependencies for next planned release diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index d087c863e1..4128ab17e1 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -325,7 +325,14 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { } msr->mpd->mpp_state = 1; + msr->mpd->mpp_substate_part_data_read = 0; msr->mpd->mpp->last_header_name = NULL; + + /* Record the last part header line in the collection */ + if (msr->mpd->mpp->last_header_line != NULL) { + *(char **)apr_array_push(msr->mpd->mpp->header_lines) = msr->mpd->mpp->last_header_line; + msr_log(msr, 9, "Multipart: Added part header line \"%s\"", msr->mpd->mpp->last_header_line); + } } else { /* Header line. */ @@ -379,12 +386,28 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { *error_msg = apr_psprintf(msr->mp, "Multipart: Part header too long."); return -1; } + if ((msr->mpd->mpp->last_header_line != NULL) && (msr->mpd->mpp->last_header_name != NULL) + && (new_value != NULL)) { + msr->mpd->mpp->last_header_line = apr_psprintf(msr->mp, + "%s: %s", msr->mpd->mpp->last_header_name, new_value); + } + } else { char *header_name, *header_value, *data; /* new header */ + /* Record the most recently-seen part header line in the collection */ + if (msr->mpd->mpp->last_header_line != NULL) { + *(char **)apr_array_push(msr->mpd->mpp->header_lines) = msr->mpd->mpp->last_header_line; + msr_log(msr, 9, "Multipart: Added part header line \"%s\"", msr->mpd->mpp->last_header_line); + } + data = msr->mpd->buf; + + msr->mpd->mpp->last_header_line = apr_pstrdup(msr->mp, data); + remove_lf_crlf_inplace(msr->mpd->mpp->last_header_line); + while((*data != ':') && (*data != '\0')) data++; if (*data == '\0') { *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (colon missing): %s.", @@ -438,6 +461,8 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; + msr->mpd->mpp_substate_part_data_read = 1; + /* Preserve some bytes for later. */ if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1) && (*(p - 1) == '\n') ) @@ -680,10 +705,14 @@ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **err if (msr->mpd->mpp == NULL) return -1; msr->mpd->mpp->type = MULTIPART_FORMDATA; msr->mpd->mpp_state = 0; + msr->mpd->mpp_substate_part_data_read = 0; msr->mpd->mpp->headers = apr_table_make(msr->mp, 10); if (msr->mpd->mpp->headers == NULL) return -1; msr->mpd->mpp->last_header_name = NULL; + msr->mpd->mpp->last_header_line = NULL; + msr->mpd->mpp->header_lines = apr_array_make(msr->mp, 2, sizeof(char *)); + if (msr->mpd->mpp->header_lines == NULL) return -1; msr->mpd->reserve[0] = 0; msr->mpd->reserve[1] = 0; @@ -983,6 +1012,19 @@ int multipart_complete(modsec_rec *msr, char **error_msg) { && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary)) == '-') && (*(msr->mpd->buf + 2 + strlen(msr->mpd->boundary) + 1) == '-') ) { + if ((msr->mpd->crlf_state_buf_end == 2) && (msr->mpd->flag_lf_line != 1)) { + msr->mpd->flag_lf_line = 1; + if (msr->mpd->flag_crlf_line) { + msr_log(msr, 4, "Multipart: Warning: mixed line endings used (CRLF/LF)."); + } else { + msr_log(msr, 4, "Multipart: Warning: incorrect line endings used (LF)."); + } + } + if (msr->mpd->mpp_substate_part_data_read == 0) { + /* it looks like the final boundary, but it's where part data should begin */ + msr->mpd->flag_invalid_part = 1; + msr_log(msr, 4, "Multipart: Warning: Invalid part (data contains final boundary)"); + } /* Looks like the final boundary - process it. */ if (multipart_process_boundary(msr, 1 /* final */, error_msg) < 0) { msr->mpd->flag_error = 1; @@ -1075,54 +1117,63 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, if ( (strlen(msr->mpd->buf) >= strlen(msr->mpd->boundary) + 2) && (strncmp(msr->mpd->buf + 2, msr->mpd->boundary, strlen(msr->mpd->boundary)) == 0) ) { - char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); - int is_final = 0; + if (msr->mpd->crlf_state_buf_end == 2) { + msr->mpd->flag_lf_line = 1; + } + if ((msr->mpd->mpp_substate_part_data_read == 0) && (msr->mpd->boundary_count > 0)) { + /* string matches our boundary, but it's where part data should begin */ + msr->mpd->flag_invalid_part = 1; + msr_log(msr, 4, "Multipart: Warning: Invalid part (data contains boundary)"); + } else { + char *boundary_end = msr->mpd->buf + 2 + strlen(msr->mpd->boundary); + int is_final = 0; + + /* Is this the final boundary? */ + if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) { + is_final = 1; + boundary_end += 2; + + if (msr->mpd->is_complete != 0) { + msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary (final duplicate)."); + return -1; + } + } - /* Is this the final boundary? */ - if ((*boundary_end == '-') && (*(boundary_end + 1)== '-')) { - is_final = 1; - boundary_end += 2; + /* Allow for CRLF and LF line endings. */ + if ( ( (*boundary_end == '\r') + && (*(boundary_end + 1) == '\n') + && (*(boundary_end + 2) == '\0') ) + || ( (*boundary_end == '\n') + && (*(boundary_end + 1) == '\0') ) ) + { + if (*boundary_end == '\n') { + msr->mpd->flag_lf_line = 1; + } else { + msr->mpd->flag_crlf_line = 1; + } - if (msr->mpd->is_complete != 0) { - msr->mpd->flag_error = 1; - *error_msg = apr_psprintf(msr->mp, - "Multipart: Invalid boundary (final duplicate)."); - return -1; - } - } + if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { + msr->mpd->flag_error = 1; + return -1; + } - /* Allow for CRLF and LF line endings. */ - if ( ( (*boundary_end == '\r') - && (*(boundary_end + 1) == '\n') - && (*(boundary_end + 2) == '\0') ) - || ( (*boundary_end == '\n') - && (*(boundary_end + 1) == '\0') ) ) - { - if (*boundary_end == '\n') { - msr->mpd->flag_lf_line = 1; - } else { - msr->mpd->flag_crlf_line = 1; - } + if (is_final) { + msr->mpd->is_complete = 1; + } - if (multipart_process_boundary(msr, (is_final ? 1 : 0), error_msg) < 0) { + processed_as_boundary = 1; + msr->mpd->boundary_count++; + } + else { + /* error */ msr->mpd->flag_error = 1; + *error_msg = apr_psprintf(msr->mp, + "Multipart: Invalid boundary: %s", + log_escape_nq(msr->mp, msr->mpd->buf)); return -1; } - - if (is_final) { - msr->mpd->is_complete = 1; - } - - processed_as_boundary = 1; - msr->mpd->boundary_count++; - } - else { - /* error */ - msr->mpd->flag_error = 1; - *error_msg = apr_psprintf(msr->mp, - "Multipart: Invalid boundary: %s", - log_escape_nq(msr->mp, msr->mpd->buf)); - return -1; } } else { /* It looks like a boundary but we couldn't match it. */ char *p = NULL; @@ -1221,6 +1272,21 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, msr->mpd->bufptr = msr->mpd->buf; msr->mpd->bufleft = MULTIPART_BUF_SIZE; msr->mpd->buf_contains_line = (c == 0x0a) ? 1 : 0; + + if (c == 0x0a) { + if (msr->mpd->crlf_state == 1) { + msr->mpd->crlf_state = 3; + } else { + msr->mpd->crlf_state = 2; + } + } + msr->mpd->crlf_state_buf_end = msr->mpd->crlf_state; + } + + if (c == 0x0d) { + msr->mpd->crlf_state = 1; + } else if (c != 0x0a) { + msr->mpd->crlf_state = 0; } if ((msr->mpd->is_complete) && (inleft != 0)) { diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h index a0f6a08ddf..13db0658f4 100644 --- a/apache2/msc_multipart.h +++ b/apache2/msc_multipart.h @@ -55,6 +55,8 @@ struct multipart_part { char *last_header_name; apr_table_t *headers; + char *last_header_line; + apr_array_header_t *header_lines; unsigned int offset; unsigned int length; @@ -81,6 +83,15 @@ struct multipart_data { char *bufptr; int bufleft; + /* line ending status seen immediately before current position. + * 0 = neither LF nor CR; 1 = prev char CR; 2 = prev char LF alone; + * 3 = prev two chars were CRLF + */ + int crlf_state; + + /* crlf_state at end of previous buffer */ + int crlf_state_buf_end; + unsigned int buf_offset; /* pointer that keeps track of a part while @@ -94,6 +105,14 @@ struct multipart_data { */ int mpp_state; + /* part parsing substate; if mpp_state is 1 (collecting + * data), then for this variable: + * 0 means we have not yet read any data between the + * post-headers blank line and the next boundary + * 1 means we have read at some data after that blank line + */ + int mpp_substate_part_data_read; + /* because of the way this parsing algorithm * works we hold back the last two bytes of * each data chunk so that we can discard it diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 4007386151..f3015acd94 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1394,6 +1394,52 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre return 1; } +/* MULTIPART_PART_HEADERS */ + +static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, + apr_table_t *vartab, apr_pool_t *mptmp) +{ + multipart_part **parts = NULL; + int i, j, count = 0; + + if (msr->mpd == NULL) return 0; + + parts = (multipart_part **)msr->mpd->parts->elts; + for(i = 0; i < msr->mpd->parts->nelts; i++) { + 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) { + for (j = 0; j < parts[i]->header_lines->nelts; j++) { + char *header_line = ((char **)parts[i]->header_lines->elts)[j]; + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = header_line; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "MULTIPART_PART_HEADERS:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } + } + + return count; +} + /* MODSEC_BUILD */ static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, @@ -2966,6 +3012,17 @@ void msre_engine_register_default_variables(msre_engine *engine) { PHASE_REQUEST_BODY ); + /* MULTIPART_PART_HEADERS */ + msre_engine_variable_register(engine, + "MULTIPART_PART_HEADERS", + VAR_LIST, + 0, 1, + var_generic_list_validate, + var_multipart_part_headers_generate, + VAR_CACHE, + PHASE_REQUEST_BODY + ); + /* GEO */ msre_engine_variable_register(engine, "GEO", diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t index 3c1f41b7d2..e5ee4c13cd 100644 --- a/tests/regression/misc/00-multipart-parser.t +++ b/tests/regression/misc/00-multipart-parser.t @@ -1849,3 +1849,48 @@ ), }, +# part headers +{ + type => "misc", + comment => "multipart parser (part headers)", + conf => qq( + SecRuleEngine On + SecDebugLog $ENV{DEBUG_LOG} + SecDebugLogLevel 9 + SecRequestBodyAccess On + SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny,status:400,id:500168" + SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,status:400,id:500169" + SecRule MULTIPART_PART_HEADERS:image "\@rx content-type:.*jpeg" "phase:2,deny,status:403,id:500170,t:lowercase" + ), + match_log => { + debug => [ qr/500170.*against MULTIPART_PART_HEADERS:image.*Rule returned 1./s, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => q(multipart/form-data; boundary=0000), + ], + normalize_raw_request_data( + q( + --0000 + Content-Disposition: form-data; name="username" + + Bill + --0000 + Content-Disposition: form-data; name="email" + + bill@fakesite.com + --0000 + Content-Disposition: form-data; name="image"; filename="image.jpg" + Content-Type: image/jpeg + + BINARYDATA + --0000-- + ), + ), + ), +}, + From bb372850ac23632ff232d3650f0b64a44a5092a3 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 7 Sep 2022 11:43:54 -0700 Subject: [PATCH 272/477] Adjust parser activation rules in modsecurity.conf-recommended --- CHANGES | 2 ++ modsecurity.conf-recommended | 6 +++--- tests/regression/rule/10-xml.t | 2 +- tests/regression/rule/15-json.t | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 6a9804a7da..b0b0d0d642 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Adjust parser activation rules in modsecurity.conf-recommended + [Issue #2799 - @terjanq, @martinhsv] * Multipart parsing fixes and new MULTIPART_PART_HEADERS collection [Issue #2797 - @terjanq, @martinhsv] * Limit rsub null termination to where necessary diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 203349ecd0..11ffbbbdfd 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -19,21 +19,21 @@ SecRequestBodyAccess On # Enable XML request body parser. # Initiate XML Processor in case of xml content-type # -SecRule REQUEST_HEADERS:Content-Type "(?:application(?:/soap\+|/)|text/)xml" \ +SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" \ "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" # Enable JSON request body parser. # Initiate JSON Processor in case of JSON content-type; change accordingly # if your application does not use 'application/json' # -SecRule REQUEST_HEADERS:Content-Type "application/json" \ +SecRule REQUEST_HEADERS:Content-Type "^application/json" \ "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" # Sample rule to enable JSON request body parser for more subtypes. # Uncomment or adapt this rule if you want to engage the JSON # Processor for "+json" subtypes # -#SecRule REQUEST_HEADERS:Content-Type "^application/.+[+]json$" \ +#SecRule REQUEST_HEADERS:Content-Type "^application/[a-z0-9.-]+[+]json" \ # "id:'200006',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" # Maximum request body size we will accept for buffering. If you support diff --git a/tests/regression/rule/10-xml.t b/tests/regression/rule/10-xml.t index ea9d6ad99a..f2632745b7 100644 --- a/tests/regression/rule/10-xml.t +++ b/tests/regression/rule/10-xml.t @@ -394,7 +394,7 @@ SecXmlExternalEntity On SecDebugLog $ENV{DEBUG_LOG} SecDebugLogLevel 9 - SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" "id:500029, \\ + SecRule REQUEST_HEADERS:Content-Type "^(?:application(?:/soap\+|/)|text/)xml" "id:500029, \\ phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345,id:500030 SecRule XML "\@validateDTD $ENV{CONF_DIR}/SoapEnvelope-bad.dtd" "id:500031 \\ diff --git a/tests/regression/rule/15-json.t b/tests/regression/rule/15-json.t index 370ebba6a9..9c17817503 100644 --- a/tests/regression/rule/15-json.t +++ b/tests/regression/rule/15-json.t @@ -236,7 +236,7 @@ SecAuditLog "$ENV{AUDIT_LOG}" SecDebugLogLevel 9 SecRequestBodyJsonDepthLimit 3 - SecRule REQUEST_HEADERS:Content-Type "application/json" \\ + SecRule REQUEST_HEADERS:Content-Type "^application/json" \\ "id:'200001',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=JSON" SecRule REQBODY_ERROR "!\@eq 0" "id:'200444',phase:2,log,deny,status:403,msg:'Failed to parse request body'" SecRule ARGS "\@streq 25" "id:'200445',phase:2,log,deny,status:403" From dfba4fd24a4e790bb4156e9347d5ec947101080d Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 7 Sep 2022 13:36:13 -0700 Subject: [PATCH 273/477] Version 2.9.6 --- CHANGES | 2 +- apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index b0b0d0d642..aecdf2f058 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -DD mmm YYYY - 2.9.x (to be released) +07 Sep 2022 - 2.9.6 ------------------- * Adjust parser activation rules in modsecurity.conf-recommended diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 5d185ab161..8905a72ac2 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "5" +#define MODSEC_VERSION_MAINT "6" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" diff --git a/iis/installer.wxs b/iis/installer.wxs index e88d9297c9..1db301954d 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.5" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.6" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> From 849cd7e8484bb5dcbc351a7a4c4060c4274fe840 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 14 Oct 2022 08:56:01 -0700 Subject: [PATCH 274/477] CHANGES: Preparing for next version --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index aecdf2f058..2491b5dd64 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +DD mmm YYYY - 2.9.x (to be released) +------------------- + + 07 Sep 2022 - 2.9.6 ------------------- From baa38ddbaf55a87afecad7a1e1760c69a2689787 Mon Sep 17 00:00:00 2001 From: Hugh McMaster <hugh.mcmaster@outlook.com> Date: Sun, 16 Oct 2022 18:09:37 +1100 Subject: [PATCH 275/477] build/find_xml.m4: Check for libxml2 via pkg-config then xml2-config Debian is taking steps to remove xml2-config in favour of pkg-config. This means ModSecurity will build without libxml2 support by default on Debian, Ubuntu and other distributions tracking Debian packages. This patch modifies build/find_xml.m4 to check for libxml2 via pkg-config, falling back to xml2-config if necessary. --- build/find_xml.m4 | 59 ++++++++++++++++++++++++++++++++--------------- configure.ac | 1 + 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/build/find_xml.m4 b/build/find_xml.m4 index 691679e467..cd410faf4d 100644 --- a/build/find_xml.m4 +++ b/build/find_xml.m4 @@ -4,21 +4,7 @@ dnl Sets: dnl LIBXML2_CFLAGS dnl LIBXML2_LIBS -LIBXML2_CONFIG="" -LIBXML2_VERSION="" -LIBXML2_CFLAGS="" -LIBXML2_CPPFLAGS="" -LIBXML2_LDADD="" -LIBXML2_LDFLAGS="" - -AC_DEFUN([CHECK_LIBXML2], -[dnl - -AC_ARG_WITH( - libxml, - [AC_HELP_STRING([--with-libxml=PATH],[Path to libxml2 prefix or config script])], - [test_paths="${with_libxml}"], - [test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr"]) +AC_DEFUN([CHECK_XML2CONFIG], [ AC_MSG_CHECKING([for libxml2 config script]) @@ -59,19 +45,56 @@ if test -n "${libxml2_path}"; then LIBXML2_LDADD="`${LIBXML2_CONFIG} --libs`" if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml LDADD: $LIBXML2_LDADD); fi - AC_MSG_CHECKING([if libxml2 is at least v2.6.29]) - libxml2_min_ver=`echo 2.6.29 | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` + AC_MSG_CHECKING([if libxml2 is at least v${LIBXML2_MIN_VERSION}]) + libxml2_min_ver=`echo ${LIBXML2_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` libxml2_ver=`echo ${LIBXML2_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'` if test "$libxml2_ver" -ge "$libxml2_min_ver"; then AC_MSG_RESULT([yes, $LIBXML2_VERSION]) else AC_MSG_RESULT([no, $LIBXML2_VERSION]) - AC_MSG_ERROR([NOTE: libxml2 library must be at least 2.6.29]) + AC_MSG_ERROR([NOTE: libxml2 library must be at least ${LIBXML2_MIN_VERSION}]) fi else AC_MSG_RESULT([no]) fi +]) + +AC_DEFUN([CHECK_LIBXML2], [ + +AC_ARG_WITH( + libxml, + [AS_HELP_STRING([--with-libxml=PATH],[Path to libxml2 prefix or config script])], + [test_paths="${with_libxml}"], + [test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr"]) + +LIBXML2_MIN_VERSION="2.6.29" +LIBXML2_PKG_NAME="libxml-2.0" +LIBXML2_CONFIG="" +LIBXML2_VERSION="" +LIBXML2_CFLAGS="" +LIBXML2_CPPFLAGS="" +LIBXML2_LDADD="" +LIBXML2_LDFLAGS="" + +if test "x${with_libxml}" != "xno"; then + if test -n "${PKG_CONFIG}"; then + AC_MSG_CHECKING([for libxml2 >= ${LIBXML2_MIN_VERSION} via pkg-config]) + if `${PKG_CONFIG} --exists "${LIBXML2_PKG_NAME} >= ${LIBXML2_MIN_VERSION}"`; then + LIBXML2_VERSION="`${PKG_CONFIG} --modversion ${LIBXML2_PKG_NAME}`" + LIBXML2_CFLAGS="`${PKG_CONFIG} --cflags ${LIBXML2_PKG_NAME}`" + LIBXML2_LDADD="`${PKG_CONFIG} --libs-only-l ${LIBXML2_PKG_NAME}`" + LIBXML2_LDFLAGS="`${PKG_CONFIG} --libs-only-L --libs-only-other ${LIBXML2_PKG_NAME}`" + AC_MSG_RESULT([found version ${LIBXML2_VERSION}]) + else + AC_MSG_RESULT([not found]) + fi + fi + + if test -z "${LIBXML2_VERSION}"; then + CHECK_XML2CONFIG + fi +fi AC_SUBST(LIBXML2_CONFIG) AC_SUBST(LIBXML2_VERSION) diff --git a/configure.ac b/configure.ac index 01d2fb4b81..5edd23d5e3 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ AC_PROG_MAKE_SET AC_PROG_GREP AC_PATH_PROGS(PERL, [perl perl5], ) AC_PATH_PROGS(ENV_CMD, [env printenv], ) +PKG_PROG_PKG_CONFIG # Checks for header files. AC_HEADER_STDC From 8fc0b519b7a6c023259753a21f33bf3649a25b14 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 8 Nov 2022 08:06:39 -0800 Subject: [PATCH 276/477] Support for PCRE2 --- CHANGES | 2 + apache2/Makefile.am | 13 +++- apache2/apache2_config.c | 6 +- apache2/mod_security2.c | 15 ++++- apache2/modsecurity.c | 6 +- apache2/msc_crypt.c | 42 +++++++++++- apache2/msc_pcre.c | 130 ++++++++++++++++++++++++++++++++++-- apache2/msc_pcre.h | 16 ++++- apache2/msc_status_engine.c | 7 +- apache2/re_operators.c | 128 +++++++++++++++++++++++++++++++---- apache2/re_variables.c | 13 +++- build/find_pcre.m4 | 1 - build/find_pcre2.m4 | 87 ++++++++++++++++++++++++ configure.ac | 1 + 14 files changed, 438 insertions(+), 29 deletions(-) create mode 100644 build/find_pcre2.m4 diff --git a/CHANGES b/CHANGES index 2491b5dd64..69dd8d8732 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Support for PCRE2 + [Issue #2737, #2827 - @martinhsv] 07 Sep 2022 - 2.9.6 ------------------- diff --git a/apache2/Makefile.am b/apache2/Makefile.am index e7bf787bdc..9af9633a30 100644 --- a/apache2/Makefile.am +++ b/apache2/Makefile.am @@ -42,6 +42,7 @@ mod_security2_la_CFLAGS = @APR_CFLAGS@ \ @LUA_CFLAGS@ \ @MODSEC_EXTRA_CFLAGS@ \ @PCRE_CFLAGS@ \ + @PCRE2_CFLAGS@ \ @YAJL_CFLAGS@ \ @SSDEEP_CFLAGS@ @@ -50,7 +51,8 @@ mod_security2_la_CPPFLAGS = @APR_CPPFLAGS@ \ @CURL_CPPFLAGS@ \ @LIBXML2_CFLAGS@ \ @LIBXML2_CPPFLAGS@ \ - @PCRE_CPPFLAGS@ + @PCRE_CPPFLAGS@ \ + @PCRE2_CPPFLAGS@ mod_security2_la_LIBADD = @APR_LDADD@ \ @APU_LDADD@ \ @@ -59,6 +61,7 @@ mod_security2_la_LIBADD = @APR_LDADD@ \ @LIBXML2_LDADD@ \ @LUA_LDADD@ \ @PCRE_LDADD@ \ + @PCRE2_LDADD@ \ @YAJL_LDADD@ if AIX @@ -71,6 +74,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -85,6 +89,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -99,6 +104,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -113,6 +119,7 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -127,6 +134,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -141,6 +149,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -155,6 +164,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif @@ -169,6 +179,7 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ endif diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 4ea098f3cc..9cc93f5d99 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -1293,7 +1293,11 @@ static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, { directory_config *dcfg = _dcfg; +#ifdef WITH_PCRE2 + dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE2_DOTALL, NULL, NULL); +#else dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL); +#endif if (dcfg->auditlog_relevant_regex == NULL) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); } diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 7bb215e2ed..d85626fbc7 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -107,6 +107,8 @@ static int server_limit, thread_limit; */ static void version(apr_pool_t *mp) { char *pcre_vrs = NULL; + char *pcre_loaded_vrs = NULL; + char pcre2_loaded_vrs_buffer[80] ={0}; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "ModSecurity: APR compiled version=\"%s\"; " @@ -116,13 +118,20 @@ static void version(apr_pool_t *mp) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded APR do not match with compiled!"); } +#ifdef WITH_PCRE2 + pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE2_MAJOR, PCRE2_MINOR); + pcre_loaded_vrs = pcre2_loaded_vrs_buffer; + pcre2_config(PCRE2_CONFIG_VERSION, pcre_loaded_vrs); +#else pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE_MAJOR, PCRE_MINOR); + pcre_loaded_vrs = pcre_version(); +#endif ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "ModSecurity: PCRE compiled version=\"%s\"; " - "loaded version=\"%s\"", pcre_vrs, pcre_version()); + "loaded version=\"%s\"", pcre_vrs, pcre_loaded_vrs); - if (strstr(pcre_version(),pcre_vrs) == NULL) { + if (strstr(pcre_loaded_vrs,pcre_vrs) == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded PCRE do not match with compiled!"); } diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 2a37e4976a..4805de960b 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -561,7 +561,11 @@ static int is_response_status_relevant(modsec_rec *msr, int status) { rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg); if (rc >= 0) return 1; +#ifdef WITH_PCRE2 + if (rc == PCRE2_ERROR_NOMATCH) return 0; +#else if (rc == PCRE_ERROR_NOMATCH) return 0; +#endif msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg); diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index dff2234a64..3fe18c78b4 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ - * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -386,7 +386,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { case HASH_URL_HREF_HASH_RX: if(em[i]->type == HASH_URL_HREF_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -415,7 +419,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif return 1; } } @@ -441,7 +449,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { case HASH_URL_FACTION_HASH_RX: if(em[i]->type == HASH_URL_FACTION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -470,7 +482,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif return 1; } } @@ -496,7 +512,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { case HASH_URL_LOCATION_HASH_RX: if(em[i]->type == HASH_URL_LOCATION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -525,7 +545,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif return 1; } } @@ -551,7 +575,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { case HASH_URL_IFRAMESRC_HASH_RX: if(em[i]->type == HASH_URL_IFRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -580,7 +608,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif return 1; } } @@ -606,7 +638,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { case HASH_URL_FRAMESRC_HASH_RX: if(em[i]->type == HASH_URL_FRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -635,7 +671,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif return 1; } } diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 8534a20914..ef9aa0f894 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -20,6 +20,16 @@ */ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { if (regex != NULL) { +#ifdef WITH_PCRE2 + if (regex->match_context != NULL) { + pcre2_match_context_free(regex->match_context); + regex->match_context = NULL; + } + if (regex->re != NULL) { + pcre2_code_free(regex->re); + regex->re = NULL; + } +#else if (regex->pe != NULL) { #if defined(VERSION_NGINX) pcre_free(regex->pe); @@ -32,6 +42,7 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { pcre_free(regex->re); regex->re = NULL; } +#endif } return APR_SUCCESS; @@ -48,6 +59,78 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, const char **_errptr, int *_erroffset, int match_limit, int match_limit_recursion) +#ifdef WITH_PCRE2 +{ + msc_regex_t *regex = NULL; + PCRE2_SPTR pcre2_pattern; + uint32_t pcre2_options; + int error_number = 0; + PCRE2_SIZE error_offset = 0; + pcre2_match_context *match_context = NULL; + + regex = apr_pcalloc(pool, sizeof(msc_regex_t)); + if (regex == NULL) return NULL; + regex->pattern = pattern; + + pcre2_pattern = (PCRE2_SPTR)pattern; + pcre2_options = (uint32_t)options; + + regex->re = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED, + pcre2_options, &error_number, &error_offset, NULL); + if (regex->re == NULL) { + if (_erroffset != NULL) { + *_erroffset = (int)error_offset; + } + return NULL; + } + + /* TODO: Add PCRE2 JIT support */ + + /* Setup the pcre2 match context */ + regex->match_context = NULL; + match_context = pcre2_match_context_create(NULL); + if (match_context == NULL) { + return NULL; + } + + /* Prefer the match limit passed as an arg; else use compilation default */ + { + uint32_t final_match_limit = 0; + if (match_limit > 0) { + final_match_limit = match_limit; + pcre2_set_match_limit(match_context, final_match_limit); + } +#ifdef MODSEC_PCRE_MATCH_LIMIT + else { + final_match_limit = MODSEC_PCRE_MATCH_LIMIT; + pcre2_set_match_limit(match_context, final_match_limit); + } +#endif /* MODSEC_PCRE_MATCH_LIMIT */ + } + + /* Prefer the depth limit passed as an arg; else use compilation default */ + { + uint32_t final_match_limit_recursion = 0; + if (match_limit_recursion > 0) { + final_match_limit_recursion = match_limit_recursion; + pcre2_set_depth_limit(match_context, final_match_limit_recursion); + } +#ifdef MODSEC_PCRE_MATCH_LIMIT_RECURSION + else { + final_match_limit_recursion = MODSEC_PCRE_MATCH_LIMIT_RECURSION; + pcre2_set_depth_limit(match_context, final_match_limit_recursion); + } +#endif /* MODSEC_PCRE_MATCH_LIMIT_RECURSION */ + } + + regex->match_context = match_context; + + apr_pool_cleanup_register(pool, (void *)regex, + (apr_status_t (*)(void *))msc_pcre_cleanup, apr_pool_cleanup_null); + + return regex; +} +#else /* not WITH_PCRE2 */ { const char *errptr = NULL; int erroffset; @@ -131,6 +214,7 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, return regex; } +#endif /* WITH_PCRE2 */ /** * Compiles the provided regular expression pattern. Calls msc_pregcomp_ex() @@ -143,9 +227,9 @@ void *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options, } /** - * Executes regular expression with extended options. - * Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1 - * on errors, and a value > 0 when there is a match. + * Executes regular expression with extended options (or match context) + * Returns PCRE_ERROR_NOMATCH (or PCRE2_ERROR_NOMATCH), + * error code < -1 on errors, and a value > 0 when there is a match. */ int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, int startoffset, int options, int *ovector, int ovecsize, char **error_msg) @@ -153,7 +237,41 @@ int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */ *error_msg = NULL; +#ifdef WITH_PCRE2 + { + PCRE2_SPTR pcre2_s; + int pcre2_ret; + pcre2_match_data *match_data; + PCRE2_SIZE *pcre2_ovector = NULL; + + pcre2_s = (PCRE2_SPTR)s; + match_data = pcre2_match_data_create_from_pattern(regex->re, NULL); + + pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + (PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context); + if (match_data != NULL) { + if (ovector != NULL) { + pcre2_ovector = pcre2_get_ovector_pointer(match_data); + if (pcre2_ovector != NULL) { + for (int i = 0; ((i < pcre2_ret) && ((i*2) <= ovecsize)); i++) { + if ((i*2) < ovecsize) { + ovector[2*i] = pcre2_ovector[2*i]; + ovector[2*i+1] = pcre2_ovector[2*i+1]; + } + } + } + } + pcre2_match_data_free(match_data); + } + if ((pcre2_ret*2) > ovecsize) { + return 0; + } else { + return pcre2_ret; + } + } +#else return pcre_exec(regex->re, regex->pe, s, slen, startoffset, options, ovector, ovecsize); +#endif } /** @@ -188,6 +306,10 @@ int msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen, */ int msc_fullinfo(msc_regex_t *regex, int what, void *where) { +#ifdef WITH_PCRE2 + return pcre2_pattern_info(regex->re, (uint32_t)what, where); +#else return pcre_fullinfo(regex->re, regex->pe, what, where); +#endif } diff --git a/apache2/msc_pcre.h b/apache2/msc_pcre.h index bbaa818b29..4871c1f8fa 100644 --- a/apache2/msc_pcre.h +++ b/apache2/msc_pcre.h @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -17,7 +17,14 @@ typedef struct msc_regex_t msc_regex_t; +#ifdef WITH_PCRE2 +#define PCRE2_CODE_UNIT_WIDTH 8 +#include "pcre2.h" +#else #include "pcre.h" +#endif + +#ifndef WITH_PCRE2 #ifndef PCRE_ERROR_MATCHLIMIT /* Define for compile, but not valid in this version of PCRE. */ @@ -29,12 +36,19 @@ typedef struct msc_regex_t msc_regex_t; #define PCRE_ERROR_RECURSIONLIMIT (-21) #endif /* PCRE_ERROR_RECURSIONLIMIT */ +#endif + #include "apr_general.h" #include "modsecurity.h" struct msc_regex_t { +#ifdef WITH_PCRE2 + pcre2_code *re; + pcre2_match_context *match_context; +#else void *re; void *pe; +#endif const char *pattern; }; diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 3ee6c686c1..00165bd7a5 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -345,8 +345,13 @@ int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len) apr = APR_VERSION_STRING; apr_loaded = apr_version_string(); +#ifdef WITH_PCRE2 + apr_snprintf(pcre, 7, "%d.%d", PCRE2_MAJOR, PCRE2_MINOR); + pcre_loaded = ""; /* complete this if/when status reactivated */ +#else apr_snprintf(pcre, 7, "%d.%d", PCRE_MAJOR, PCRE_MINOR); pcre_loaded = pcre_version(); +#endif #ifdef WITH_LUA lua = LUA_VERSION; #endif diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 01db9ade6f..9217ad7923 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -697,7 +697,12 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { /* Compile pattern */ if(strstr(pattern,"%{") == NULL) { - regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); +#ifdef WITH_PCRE2 + int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; +#else + int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; +#endif + regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -747,6 +752,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v const char *target; const char *errptr = NULL; int erroffset; + int options = 0; unsigned int target_length; char *my_error_msg = NULL; int ovector[33]; @@ -786,7 +792,12 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v msr_log(msr, 6, "Escaping pattern [%s]",pattern); } - regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; +#else + options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; +#endif + regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", @@ -831,7 +842,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v * and no memory has to be allocated for any backreferences. */ rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -861,7 +876,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v return -1; } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif /* We no longer escape the pattern here as it is done when logging */ char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); char *hmac = NULL, *valid = NULL; @@ -940,7 +959,12 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { /* Compile pattern */ if(strstr(pattern,"%{") == NULL) { - regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); +#ifdef WITH_PCRE2 + int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; +#else + int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; +#endif + regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -979,6 +1003,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c const char *target; const char *errptr = NULL; int erroffset; + int options = 0; unsigned int target_length; char *my_error_msg = NULL; int ovector[33]; @@ -1020,7 +1045,12 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msr_log(msr, 6, "Escaping pattern [%s]",pattern); } - regex = msc_pregcomp_ex(msr->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; +#else + options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; +#endif + regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -1075,7 +1105,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c /* Show when the regex captures but "capture" is not set */ if (msr->txcfg->debuglog_level >= 6) { int capcount = 0; +#ifdef WITH_PCRE2 + rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); +#else rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); +#endif if (msr->txcfg->debuglog_level >= 6) { if ((capture == 0) && (capcount > 0)) { msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); @@ -1087,7 +1121,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c * and no memory has to be allocated for any backreferences. */ rc = msc_regexec_capture(regex, target, target_length, ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { +#else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { +#endif msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -1178,7 +1216,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c } } +#ifdef WITH_PCRE2 + if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ +#else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ +#endif /* We no longer escape the pattern here as it is done when logging */ char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); @@ -1623,13 +1665,19 @@ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { const char *errptr = NULL; int erroffset; + int options = 0; msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; /* Compile rule->op_param */ - regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_MULTILINE; +#else + options = PCRE_DOTALL | PCRE_MULTILINE; +#endif + regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", @@ -1659,6 +1707,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var char *my_error_msg = NULL; int ovector[33]; unsigned int offset = 0; + int options = 0; gsb_db *gsb = msr->txcfg->gsb; const char *match = NULL; unsigned int match_length; @@ -1697,7 +1746,12 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var memcpy(data,var->value,var->value_len); - while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg)) >= 0) +#ifdef WITH_PCRE2 + options = PCRE2_NOTEMPTY; +#else + options = PCRE_NOTEMPTY; +#endif + while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, options, ovector, 30, &my_error_msg)) >= 0) { for(i = 0; i < rv; ++i) { @@ -2731,13 +2785,19 @@ static int luhn_verify(const char *ccnumber, int len) { static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { const char *errptr = NULL; int erroffset; + int options = 0; msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_MULTILINE; +#else + options = PCRE_DOTALL | PCRE_MULTILINE; +#endif /* Compile rule->op_param */ - regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -2758,6 +2818,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * int rc; int is_cc = 0; int offset; + int options = 0; int matched_bytes = 0; char *qspos = NULL; const char *parm = NULL; @@ -2817,10 +2878,19 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * } } - rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + options = PCRE2_NOTEMPTY; +#else + options = PCRE_NOTEMPTY; +#endif + rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg); /* If there was no match, then we are done. */ +#ifdef WITH_PCRE2 + if (rc == PCRE2_ERROR_NOMATCH) { +#else if (rc == PCRE_ERROR_NOMATCH) { +#endif break; } @@ -3029,13 +3099,19 @@ static int cpf_verify(const char *cpfnumber, int len) { static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { const char *errptr = NULL; int erroffset; + int options = 0; msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_MULTILINE; +#else + options = PCRE_DOTALL | PCRE_MULTILINE; +#endif /* Compile rule->op_param */ - regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -3068,6 +3144,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var int rc; int is_cpf = 0; int offset; + int options = 0; int matched_bytes = 0; char *qspos = NULL; const char *parm = NULL; @@ -3127,10 +3204,19 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var } } - rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + options = PCRE2_NOTEMPTY; +#else + options = PCRE_NOTEMPTY; +#endif + rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg); /* If there was no match, then we are done. */ +#ifdef WITH_PCRE2 + if (rc == PCRE2_ERROR_NOMATCH) { +#else if (rc == PCRE_ERROR_NOMATCH) { +#endif break; } @@ -3323,13 +3409,19 @@ static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) { static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { const char *errptr = NULL; int erroffset; + int options = 0; msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_MULTILINE; +#else + options = PCRE_DOTALL | PCRE_MULTILINE; +#endif /* Compile rule->op_param */ - regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, PCRE_DOTALL | PCRE_MULTILINE, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); @@ -3362,6 +3454,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var int rc; int is_ssn = 0; int offset; + int options = 0; int matched_bytes = 0; char *qspos = NULL; const char *parm = NULL; @@ -3421,10 +3514,19 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var } } - rc = msc_regexec_ex(regex, target, target_length, offset, PCRE_NOTEMPTY, ovector, 30, &my_error_msg); +#ifdef WITH_PCRE2 + options = PCRE2_NOTEMPTY; +#else + options = PCRE_NOTEMPTY; +#endif + rc = msc_regexec_ex(regex, target, target_length, offset, options, ovector, 30, &my_error_msg); /* If there was no match, then we are done. */ +#ifdef WITH_PCRE2 + if (rc == PCRE2_ERROR_NOMATCH) { +#else if (rc == PCRE_ERROR_NOMATCH) { +#endif break; } diff --git a/apache2/re_variables.c b/apache2/re_variables.c index f3015acd94..c97466ba7d 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -21,6 +21,9 @@ #include "libxml/xpathInternals.h" +#ifdef WITH_PCRE2 +#define PCRE_ERROR_NOMATCH PCRE2_ERROR_NOMATCH +#endif /** * Generates a variable from a string and a length. */ @@ -64,12 +67,18 @@ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { msc_regex_t *regex = NULL; const char *errptr = NULL; const char *pattern = NULL; + int options = 0; int erroffset; pattern = apr_pstrmemdup(ruleset->mp, var->param + 1, strlen(var->param + 1) - 1); if (pattern == NULL) return FATAL_ERROR; - regex = msc_pregcomp(ruleset->mp, pattern, PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset); +#ifdef WITH_PCRE2 + options = PCRE2_DOTALL | PCRE2_CASELESS | PCRE2_DOLLAR_ENDONLY; +#else + options = PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY; +#endif + regex = msc_pregcomp(ruleset->mp, pattern, options, &errptr, &erroffset); if (regex == NULL) { return apr_psprintf(ruleset->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index f5da40a327..0c42fed60a 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -82,7 +82,6 @@ AC_SUBST(PCRE_LD_PATH) if test -z "${PCRE_VERSION}"; then AC_MSG_NOTICE([*** pcre library not found.]) - ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2) else AC_MSG_NOTICE([using pcre v${PCRE_VERSION}]) ifelse([$1], , , $1) diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 new file mode 100644 index 0000000000..36196bdaeb --- /dev/null +++ b/build/find_pcre2.m4 @@ -0,0 +1,87 @@ +dnl Check for PCRE2 Libraries +dnl CHECK_PCRE2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Sets: +dnl PCRE2_CFLAGS +dnl PCRE2_LIBS + +PCRE2_CONFIG="" +PCRE2_VERSION="" +PCRE2_CPPFLAGS="" +PCRE2_CFLAGS="" +PCRE2_LDFLAGS="" +PCRE2_LDADD="" +PCRE_LD_PATH="" + +AC_DEFUN([CHECK_PCRE2], +[dnl + +AC_ARG_WITH( + pcre2, + [AC_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])], + , with_pcre2=yes) + +AS_CASE(["${with_pcre2}"], + [no], [test_paths=], + [yes], [test_paths="/usr/local/libpcre2 /usr/local/pcre2 /usr/local /opt/libpcre2 /opt/pcre2 /opt /usr"], + [test_paths="${with_pcre2}"]) + +AC_MSG_CHECKING([for libpcre2 config script]) + +for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + PCRE2_CONFIG=$x + pcre2_path="no" + break + fi + + dnl # Try known config script names/locations + for PCRE2_CONFIG in pcre2-config; do + if test -e "${x}/bin/${PCRE2_CONFIG}"; then + pcre2_path="${x}/bin" + break + elif test -e "${x}/${PCRE2_CONFIG}"; then + pcre2_path="${x}" + break + else + pcre2_path="" + fi + done + if test -n "$pcre2_path"; then + break + fi +done + +if test -n "${pcre2_path}"; then + if test "${pcre2_path}" != "no"; then + PCRE2_CONFIG="${pcre2_path}/${PCRE2_CONFIG}" + fi + AC_MSG_RESULT([${PCRE2_CONFIG}]) + PCRE2_VERSION="`${PCRE2_CONFIG} --version`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 VERSION: $PCRE2_VERSION); fi + PCRE2_CFLAGS="`${PCRE2_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 CFLAGS: $PCRE2_CFLAGS); fi + PCRE2_LDADD="`${PCRE2_CONFIG} --libs8`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 LDADD: $PCRE2_LDADD); fi + PCRE_LD_PATH="/`${PCRE2_CONFIG} --libs8 | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 PCRE_LD_PATH: $PCRE_LD_PATH); fi +else + AC_MSG_RESULT([no]) +fi + +AC_SUBST(PCRE2_CONFIG) +AC_SUBST(PCRE2_VERSION) +AC_SUBST(PCRE2_CPPFLAGS) +AC_SUBST(PCRE2_CFLAGS) +AC_SUBST(PCRE2_LDFLAGS) +AC_SUBST(PCRE2_LDADD) +AC_SUBST(PCRE_LD_PATH) + +if test -z "${PCRE2_VERSION}"; then + AC_MSG_NOTICE([*** pcre2 library not found.]) +else + AC_MSG_NOTICE([using pcre2 v${PCRE2_VERSION}]) + PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}" + ifelse([$1], , , $1) +fi +]) diff --git a/configure.ac b/configure.ac index 01d2fb4b81..2ddbc0f274 100644 --- a/configure.ac +++ b/configure.ac @@ -865,6 +865,7 @@ AC_SUBST(APXS_MODULES) AC_SUBST(APXS_HTTPD) CHECK_PCRE() +CHECK_PCRE2() if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then CHECK_APR() CHECK_APU() From 9c8f8f03d7347abec3718d3fb48838f29e382d18 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 8 Nov 2022 13:04:27 -0800 Subject: [PATCH 277/477] Support for PCRE2 in mlogc --- CHANGES | 4 +++- mlogc/Makefile.am | 10 +++++--- mlogc/mlogc.c | 61 +++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/CHANGES b/CHANGES index 69dd8d8732..46f535315e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,8 +1,10 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- - * Support for PCRE2 + * Support for PCRE2 in mlogc [Issue #2737, #2827 - @martinhsv] + * Support for PCRE2 + [Issue #2737 - @martinhsv] 07 Sep 2022 - 2.9.6 ------------------- diff --git a/mlogc/Makefile.am b/mlogc/Makefile.am index e84e3de504..6946ca492e 100644 --- a/mlogc/Makefile.am +++ b/mlogc/Makefile.am @@ -7,17 +7,21 @@ mlogc_SOURCES = mlogc.c mlogc_CPPFLAGS = @APR_CPPFLAGS@ \ @PCRE_CPPFLAGS@ \ + @PCRE2_CPPFLAGS@ \ @CURL_CPPFLAGS@ \ -I$(top_srcdir)/apache2 mlogc_CFLAGS = @APR_CFLAGS@ \ @CURL_CFLAGS@ \ - @PCRE_CFLAGS@ + @PCRE_CFLAGS@ \ + @PCRE2_CFLAGS@ mlogc_LDFLAGS = @APR_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @PCRE_LDFLAGS@ + @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ mlogc_LDADD = @APR_LDADD@ \ @CURL_LDADD@ \ - @PCRE_LDADD@ + @PCRE_LDADD@ \ + @PCRE2_LDADD@ diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c index ab0c06530a..b1030ee45e 100644 --- a/mlogc/mlogc.c +++ b/mlogc/mlogc.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -28,7 +28,12 @@ #if APR_HAVE_UNISTD_H #include <unistd.h> /* for getpid() */ #endif +#ifdef WITH_PCRE2 +#define PCRE2_CODE_UNIT_WIDTH 8 +#include <pcre2.h> +#else #include <pcre.h> +#endif #include <curl/curl.h> #include <fcntl.h> #include <sys/stat.h> @@ -147,7 +152,13 @@ static int keep_alive = 150; /* Not used yet. */ static int keep_alive_timeout = 300; /* Not used yet. */ static int keep_entries = 0; static const char *log_repository = NULL; +#ifdef WITH_PCRE2 +static pcre2_code *logline_regex = NULL; +static pcre2_code *requestline_regex = NULL; +#else static void *logline_regex = NULL; +static void *requestline_regex = NULL; +#endif static int max_connections = 10; static int max_worker_requests = 1000; static apr_global_mutex_t *gmutex = NULL; @@ -161,7 +172,6 @@ static int ssl_validation = 0; static int tlsprotocol = 1; static curl_version_info_data* curlversion = NULL; /* static apr_time_t queue_time = 0; */ -static void *requestline_regex = NULL; static int running = 0; static const char *sensor_password = NULL; static const char *sensor_username = NULL; @@ -1208,6 +1218,10 @@ static void logc_init(void) int i, erroffset; /* cURL major, minor and patch version */ short cmaj, cmin, cpat = 0; +#ifdef WITH_PCRE2 + int pcre2_errorcode = 0; + PCRE2_SIZE pcre2_erroffset = 0; +#endif queue = apr_array_make(pool, 64, sizeof(entry_t *)); if (queue == NULL) { @@ -1311,16 +1325,26 @@ static void logc_init(void) error_log(LOG_DEBUG2, NULL, "TLSv1.2 is unsupported in cURL %d.%d.%d", cmaj, cmin, cpat); } +#ifdef WITH_PCRE2 + logline_regex = pcre2_compile(logline_pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, + &pcre2_errorcode, &pcre2_erroffset, NULL); +#else logline_regex = pcre_compile(logline_pattern, PCRE_CASELESS, &errptr, &erroffset, NULL); +#endif if (logline_regex == NULL) { error_log(LOG_ERROR, NULL, "Failed to compile pattern: %s\n", logline_pattern); logc_shutdown(1); } - requestline_regex = pcre_compile(requestline_pattern, - PCRE_CASELESS, &errptr, &erroffset, NULL); +#ifdef WITH_PCRE2 + requestline_regex = pcre2_compile(requestline_pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, + &pcre2_errorcode, &pcre2_erroffset, NULL); +#else + requestline_regex = pcre_compile(requestline_pattern, PCRE_CASELESS, + &errptr, &erroffset, NULL); +#endif if (requestline_regex == NULL) { error_log(LOG_ERROR, NULL, "Failed to compile pattern: %s\n", requestline_pattern); @@ -1431,6 +1455,9 @@ static void * APR_THREAD_FUNC thread_worker(apr_thread_t *thread, void *data) apr_status_t rc; apr_finfo_t finfo; int capturevector[CAPTUREVECTORSIZE]; +#ifdef WITH_PCRE2 + pcre2_match_data *pcre2_match_data = NULL; +#endif int take_new = 1; apr_pool_t *tpool; struct curl_slist *headerlist = NULL; @@ -1536,9 +1563,24 @@ static void * APR_THREAD_FUNC thread_worker(apr_thread_t *thread, void *data) num_requests++; } +#ifdef WITH_PCRE2 + pcre2_match_data = pcre2_match_data_create_from_pattern(logline_regex, NULL); + rc = pcre2_match(logline_regex, entry->line, entry->line_size, 0, 0, + pcre2_match_data, NULL); + if (rc > 0) { + PCRE2_SIZE *pcre2_ovector = pcre2_get_ovector_pointer(pcre2_match_data); + for (int i = 0; i < rc; i++) { + capturevector[2*i] = pcre2_ovector[2*i]; + capturevector[2*i+1] = pcre2_ovector[2*i+1]; + } + } + pcre2_match_data_free(pcre2_match_data); + if (rc == PCRE2_ERROR_NOMATCH) { +#else rc = pcre_exec(logline_regex, NULL, entry->line, entry->line_size, 0, 0, capturevector, CAPTUREVECTORSIZE); - if (rc == PCRE_ERROR_NOMATCH) { /* No match. */ + if (rc == PCRE_ERROR_NOMATCH) { +#endif error_log(LOG_WARNING, thread, "Invalid entry (failed to match regex): %s", _log_escape(tpool, entry->line, entry->line_size)); @@ -2292,6 +2334,11 @@ static void usage(void) { * Version text. */ static void version(void) { +#ifdef WITH_PCRE2 + char pcre2_loaded_version_buffer[80] ={0}; + char *pcre_loaded_version = pcre2_loaded_version_buffer; + pcre2_config(PCRE2_CONFIG_VERSION, pcre_loaded_version); +#endif fprintf(stderr, "ModSecurity Log Collector (mlogc) v%s\n", VERSION); fprintf(stderr, @@ -2299,7 +2346,11 @@ static void version(void) { "loaded=\"%s\"\n", APR_VERSION_STRING, apr_version_string()); fprintf(stderr, " PCRE: compiled=\"%d.%d\"; " +#ifdef WITH_PCRE2 + "loaded=\"%s\"\n", PCRE2_MAJOR, PCRE2_MINOR, pcre_loaded_version); +#else "loaded=\"%s\"\n", PCRE_MAJOR, PCRE_MINOR, pcre_version()); +#endif fprintf(stderr, " cURL: compiled=\"%s\"; " "loaded=\"%s\"\n", LIBCURL_VERSION, curl_version()); From e0ef1468700ff63f4b9148235ef01b7d0fab913e Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 11 Nov 2022 14:00:20 -0800 Subject: [PATCH 278/477] Add CHANGES entry for previous PR --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 46f535315e..bcce342c4b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Use pkg-config to find libxml2 first + [Issue #2818 - @hughmcmaster] * Support for PCRE2 in mlogc [Issue #2737, #2827 - @martinhsv] * Support for PCRE2 From 3bd5836fef57de3eb0a06cf26d9bbc03a1d21978 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 14 Nov 2022 11:48:21 -0800 Subject: [PATCH 279/477] Add CHANGES entry for previous PR --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index bcce342c4b..764efa4f19 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Mark apache error log messages as from mod_security2 + [Issue #2781 - @erkia] * Use pkg-config to find libxml2 first [Issue #2818 - @hughmcmaster] * Support for PCRE2 in mlogc From b5130acb4548ace418214c728cde5f7a0dab224b Mon Sep 17 00:00:00 2001 From: Erki Aring <erki@example.ee> Date: Tue, 15 Nov 2022 17:31:18 +0200 Subject: [PATCH 280/477] Move APLOG_USE_MODULE out of modsecurity.h --- apache2/apache2_config.c | 3 +++ apache2/apache2_io.c | 4 ++++ apache2/apache2_util.c | 4 ++++ apache2/mod_security2.c | 4 ++++ apache2/modsecurity.c | 4 ++++ apache2/modsecurity.h | 3 --- apache2/msc_status_engine.c | 5 ++++- apache2/re.c | 4 ++++ 8 files changed, 27 insertions(+), 4 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 9cc93f5d99..69612f9575 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -26,6 +26,9 @@ #include "msc_lua.h" #endif +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif /* -- Directory context creation and initialisation -- */ diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index f6c785e8d2..6490d61b5d 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -18,6 +18,10 @@ #include "apache2.h" #include "msc_crypt.h" +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + /* -- Input filter -- */ #if 0 diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index 24bba0cee9..cdae2b5808 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -17,6 +17,10 @@ #include "http_core.h" #include "util_script.h" +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + /** * Sends a brigade with an error bucket down the filter chain. */ diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 221d75399a..4a0df82789 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -46,6 +46,10 @@ #include <yajl/yajl_version.h> #endif /* WITH_YAJL */ +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + /* ModSecurity structure */ msc_engine DSOLOCAL *modsecurity = NULL; diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 4805de960b..af5294668b 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -27,6 +27,10 @@ #include <curl/curl.h> #endif +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + unsigned long int DSOLOCAL unicode_codepage = 0; int DSOLOCAL *unicode_map_table = NULL; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 0a6ae4d478..261151bae9 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -145,9 +145,6 @@ extern DSOLOCAL char *real_server_signature; extern DSOLOCAL char *chroot_dir; extern module AP_MODULE_DECLARE_DATA security2_module; -#ifdef APLOG_USE_MODULE - APLOG_USE_MODULE(security2); -#endif extern DSOLOCAL const command_rec module_directives[]; diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 00165bd7a5..4587641641 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -45,6 +45,10 @@ #include <sys/utsname.h> #endif +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + // Bese32 encode, based on: // https://code.google.com/p/google-authenticator/source/browse/libpam/base32.c int DSOLOCAL msc_status_engine_base32_encode(char *encoded, @@ -504,4 +508,3 @@ int msc_status_engine_call (void) { return ret; } - diff --git a/apache2/re.c b/apache2/re.c index 64a2a6abe5..9ded3be796 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -20,6 +20,10 @@ #include "msc_lua.h" #endif +#ifdef APLOG_USE_MODULE + APLOG_USE_MODULE(security2); +#endif + static const char *const severities[] = { "EMERGENCY", "ALERT", From c291a8c9fb7241335e333aa4a7dc84a2b8e746c1 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 15 Nov 2022 14:22:03 -0800 Subject: [PATCH 281/477] Add CHANGES entry for last PR --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 764efa4f19..eb7e69e90f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Adjustment of previous fix for log messages + [Issue #2832 - @marcstern, @erkia] * Mark apache error log messages as from mod_security2 [Issue #2781 - @erkia] * Use pkg-config to find libxml2 first From f9bb518be5ec945f3651fa5582ca24a0b454d521 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 16 Nov 2022 08:39:22 -0800 Subject: [PATCH 282/477] Only check for pcre2 install if required --- CHANGES | 2 + build/find_pcre2.m4 | 106 +++++++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/CHANGES b/CHANGES index eb7e69e90f..6074a4f53b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Only check for pcre2 install if required + [Issue #2833 - @martinhsv] * Adjustment of previous fix for log messages [Issue #2832 - @marcstern, @erkia] * Mark apache error log messages as from mod_security2 diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 index 36196bdaeb..11e9890f98 100644 --- a/build/find_pcre2.m4 +++ b/build/find_pcre2.m4 @@ -18,70 +18,76 @@ AC_DEFUN([CHECK_PCRE2], AC_ARG_WITH( pcre2, [AC_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])], - , with_pcre2=yes) + , with_pcre2=no) AS_CASE(["${with_pcre2}"], [no], [test_paths=], [yes], [test_paths="/usr/local/libpcre2 /usr/local/pcre2 /usr/local /opt/libpcre2 /opt/pcre2 /opt /usr"], [test_paths="${with_pcre2}"]) -AC_MSG_CHECKING([for libpcre2 config script]) +if test "x${with_pcre2}" == "x" || test "x${with_pcre2}" == "xno"; then + AC_MSG_NOTICE([pcre2 not specified; omitting check]) +else -for x in ${test_paths}; do - dnl # Determine if the script was specified and use it directly - if test ! -d "$x" -a -e "$x"; then - PCRE2_CONFIG=$x - pcre2_path="no" - break - fi + AC_MSG_CHECKING([for libpcre2 config script]) - dnl # Try known config script names/locations - for PCRE2_CONFIG in pcre2-config; do - if test -e "${x}/bin/${PCRE2_CONFIG}"; then - pcre2_path="${x}/bin" + for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + PCRE2_CONFIG=$x + pcre2_path="no" break - elif test -e "${x}/${PCRE2_CONFIG}"; then - pcre2_path="${x}" + fi + + dnl # Try known config script names/locations + for PCRE2_CONFIG in pcre2-config; do + if test -e "${x}/bin/${PCRE2_CONFIG}"; then + pcre2_path="${x}/bin" + break + elif test -e "${x}/${PCRE2_CONFIG}"; then + pcre2_path="${x}" + break + else + pcre2_path="" + fi + done + if test -n "$pcre2_path"; then break - else - pcre2_path="" fi done - if test -n "$pcre2_path"; then - break - fi -done -if test -n "${pcre2_path}"; then - if test "${pcre2_path}" != "no"; then - PCRE2_CONFIG="${pcre2_path}/${PCRE2_CONFIG}" + if test -n "${pcre2_path}"; then + if test "${pcre2_path}" != "no"; then + PCRE2_CONFIG="${pcre2_path}/${PCRE2_CONFIG}" + fi + AC_MSG_RESULT([${PCRE2_CONFIG}]) + PCRE2_VERSION="`${PCRE2_CONFIG} --version`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 VERSION: $PCRE2_VERSION); fi + PCRE2_CFLAGS="`${PCRE2_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 CFLAGS: $PCRE2_CFLAGS); fi + PCRE2_LDADD="`${PCRE2_CONFIG} --libs8`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 LDADD: $PCRE2_LDADD); fi + PCRE_LD_PATH="/`${PCRE2_CONFIG} --libs8 | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 PCRE_LD_PATH: $PCRE_LD_PATH); fi + else + AC_MSG_RESULT([no]) fi - AC_MSG_RESULT([${PCRE2_CONFIG}]) - PCRE2_VERSION="`${PCRE2_CONFIG} --version`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 VERSION: $PCRE2_VERSION); fi - PCRE2_CFLAGS="`${PCRE2_CONFIG} --cflags`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 CFLAGS: $PCRE2_CFLAGS); fi - PCRE2_LDADD="`${PCRE2_CONFIG} --libs8`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 LDADD: $PCRE2_LDADD); fi - PCRE_LD_PATH="/`${PCRE2_CONFIG} --libs8 | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre2 PCRE_LD_PATH: $PCRE_LD_PATH); fi -else - AC_MSG_RESULT([no]) -fi -AC_SUBST(PCRE2_CONFIG) -AC_SUBST(PCRE2_VERSION) -AC_SUBST(PCRE2_CPPFLAGS) -AC_SUBST(PCRE2_CFLAGS) -AC_SUBST(PCRE2_LDFLAGS) -AC_SUBST(PCRE2_LDADD) -AC_SUBST(PCRE_LD_PATH) + AC_SUBST(PCRE2_CONFIG) + AC_SUBST(PCRE2_VERSION) + AC_SUBST(PCRE2_CPPFLAGS) + AC_SUBST(PCRE2_CFLAGS) + AC_SUBST(PCRE2_LDFLAGS) + AC_SUBST(PCRE2_LDADD) + AC_SUBST(PCRE_LD_PATH) -if test -z "${PCRE2_VERSION}"; then - AC_MSG_NOTICE([*** pcre2 library not found.]) -else - AC_MSG_NOTICE([using pcre2 v${PCRE2_VERSION}]) - PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}" - ifelse([$1], , , $1) -fi + if test -z "${PCRE2_VERSION}"; then + AC_MSG_NOTICE([*** pcre2 library not found.]) + ifelse([$2], , AC_MSG_ERROR([pcre2 library is required]), $2) + else + AC_MSG_NOTICE([using pcre2 v${PCRE2_VERSION}]) + PCRE2_CFLAGS="-DWITH_PCRE2 ${PCRE2_CFLAGS}" + ifelse([$1], , , $1) + fi +fi ]) From f7fa00aadfabdbff23cecdc28cbb229f5f65f72a Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Sun, 20 Nov 2022 10:39:04 -0800 Subject: [PATCH 283/477] Fix: handle error with SecConnReadStateLimit configuration --- CHANGES | 2 ++ apache2/apache2_config.c | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/CHANGES b/CHANGES index 6074a4f53b..a06b9055f4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix: handle error with SecConnReadStateLimit configuration + [Issue #2815, #2834 - @marcstern, @martinhsv] * Only check for pcre2 install if required [Issue #2833 - @martinhsv] * Adjustment of previous fix for log messages diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 69612f9575..0758e23561 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1732,6 +1732,12 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, char *param = strchr(p2, ' '); char *file = NULL; char *error_msg = NULL; + + if (param == NULL) { + return apr_psprintf(mp, "ModSecurity: Space character between operator " \ + "and parameter not found with ConnReadStateLimit: %s", p2); + } + param++; config_orig_path = apr_pstrndup(mp, filename, From bc8c37070aabaf9104005411e18324f4730dea36 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 23 Nov 2022 14:28:00 -0800 Subject: [PATCH 284/477] Add CHANGES entry for previous PR --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index a06b9055f4..15d4f2b385 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Use uid for user if apr_uid_name_get() fails + [Issue #2046 - @arminabf, @marcstern] * Fix: handle error with SecConnReadStateLimit configuration [Issue #2815, #2834 - @marcstern, @martinhsv] * Only check for pcre2 install if required From a17cbc8f5ea72af907f89c1697a8f5d98e86bb2a Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 7 Dec 2022 07:47:42 -0800 Subject: [PATCH 285/477] Support for JIT option for PCRE2 --- CHANGES | 2 ++ apache2/msc_pcre.c | 35 ++++++++++++++++++++++++----------- apache2/msc_pcre.h | 4 ++++ apache2/re_operators.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/CHANGES b/CHANGES index 15d4f2b385..23d1e4f917 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Support for JIT option for PCRE2 + [Issue #2840 - @martinhsv] * Use uid for user if apr_uid_name_get() fails [Issue #2046 - @arminabf, @marcstern] * Fix: handle error with SecConnReadStateLimit configuration diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index ef9aa0f894..e2ce2a4f0e 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -84,7 +84,9 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, return NULL; } - /* TODO: Add PCRE2 JIT support */ +#ifdef WITH_PCRE_JIT + regex->jit_compile_rc = pcre2_jit_compile(regex->re, PCRE2_JIT_COMPLETE); +#endif /* Setup the pcre2 match context */ regex->match_context = NULL; @@ -242,27 +244,38 @@ int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, PCRE2_SPTR pcre2_s; int pcre2_ret; pcre2_match_data *match_data; - PCRE2_SIZE *pcre2_ovector = NULL; + PCRE2_SIZE *pcre2_ovector = NULL; pcre2_s = (PCRE2_SPTR)s; match_data = pcre2_match_data_create_from_pattern(regex->re, NULL); - pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), +#ifdef WITH_PCRE_JIT + if (regex->jit_compile_rc == 0) { + pcre2_ret = pcre2_jit_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + (PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context); + } + if (regex->jit_compile_rc != 0 || pcre2_ret == PCRE2_ERROR_JIT_STACKLIMIT) { + pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + (PCRE2_SIZE)(startoffset), (PCRE2_NO_JIT | (uint32_t)options), match_data, regex->match_context); + } +#else + pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), (PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context); - if (match_data != NULL) { - if (ovector != NULL) { - pcre2_ovector = pcre2_get_ovector_pointer(match_data); - if (pcre2_ovector != NULL) { +#endif + if (match_data != NULL) { + if (ovector != NULL) { + pcre2_ovector = pcre2_get_ovector_pointer(match_data); + if (pcre2_ovector != NULL) { for (int i = 0; ((i < pcre2_ret) && ((i*2) <= ovecsize)); i++) { if ((i*2) < ovecsize) { ovector[2*i] = pcre2_ovector[2*i]; ovector[2*i+1] = pcre2_ovector[2*i+1]; } - } - } - } + } + } + } pcre2_match_data_free(match_data); - } + } if ((pcre2_ret*2) > ovecsize) { return 0; } else { diff --git a/apache2/msc_pcre.h b/apache2/msc_pcre.h index 4871c1f8fa..c0ab37b4ae 100644 --- a/apache2/msc_pcre.h +++ b/apache2/msc_pcre.h @@ -45,6 +45,10 @@ struct msc_regex_t { #ifdef WITH_PCRE2 pcre2_code *re; pcre2_match_context *match_context; +#ifdef WITH_PCRE_JIT + int jit_compile_rc; +#endif + #else void *re; void *pe; diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 9217ad7923..e68aa9cd2a 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -711,7 +711,11 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -808,7 +812,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -973,7 +981,11 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -1060,7 +1072,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -2842,7 +2858,11 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -3169,7 +3189,11 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " @@ -3479,7 +3503,11 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { + #ifdef WITH_PCRE2 + rc = regex->jit_compile_rc; + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " From 583b465fdb8bfbaf7fbb85afdeb3ad58e6e69a7b Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 12 Dec 2022 02:26:13 -0800 Subject: [PATCH 286/477] Silence compiler warning about discarded const --- CHANGES | 2 ++ apache2/mod_security2.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 23d1e4f917..25b5bd9ce0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Silence compiler warning about discarded const + [Issue #2843 - @Steve8291, @martinhsv] * Support for JIT option for PCRE2 [Issue #2840 - @martinhsv] * Use uid for user if apr_uid_name_get() fails diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 4a0df82789..c9e7d650dd 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -105,7 +105,7 @@ static int server_limit, thread_limit; */ static void version(apr_pool_t *mp) { char *pcre_vrs = NULL; - char *pcre_loaded_vrs = NULL; + const char *pcre_loaded_vrs = NULL; char pcre2_loaded_vrs_buffer[80] ={0}; ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, @@ -119,7 +119,7 @@ static void version(apr_pool_t *mp) { #ifdef WITH_PCRE2 pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE2_MAJOR, PCRE2_MINOR); pcre_loaded_vrs = pcre2_loaded_vrs_buffer; - pcre2_config(PCRE2_CONFIG_VERSION, pcre_loaded_vrs); + pcre2_config(PCRE2_CONFIG_VERSION, pcre2_loaded_vrs_buffer); #else pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE_MAJOR, PCRE_MINOR); pcre_loaded_vrs = pcre_version(); From ac52086b44a63e16bf597f7fb226510a18f2f07e Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 12 Dec 2022 02:41:16 -0800 Subject: [PATCH 287/477] Distinguish PCRE vs. PCRE2 in startup version message --- apache2/mod_security2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index c9e7d650dd..7786543a12 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -126,7 +126,11 @@ static void version(apr_pool_t *mp) { #endif ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, +#ifdef WITH_PCRE2 + "ModSecurity: PCRE2 compiled version=\"%s\"; " +#else "ModSecurity: PCRE compiled version=\"%s\"; " +#endif "loaded version=\"%s\"", pcre_vrs, pcre_loaded_vrs); if (strstr(pcre_loaded_vrs,pcre_vrs) == NULL) { From 0981b325a7e8f92cc48a5af3c63141cda924b021 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 14 Dec 2022 07:01:23 -0800 Subject: [PATCH 288/477] Support configurable limit on number of arguments processed --- CHANGES | 2 + apache2/apache2_config.c | 30 ++++++++++++ apache2/modsecurity.h | 4 +- apache2/msc_json.c | 11 ++++- apache2/msc_parsers.c | 19 +++++++- .../regression/config/10-request-directives.t | 47 +++++++++++++++++++ 6 files changed, 109 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 25b5bd9ce0..b4b4da5c77 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Support configurable limit on number of arguments processed + [Issue #2844 - @jleproust, @martinhsv] * Silence compiler warning about discarded const [Issue #2843 - @Steve8291, @martinhsv] * Support for JIT option for PCRE2 diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 0758e23561..74c76a5810 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -54,6 +54,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) dcfg->reqbody_limit = NOT_SET; dcfg->reqbody_no_files_limit = NOT_SET; dcfg->reqbody_json_depth_limit = NOT_SET; + dcfg->arguments_limit = NOT_SET; dcfg->resbody_access = NOT_SET; dcfg->debuglog_name = NOT_SET_P; @@ -338,6 +339,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit); merged->reqbody_json_depth_limit = (child->reqbody_json_depth_limit == NOT_SET ? parent->reqbody_json_depth_limit : child->reqbody_json_depth_limit); + merged->arguments_limit = (child->arguments_limit == NOT_SET + ? parent->arguments_limit : child->arguments_limit); merged->resbody_access = (child->resbody_access == NOT_SET ? parent->resbody_access : child->resbody_access); @@ -655,6 +658,7 @@ void init_directory_config(directory_config *dcfg) if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT; if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT; if (dcfg->reqbody_json_depth_limit == NOT_SET) dcfg->reqbody_json_depth_limit = REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT; + if (dcfg->arguments_limit == NOT_SET) dcfg->arguments_limit = ARGUMENTS_LIMIT; if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0; if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT; if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT; @@ -1955,6 +1959,24 @@ static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg return NULL; } +static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecArgumentsLimit: %s", p1); + } + + dcfg->arguments_limit = limit; + + return NULL; +} + static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { @@ -3596,6 +3618,14 @@ const command_rec module_directives[] = { "maximum request body JSON parsing depth ModSecurity will accept." ), + AP_INIT_TAKE1 ( + "SecArgumentsLimit", + cmd_arguments_limit, + NULL, + CMD_SCOPE_ANY, + "maximum number of ARGS that ModSecurity will accept." + ), + AP_INIT_TAKE1 ( "SecRequestEncoding", cmd_request_encoding, diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 261151bae9..8e1880edc2 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -96,6 +96,7 @@ typedef struct msc_parm msc_parm; #define REQUEST_BODY_DEFAULT_LIMIT 134217728 #define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576 #define REQUEST_BODY_JSON_DEPTH_DEFAULT_LIMIT 10000 +#define ARGUMENTS_LIMIT 1000 #define RESPONSE_BODY_DEFAULT_LIMIT 524288 #define RESPONSE_BODY_HARD_LIMIT 1073741824L @@ -500,6 +501,7 @@ struct directory_config { long int reqbody_limit; long int reqbody_no_files_limit; long int reqbody_json_depth_limit; + long int arguments_limit; int resbody_access; long int of_limit; diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 737069b8d2..17f938b64e 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ - * Copyright (c) 2004-2011 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -57,6 +57,15 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) msr_log(msr, 9, "Adding JSON argument '%s' with value '%s'", arg->name, arg->value); } + if (apr_table_elts(msr->arguments)->nelts >= msr->txcfg->arguments_limit) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Skipping request argument, over limit (%s): name \"%s\", value \"%s\"", + arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), + log_escape_ex(msr->mp, arg->value, arg->value_len)); + } + msr->msc_reqbody_error = 1; + return 0; + } apr_table_addn(msr->arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg); diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 61344aa1b9..8bbf972689 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -346,6 +346,21 @@ void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) log_escape_ex(msr->mp, arg->value, arg->value_len)); } - apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg); + if (apr_table_elts(arguments)->nelts >= msr->txcfg->arguments_limit) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Skipping request argument, over limit (%s): name \"%s\", value \"%s\"", + arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), + log_escape_ex(msr->mp, arg->value, arg->value_len)); + } + if (msr->msc_reqbody_error != 1) { + char *error_msg = apr_psprintf(msr->mp, "SecArgumentsLimit exceeded"); + msr->msc_reqbody_error = 1; + if (error_msg != NULL) { + msr->msc_reqbody_error_msg = error_msg; + } + } + } else { + apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg); + } } diff --git a/tests/regression/config/10-request-directives.t b/tests/regression/config/10-request-directives.t index 42094e11b1..21b83ff101 100644 --- a/tests/regression/config/10-request-directives.t +++ b/tests/regression/config/10-request-directives.t @@ -703,3 +703,50 @@ ), }, +# SecArgumentsLimit +{ + type => "config", + comment => "SecArgumentsLimit (pos)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecArgumentsLimit 5 + SecRule REQBODY_ERROR "!\@eq 0" "id:'500232',phase:2,log,deny,status:403,msg:'Failed to parse request body'" + ), + match_log => { + error => [ qr/Access denied with code 403 /, 1 ], + }, + match_response => { + status => qr/^403$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2&c=3&d=4&e=5&f=6", + ), +}, +{ + type => "config", + comment => "SecArgumentsLimit (neg)", + conf => qq( + SecRuleEngine On + SecRequestBodyAccess On + SecArgumentsLimit 5 + SecRule REQBODY_ERROR "!\@eq 0" "id:'500233',phase:2,log,deny,status:403,msg:'Failed to parse request body'" + ), + match_log => { + }, + match_response => { + status => qr/^200$/, + }, + request => new HTTP::Request( + POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", + [ + "Content-Type" => "application/x-www-form-urlencoded", + ], + "a=1&b=2&c=3&d=4&e=5", + ), +}, + From 1cba2d47582c7ca5b76e32be0d86acb8495016e5 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Fri, 16 Dec 2022 08:37:56 -0800 Subject: [PATCH 289/477] PCRE2 fix: correct length arg in calls to match functions --- apache2/msc_pcre.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index e2ce2a4f0e..6f1a9a186c 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -251,15 +251,15 @@ int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen, #ifdef WITH_PCRE_JIT if (regex->jit_compile_rc == 0) { - pcre2_ret = pcre2_jit_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + pcre2_ret = pcre2_jit_match(regex->re, pcre2_s, slen, (PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context); } if (regex->jit_compile_rc != 0 || pcre2_ret == PCRE2_ERROR_JIT_STACKLIMIT) { - pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + pcre2_ret = pcre2_match(regex->re, pcre2_s, slen, (PCRE2_SIZE)(startoffset), (PCRE2_NO_JIT | (uint32_t)options), match_data, regex->match_context); } #else - pcre2_ret = pcre2_match(regex->re, pcre2_s, (PCRE2_SIZE)strlen(s), + pcre2_ret = pcre2_match(regex->re, pcre2_s, slen, (PCRE2_SIZE)(startoffset), (uint32_t)options, match_data, regex->match_context); #endif if (match_data != NULL) { From 8038a529c045fe3e5d3c9ca916e1cd93cd33e89d Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 21 Dec 2022 07:07:14 -0800 Subject: [PATCH 290/477] Copyright line updates --- apache2/msc_multipart.c | 2 +- apache2/msc_multipart.h | 2 +- apache2/msc_util.c | 2 +- apache2/msc_xml.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 4128ab17e1..9309d4df29 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/apache2/msc_multipart.h b/apache2/msc_multipart.h index 13db0658f4..a9c20b9b19 100644 --- a/apache2/msc_multipart.h +++ b/apache2/msc_multipart.h @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 6b6d27f9c1..cf9a393517 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 763ef399f4..5b5bbb1a25 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at From 8b3b7a0e238c077129e693074d1a3ff27feb4afd Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 4 Jan 2023 06:56:54 -0800 Subject: [PATCH 291/477] Add ostensibly unnecessary null check --- apache2/re_variables.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index c97466ba7d..12a0a5620e 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1431,18 +1431,20 @@ static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, m /* If we had a match add this argument to the collection. */ if (match) { - for (j = 0; j < parts[i]->header_lines->nelts; j++) { - char *header_line = ((char **)parts[i]->header_lines->elts)[j]; - msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); - - rvar->value = header_line; - rvar->value_len = strlen(rvar->value); - rvar->name = apr_psprintf(mptmp, "MULTIPART_PART_HEADERS:%s", - log_escape_nq(mptmp, parts[i]->name)); - apr_table_addn(vartab, rvar->name, (void *)rvar); - - count++; - } + if (parts[i]->header_lines) { /* this NULL check shouldn't be necessary */ + for (j = 0; j < parts[i]->header_lines->nelts; j++) { + char *header_line = ((char **)parts[i]->header_lines->elts)[j]; + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + + rvar->value = header_line; + rvar->value_len = strlen(rvar->value); + rvar->name = apr_psprintf(mptmp, "MULTIPART_PART_HEADERS:%s", + log_escape_nq(mptmp, parts[i]->name)); + apr_table_addn(vartab, rvar->name, (void *)rvar); + + count++; + } + } } } From afb48b2c9785fffaf89da4eba8d17baf09d08b47 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 4 Jan 2023 08:00:49 -0800 Subject: [PATCH 292/477] Adjust one automated test --- tests/regression/misc/10-tfn-cache.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/misc/10-tfn-cache.t b/tests/regression/misc/10-tfn-cache.t index 672b610d22..f0a663e495 100644 --- a/tests/regression/misc/10-tfn-cache.t +++ b/tests/regression/misc/10-tfn-cache.t @@ -182,6 +182,6 @@ "Content-Type" => "application/x-www-form-urlencoded", ], # 1000 Args - join("&", map { sprintf "arg%08d=0123456789abcdef+0123456789ABCDEF+0123456789abcdef", $_ } (1 .. 1000))."&test=Foo+Bar", + join("&", map { sprintf "arg%08d=0123456789abcdef+0123456789ABCDEF+0123456789abcdef", $_ } (1 .. 999))."&test=Foo+Bar", ), }, From 4324f0ac59f8225aa44bc5034df60dbeccd1d334 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 4 Jan 2023 11:34:11 -0800 Subject: [PATCH 293/477] Fix: FILES_TMP_CONTENT may sometimes lack complete content --- CHANGES | 2 ++ apache2/re_variables.c | 26 ++++++++++++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index b4b4da5c77..163f9edf68 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix: FILES_TMP_CONTENT may sometimes lack complete content + [Issue #2857 - gieltje, @airween, @dune73, @martinhsv] * Support configurable limit on number of arguments processed [Issue #2844 - @jleproust, @martinhsv] * Silence compiler warning about discarded const diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 12a0a5620e..a53140b2c1 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -1173,6 +1173,7 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, FILE *file; size_t nread; char *full_content = NULL; + char *full_content_tmp_ptr = NULL; size_t total_lenght = 0; msre_var *rvar = NULL; @@ -1182,19 +1183,23 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, continue; } + full_content = (char *)apr_pcalloc(mptmp, (sizeof(char)*parts[i]->length) + 1); + if (full_content == NULL) { + if (msr->txcfg->debuglog_level >= 3) { + msr_log(msr, 3, "Variable FILES_TMP_CONTENT will not be created, not " \ + "enough memory available."); + } + goto files_tmp_content_not_enough_mem; + } + full_content_tmp_ptr = full_content; + while ((nread = fread(buf, 1, 1023, 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); - } + full_content_tmp_ptr = memcpy(full_content_tmp_ptr, buf, nread); + full_content_tmp_ptr += nread; + total_lenght += nread; } + full_content_tmp_ptr[total_lenght] = '\0'; fclose(file); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -1209,6 +1214,7 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, } } +files_tmp_content_not_enough_mem: return count; } From 053965529cb6993fbeb931e6760097e66936fd81 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Wed, 4 Jan 2023 13:15:13 -0800 Subject: [PATCH 294/477] Version 2.9.7 --- CHANGES | 2 +- apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 163f9edf68..30b3843f65 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -DD mmm YYYY - 2.9.x (to be released) +04 Jan 2023 - 2.9.7 ------------------- * Fix: FILES_TMP_CONTENT may sometimes lack complete content diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 8905a72ac2..bc6f959970 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "6" +#define MODSEC_VERSION_MAINT "7" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" diff --git a/iis/installer.wxs b/iis/installer.wxs index 1db301954d..6ef3c05e6f 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> - <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.6" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> + <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.7" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB"> <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" /> <?define ProductName = "ModSecuirty IIS" ?> <?if $(sys.BUILDARCH) = x64 ?> From 916bded59014e15c57221d177fad4d45c8f4454f Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Thu, 19 Jan 2023 12:20:13 -0800 Subject: [PATCH 295/477] CHANGES: Preparing for next version --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 30b3843f65..954a28aa70 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +DD mmm YYYY - 2.9.x (to be released) +------------------- + + 04 Jan 2023 - 2.9.7 ------------------- From 4b9edaddfc947bc08838a1ef6cb59000450257b4 Mon Sep 17 00:00:00 2001 From: Lars Wendler <polynomial-c@gmx.de> Date: Tue, 14 Mar 2023 11:36:22 +0100 Subject: [PATCH 296/477] build: Avoid bashisms otherwise configure fails to find pcre2 when /bin/sh does not point to bash: configure: using pcre v8.45 ./configure: 16601: test: xno: unexpected operator ./configure: 16601: test: xno: unexpected operator checking for libpcre2 config script... no configure: *** pcre2 library not found. configure: error: pcre2 library is required Signed-off-by: Lars Wendler <polynomial-c@gmx.de> --- build/find_pcre2.m4 | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 index 11e9890f98..18c2e25807 100644 --- a/build/find_pcre2.m4 +++ b/build/find_pcre2.m4 @@ -25,7 +25,7 @@ AS_CASE(["${with_pcre2}"], [yes], [test_paths="/usr/local/libpcre2 /usr/local/pcre2 /usr/local /opt/libpcre2 /opt/pcre2 /opt /usr"], [test_paths="${with_pcre2}"]) -if test "x${with_pcre2}" == "x" || test "x${with_pcre2}" == "xno"; then +if test "x${with_pcre2}" = "x" || test "x${with_pcre2}" = "xno"; then AC_MSG_NOTICE([pcre2 not specified; omitting check]) else diff --git a/configure.ac b/configure.ac index 1d42896772..81a1a6b62e 100644 --- a/configure.ac +++ b/configure.ac @@ -696,7 +696,7 @@ AC_ARG_ENABLE(large-stream-input, AS_HELP_STRING([--enable-large-stream-input], [Enable optimization for large stream input]), [ - if test "$enableval" == "yes"; then + if test "$enableval" = "yes"; then large_stream_input="-DMSC_LARGE_STREAM_INPUT" MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" else From fb1abae980f5460ef0bfecf5e19cb8bb8f84073e Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 20 Mar 2023 10:49:44 -0700 Subject: [PATCH 297/477] Add CHANGES entry for previous merger --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 954a28aa70..7ce5022f0f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Substitute two equals-equals operators in build + [Issue #2883 - @Polynomial-C] 04 Jan 2023 - 2.9.7 ------------------- From 5bb58b8e607f2c13e160eedbbc974650b2bacf80 Mon Sep 17 00:00:00 2001 From: Paolino <leancz@gmail.com> Date: Mon, 17 Jul 2023 17:32:10 +0200 Subject: [PATCH 298/477] Adding PCRE2 support for windows build in Makefile.win Including new parameter PCRE2, which if set will enable PCRE2 in the build. --- apache2/Makefile.win | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/apache2/Makefile.win b/apache2/Makefile.win index ed4bfc9ed2..9efa74f8fb 100644 --- a/apache2/Makefile.win +++ b/apache2/Makefile.win @@ -1,29 +1,37 @@ ########################################################################### # -# Usage: NMAKE -f Makefile.win APACHE={httpd installion dir} PCRE={pcre dir} LIBXML2={LibXML2 dir} [ LUA={Lua dir} ] +# Usage: NMAKE -f Makefile.win APACHE={httpd installion dir} PCRE|PCRE2={pcre dir} LIBXML2={LibXML2 dir} [ LUA={Lua dir} ] # +!IF "$(PCRE2)" != "" +PCRE = $(PCRE2) +!ENDIF + !IF "$(APACHE)" == "" || "$(PCRE)" == "" || "$(LIBXML2)" == "" || "$(CURL)" == "" -!ERROR NMAKE arguments: APACHE=dir PCRE=dir LIBXML2=dir CURL=dir are required to build mod_security2 for Windows +!ERROR NMAKE arguments: APACHE=dir PCRE|PCRE2=dir LIBXML2=dir CURL=dir are required to build mod_security2 for Windows !ENDIF # Linking libraries LIBS = $(APACHE)\lib\libhttpd.lib \ $(APACHE)\lib\libapr-1.lib \ $(APACHE)\lib\libaprutil-1.lib \ - $(PCRE)\pcre.lib \ - $(CURL)\libcurl.lib \ + $(CURL)\libcurl.lib \ $(LIBXML2)\win32\bin.msvc\libxml2.lib \ Ws2_32.lib \ "iphlpapi.lib" +!IF "$(PCRE2)" != "" +LIBS =$(LIBS) $(PCRE2)\lib\pcre2-8.lib +!ELSE +LIBS =$(LIBS) $(PCRE)\lib\pcre.lib +!ENDIF ########################################################################### ########################################################################### - -!IF "$(IIS_BUILD)" == "yes" -DEFS=$(DEFS) -DVERSION_IIS -!ENDIF - + +!IF "$(IIS_BUILD)" == "yes" +DEFS=$(DEFS) -DVERSION_IIS +!ENDIF + CC = CL MT = mt @@ -37,9 +45,14 @@ INCLUDES = -I. -I.. \ -I$(PCRE)\include -I$(PCRE) \ -I$(LIBXML2)\include \ -I$(APACHE)\include - -# Enables support for SecRemoteRules and external resources. -DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES + +# Enables support for SecRemoteRules and external resources. +DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES + +# Enable PCRE2 +!IF "$(PCRE2)" != "" +DEFS =$(DEFS) -DWITH_PCRE2 +!ENDIF # Lua is optional !IF "$(LUA)" != "" @@ -65,8 +78,8 @@ OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \ msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \ msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_crypt.obj msc_tree.obj msc_unicode.obj acmp.obj msc_lua.obj \ msc_release.obj \ - msc_status_engine.obj \ - msc_remote_rules.obj \ + msc_status_engine.obj \ + msc_remote_rules.obj \ msc_json.obj \ libinjection/libinjection_html5.obj \ libinjection/libinjection_sqli.obj \ From 2105ed0639f7323589f4517d0cea03c351a5b1ac Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 6 Jun 2023 13:50:07 -0700 Subject: [PATCH 299/477] Do not escape special chars in regex pattern with macro --- CHANGES | 2 ++ apache2/re_operators.c | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CHANGES b/CHANGES index 7ce5022f0f..15ea1c2ff1 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Do not escape special chars in rx pattern with macro + [Issue #2357 - @marcstern, @martinhsv] * Substitute two equals-equals operators in build [Issue #2883 - @Polynomial-C] diff --git a/apache2/re_operators.c b/apache2/re_operators.c index e68aa9cd2a..cfd8952539 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1,6 +1,6 @@ /* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2022 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* Copyright (c) 2004-2023 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License. You may obtain a copy of the License at @@ -1024,7 +1024,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c int matched = 0; int rc; char *qspos = NULL; - const char *parm = NULL, *pattern = NULL; + const char *parm = NULL; msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT @@ -1052,9 +1052,9 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c expand_macros(msr, re_pattern, rule, msr->mp); - pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - msr_log(msr, 6, "Escaping pattern [%s]",pattern); + char *pattern = log_escape_re(msr->mp, re_pattern->value); + msr_log(msr, 6, "Expanded-macro pattern [%s]",pattern); } #ifdef WITH_PCRE2 @@ -1062,7 +1062,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c #else options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; #endif - regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + regex = msc_pregcomp_ex(msr->mp, re_pattern->value, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", erroffset, errptr); From eb532bd791059fa2104c8f9d8cc7b545b9dce05b Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 16:34:04 +0200 Subject: [PATCH 300/477] remove useless apr_pstrdup() --- apache2/re_actions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 02ec07d222..5b6b9dd184 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -183,9 +183,9 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t * no macros in the input data. */ - data = apr_pstrdup(mptmp, var->value); /* IMP1 Are we modifying data anywhere? */ + data = var->value; arr = apr_array_make(mptmp, 16, sizeof(msc_string *)); - if ((data == NULL)||(arr == NULL)) return -1; + if (arr == NULL) return -1; text_start = next_text_start = data; do { From 3dc5ff5f6532a9222bc9607f5f2dd34b28ca6fe4 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 16:44:18 +0200 Subject: [PATCH 301/477] remove useless memset --- apache2/re_operators.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index cfd8952539..07dca7df43 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -630,18 +630,13 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, } if(msr->stream_input_data != NULL && input_body == 1) { - memset(msr->stream_input_data, 0x0, msr->stream_input_length); free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = 0; - - msr->stream_input_data = (char *)malloc(size); -#else - msr->stream_input_data = (char *)malloc(size+1); #endif - + msr->stream_input_data = (char *)malloc(size+1); if(msr->stream_input_data == NULL) { return -1; } @@ -649,16 +644,11 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_length = size; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = size; - memset(msr->stream_input_data, 0x0, size); -#else - memset(msr->stream_input_data, 0x0, size+1); #endif msr->if_stream_changed = 1; memcpy(msr->stream_input_data, data, size); -#ifndef MSC_LARGE_STREAM_INPUT msr->stream_input_data[size] = '\0'; -#endif var->value_len = size; var->value = msr->stream_input_data; From c7b28f0e13fa18d8503877e026744f76607cfbae Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 17:17:59 +0200 Subject: [PATCH 302/477] Centralized function compatible with Linux & Windows (also with mpm-itk & mod_ruid2) to get username --- apache2/msc_util.c | 11 + apache2/msc_util.h | 2 + apache2/persist_dbm.c | 1649 ++++++++++++++++++++--------------------- 3 files changed, 821 insertions(+), 841 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index cf9a393517..48d297c20d 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2843,3 +2843,14 @@ char* strtok_r( } #endif +// Function compatible with Linux & Windows, also with mpm-itk & mod_ruid2 +char* get_username(apr_pool_t* mp) { + char* username; + apr_uid_t uid; + apr_gid_t gid; + int rc = apr_uid_current(&uid, &gid, mp); + if (rc != APR_SUCCESS) return "apache"; + rc = apr_uid_name_get(&username, uid, mp); + if (rc != APR_SUCCESS) return "apache"; + return username; +} diff --git a/apache2/msc_util.h b/apache2/msc_util.h index f7e1280f21..e4e043de16 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -159,6 +159,8 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, int DSOLOCAL ip_tree_from_param(apr_pool_t *pool, char *param, TreeRoot **rtree, char **error_msg); +char DSOLOCAL *get_username(apr_pool_t* mp); + #ifdef WITH_CURL int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index e4f8036f6f..0690ef80b8 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -1,841 +1,808 @@ -/* -* ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) -* -* You may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* If any of the files related to licensing are missing or if you have any -* other questions related to licensing please contact Trustwave Holdings, Inc. -* directly using the email address security@modsecurity.org. -*/ - -#include "persist_dbm.h" -#include "apr_sdbm.h" - -/** - * - */ -static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, - int log_vars) -{ - apr_table_t *col = NULL; - unsigned int blob_offset; - - col = apr_table_make(msr->mp, 32); - if (col == NULL) return NULL; - - /* ENH verify the first 3 bytes (header) */ - - blob_offset = 3; - while (blob_offset + 1 < blob_size) { - msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); - - var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - if (var->name_len == 0) { - /* Is the length a name length, or just the end of the blob? */ - if (blob_offset < blob_size - 2) { - /* This should never happen as the name length - * includes the terminating NUL and should be 1 for "" - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); - } - break; - } - else if (var->name_len > 65536) { - /* This should never happen as the length is restricted on store - * to 65536. - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); - break; - } - - blob_offset += 2; - if (blob_offset + var->name_len > blob_size) return NULL; - var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); - blob_offset += var->name_len; - var->name_len--; - - var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - blob_offset += 2; - - if (blob_offset + var->value_len > blob_size) return NULL; - var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); - blob_offset += var->value_len; - var->value_len--; - - if (log_vars && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - - apr_table_addn(col, var->name, (void *)var); - } - - return col; -} - -/** - * - */ -static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - char *dbm_filename = NULL; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t *value = NULL; - apr_sdbm_t *dbm = NULL; - apr_table_t *col = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int expired = 0; - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len)); - goto cleanup; - } - - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - - key.dptr = (char *)col_key; - key.dsize = col_key_len + 1; - - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); - rc = apr_sdbm_fetch(dbm, value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, - dbm_filename), get_apr_error(msr->mp, rc)); - goto cleanup; - } - - if (value->dptr == NULL) { /* Key not found in DBM file. */ - goto cleanup; - } - - /* ENH Need expiration (and perhaps other metadata) accessible in blob - * form to determine if converting to a table is needed. This will - * save some cycles. - */ - - /* Transform raw data into a table. */ - col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); - if (col == NULL) { - goto cleanup; - } - - /* Close after "value" used from fetch or memory may be overwritten. */ - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - /* Remove expired variables. */ - do { - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - if (strncmp(te[i].key, "__expire_", 9) == 0) { - msc_string *var = (msc_string *)te[i].val; - int expiry_time = atoi(var->value); - - if (expiry_time <= apr_time_sec(msr->request_time)) { - char *key_to_expire = te[i].key; - - /* Done early if the col expired */ - if (strcmp(key_to_expire, "__expire_KEY") == 0) { - expired = 1; - } - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); - } - - apr_table_unset(col, key_to_expire + 9); - apr_table_unset(col, key_to_expire); - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); - } - - break; - } - } - } - } while(!expired && (i != arr->nelts)); - - /* Delete the collection if the variable "KEY" does not exist. - * - * ENH It would probably be more efficient to hold the DBM - * open until determined if it needs deleted than to open a second - * time. - */ - if (apr_table_get(col, "KEY") == NULL) { - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto cleanup; - } - - - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - if (expired && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, - log_escape_ex(msr->mp, col_key, col_key_len)); - } - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - goto cleanup; - } - - /* Update UPDATE_RATE */ - { - msc_string *var; - int create_time, counter; - - var = (msc_string *)apr_table_get(col, "CREATE_TIME"); - if (var == NULL) { - /* Error. */ - } else { - create_time = atoi(var->value); - var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - if (var == NULL) { - /* Error. */ - } else { - apr_time_t td; - counter = atoi(var->value); - - /* UPDATE_RATE is removed on store, so add it back here */ - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_RATE"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - - /* NOTE: No rate if there has been no time elapsed */ - td = (apr_time_sec(apr_time_now()) - create_time); - if (td == 0) { - var->value = apr_psprintf(msr->mp, "%d", 0); - } - else { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, - (apr_time_t)((60 * counter)/td)); - } - var->value_len = strlen(var->value); - } - } - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - - if ((existing_dbm == NULL) && dbm) { - /* Should not ever get here */ - msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return col; - -cleanup: - - if ((existing_dbm == NULL) && dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return NULL; -} - -/** - * - */ -apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - apr_time_t time_before = apr_time_now(); - apr_table_t *rtable = NULL; - - rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); - - msr->time_storage_read += apr_time_now() - time_before; - - return rtable; -} - -/** - * - */ -int collection_store(modsec_rec *msr, apr_table_t *col) { - char *dbm_filename = NULL; - msc_string *var_name = NULL, *var_key = NULL; - unsigned char *blob = NULL; - unsigned int blob_size, blob_offset; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t value; - apr_sdbm_t *dbm = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int i; - const apr_table_t *stored_col = NULL; - const apr_table_t *orig_col = NULL; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { - goto error; - } - - var_key = (msc_string *)apr_table_get(col, "__key"); - if (var_key == NULL) { - goto error; - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - goto error; - } - - // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* Delete IS_NEW on store. */ - apr_table_unset(col, "IS_NEW"); - - /* Delete UPDATE_RATE on store to save space as it is calculated */ - apr_table_unset(col, "UPDATE_RATE"); - - /* Update the timeout value. */ - { - msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); - if (var != NULL) { - int timeout = atoi(var->value); - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var != NULL) { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); - var->value_len = strlen(var->value); - } - } - } - - /* LAST_UPDATE_TIME */ - { - msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "LAST_UPDATE_TIME"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); - var->value_len = strlen(var->value); - } - - /* UPDATE_COUNTER */ - { - msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - int counter = 0; - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_COUNTER"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } else { - counter = atoi(var->value); - } - var->value = apr_psprintf(msr->mp, "%d", counter + 1); - var->value_len = strlen(var->value); - } - - /* ENH Make the expiration timestamp accessible in blob form so that - * it is easier/faster to determine expiration without having to - * convert back to table form - */ - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - -#ifndef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* If there is an original value, then create a delta and - * apply the delta to the current value */ - orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); - if (orig_col != NULL) { - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", - apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); - } - - stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); - } - - /* Merge deltas and calculate the size first. */ - blob_size = 3 + 2; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - /* If there is an original value, then apply the delta - * to the latest stored value */ - if (stored_col != NULL) { - const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); - if (orig_var != NULL) { - const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); - if (stored_var != NULL) { - int origval = atoi(orig_var->value); - int ourval = atoi(var->value); - int storedval = atoi(stored_var->value); - int delta = ourval - origval; - int newval = storedval + delta; - - if (newval < 0) newval = 0; /* Counters never go below zero. */ - - var->value = apr_psprintf(msr->mp, "%d", newval); - var->value_len = strlen(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var->name, var->name_len), - origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); - } - } - } - } - - // Allocate blob_size for keys - len = var->name_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - - // Allocate blob_size for values - len = var->value_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - } - - /* Now generate the binary object. */ - blob = apr_pcalloc(msr->mp, blob_size); - if (blob == NULL) { - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - - blob[0] = 0x49; - blob[1] = 0x52; - blob[2] = 0x01; - - blob_offset = 3; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - len = var->name_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->name, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - len = var->value_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->value, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - } - - blob[blob_offset] = 0; - blob[blob_offset + 1] = 0; - - /* And, finally, store it. */ - key.dptr = var_key->value; - key.dsize = var_key->value_len + 1; - - value.dptr = (char *)blob; - value.dsize = blob_size; - - rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - } - - return 0; - -error: - return -1; -} - -/** - * - */ -int collections_remove_stale(modsec_rec *msr, const char *col_name) { - char *dbm_filename = NULL; - apr_sdbm_datum_t key, value; - apr_sdbm_t *dbm = NULL; - apr_status_t rc; - apr_array_header_t *keys_arr; - char **keys; - apr_time_t now = apr_time_sec(msr->request_time); - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. - * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " - * "define data directory first.", log_escape(msr->mp, col_name)); - */ - goto error; - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - - /* First get a list of all keys. */ - keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - -#ifndef GLOBAL_COLLECTION_LOCK - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* No one can write to the file while doing this so - * do it as fast as possible. - */ - rc = apr_sdbm_firstkey(dbm, &key); - while(rc == APR_SUCCESS) { - if (key.dsize) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); - *(char **)apr_array_push(keys_arr) = s; - } - rc = apr_sdbm_nextkey(dbm, &key); - } -#ifndef GLOBAL_COLLECTION_LOCK - apr_sdbm_unlock(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, - log_escape(msr->mp, dbm_filename)); - } - - /* Now retrieve the entires one by one. */ - keys = (char **)keys_arr->elts; - for (i = 0; i < keys_arr->nelts; i++) { - key.dptr = keys[i]; - key.dsize = strlen(key.dptr) + 1; - - rc = apr_sdbm_fetch(dbm, &value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - goto error; - } - - if (value.dptr != NULL) { - apr_table_t *col = NULL; - msc_string *var = NULL; - - col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); - if (col == NULL) { - goto error; - } - - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var == NULL) { - msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " - "__expire_KEY (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } else { - unsigned int expiry_time = atoi(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), - expiry_time - now); - } - - if (expiry_time <= now) { - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto error; - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " - "key \"%s\").", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } - } - } - } else { - /* Ignore entry not found - it may have been removed in the meantime. */ - } - } - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - return 1; - -error: - - if (dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return -1; -} +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); + } + + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); + } + + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, + log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +ÿ�nd罎 + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + apr_time_t time_before = apr_time_now(); + apr_table_t *rtable = NULL; + + rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); + + msr->time_storage_read += apr_time_now() - time_before; + + return rtable; +} + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + char *userinfo = get_username(msr->mp); + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", + apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + // Allocate blob_size for keys + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + // Allocate blob_size for values + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); + else + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } + rc = apr_sdbm_nextkey(dbm, &key); + } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto error; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return -1; +} From b3b33c9ff1bc17ca88bab25ae51ea0eef83305c1 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 17:19:08 +0200 Subject: [PATCH 303/477] Revert "Centralized function compatible with Linux & Windows (also with mpm-itk & mod_ruid2) to get username" This reverts commit c7b28f0e13fa18d8503877e026744f76607cfbae. --- apache2/msc_util.c | 11 - apache2/msc_util.h | 2 - apache2/persist_dbm.c | 1649 +++++++++++++++++++++-------------------- 3 files changed, 841 insertions(+), 821 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 48d297c20d..cf9a393517 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2843,14 +2843,3 @@ char* strtok_r( } #endif -// Function compatible with Linux & Windows, also with mpm-itk & mod_ruid2 -char* get_username(apr_pool_t* mp) { - char* username; - apr_uid_t uid; - apr_gid_t gid; - int rc = apr_uid_current(&uid, &gid, mp); - if (rc != APR_SUCCESS) return "apache"; - rc = apr_uid_name_get(&username, uid, mp); - if (rc != APR_SUCCESS) return "apache"; - return username; -} diff --git a/apache2/msc_util.h b/apache2/msc_util.h index e4e043de16..f7e1280f21 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -159,8 +159,6 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, int DSOLOCAL ip_tree_from_param(apr_pool_t *pool, char *param, TreeRoot **rtree, char **error_msg); -char DSOLOCAL *get_username(apr_pool_t* mp); - #ifdef WITH_CURL int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 0690ef80b8..e4f8036f6f 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -1,808 +1,841 @@ -/* -* ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) -* -* You may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* If any of the files related to licensing are missing or if you have any -* other questions related to licensing please contact Trustwave Holdings, Inc. -* directly using the email address security@modsecurity.org. -*/ - -#include "persist_dbm.h" -#include "apr_sdbm.h" - -/** - * - */ -static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, - int log_vars) -{ - apr_table_t *col = NULL; - unsigned int blob_offset; - - col = apr_table_make(msr->mp, 32); - if (col == NULL) return NULL; - - /* ENH verify the first 3 bytes (header) */ - - blob_offset = 3; - while (blob_offset + 1 < blob_size) { - msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); - - var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - if (var->name_len == 0) { - /* Is the length a name length, or just the end of the blob? */ - if (blob_offset < blob_size - 2) { - /* This should never happen as the name length - * includes the terminating NUL and should be 1 for "" - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); - } - break; - } - else if (var->name_len > 65536) { - /* This should never happen as the length is restricted on store - * to 65536. - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); - break; - } - - blob_offset += 2; - if (blob_offset + var->name_len > blob_size) return NULL; - var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); - blob_offset += var->name_len; - var->name_len--; - - var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - blob_offset += 2; - - if (blob_offset + var->value_len > blob_size) return NULL; - var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); - blob_offset += var->value_len; - var->value_len--; - - if (log_vars && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - - apr_table_addn(col, var->name, (void *)var); - } - - return col; -} - -/** - * - */ -static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - char *dbm_filename = NULL; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t *value = NULL; - apr_sdbm_t *dbm = NULL; - apr_table_t *col = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int expired = 0; - int i; - char *userinfo = get_username(msr->mp); - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len)); - goto cleanup; - } - - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - - key.dptr = (char *)col_key; - key.dsize = col_key_len + 1; - - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); - rc = apr_sdbm_fetch(dbm, value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, - dbm_filename), get_apr_error(msr->mp, rc)); - goto cleanup; - } - - if (value->dptr == NULL) { /* Key not found in DBM file. */ - goto cleanup; - } - - /* ENH Need expiration (and perhaps other metadata) accessible in blob - * form to determine if converting to a table is needed. This will - * save some cycles. - */ - - /* Transform raw data into a table. */ - col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); - if (col == NULL) { - goto cleanup; - } - - /* Close after "value" used from fetch or memory may be overwritten. */ - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - /* Remove expired variables. */ - do { - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - if (strncmp(te[i].key, "__expire_", 9) == 0) { - msc_string *var = (msc_string *)te[i].val; - int expiry_time = atoi(var->value); - - if (expiry_time <= apr_time_sec(msr->request_time)) { - char *key_to_expire = te[i].key; - - /* Done early if the col expired */ - if (strcmp(key_to_expire, "__expire_KEY") == 0) { - expired = 1; - } - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); - } - - apr_table_unset(col, key_to_expire + 9); - apr_table_unset(col, key_to_expire); - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); - } - - break; - } - } - } - } while(!expired && (i != arr->nelts)); - - /* Delete the collection if the variable "KEY" does not exist. - * - * ENH It would probably be more efficient to hold the DBM - * open until determined if it needs deleted than to open a second - * time. - */ - if (apr_table_get(col, "KEY") == NULL) { - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto cleanup; - } - - - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - if (expired && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, - log_escape_ex(msr->mp, col_key, col_key_len)); - } - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - goto cleanup; - } - - /* Update UPDATE_RATE */ - { - msc_string *var; - int create_time, counter; - - var = (msc_string *)apr_table_get(col, "CREATE_TIME"); - if (var == NULL) { - /* Error. */ - } else { - create_time = atoi(var->value); - var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - if (var == NULL) { - /* Error. */ - } else { - apr_time_t td; - counter = atoi(var->value); - - /* UPDATE_RATE is removed on store, so add it back here */ - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_RATE"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - - /* NOTE: No rate if there has been no time elapsed */ - td = (apr_time_sec(apr_time_now()) - create_time); - if (td == 0) { - var->value = apr_psprintf(msr->mp, "%d", 0); - } - else { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, - (apr_time_t)((60 * counter)/td)); - } - var->value_len = strlen(var->value); - } - } - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - - if ((existing_dbm == NULL) && dbm) { - /* Should not ever get here */ - msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return col; - -cleanup: - - if ((existing_dbm == NULL) && dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -ÿ�nd罎 - } - - return NULL; -} - -/** - * - */ -apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - apr_time_t time_before = apr_time_now(); - apr_table_t *rtable = NULL; - - rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); - - msr->time_storage_read += apr_time_now() - time_before; - - return rtable; -} - -/** - * - */ -int collection_store(modsec_rec *msr, apr_table_t *col) { - char *dbm_filename = NULL; - msc_string *var_name = NULL, *var_key = NULL; - unsigned char *blob = NULL; - unsigned int blob_size, blob_offset; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t value; - apr_sdbm_t *dbm = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int i; - const apr_table_t *stored_col = NULL; - const apr_table_t *orig_col = NULL; - char *userinfo = get_username(msr->mp); - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { - goto error; - } - - var_key = (msc_string *)apr_table_get(col, "__key"); - if (var_key == NULL) { - goto error; - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - goto error; - } - - // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* Delete IS_NEW on store. */ - apr_table_unset(col, "IS_NEW"); - - /* Delete UPDATE_RATE on store to save space as it is calculated */ - apr_table_unset(col, "UPDATE_RATE"); - - /* Update the timeout value. */ - { - msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); - if (var != NULL) { - int timeout = atoi(var->value); - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var != NULL) { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); - var->value_len = strlen(var->value); - } - } - } - - /* LAST_UPDATE_TIME */ - { - msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "LAST_UPDATE_TIME"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); - var->value_len = strlen(var->value); - } - - /* UPDATE_COUNTER */ - { - msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - int counter = 0; - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_COUNTER"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } else { - counter = atoi(var->value); - } - var->value = apr_psprintf(msr->mp, "%d", counter + 1); - var->value_len = strlen(var->value); - } - - /* ENH Make the expiration timestamp accessible in blob form so that - * it is easier/faster to determine expiration without having to - * convert back to table form - */ - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - -#ifndef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* If there is an original value, then create a delta and - * apply the delta to the current value */ - orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); - if (orig_col != NULL) { - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", - apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); - } - - stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); - } - - /* Merge deltas and calculate the size first. */ - blob_size = 3 + 2; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - /* If there is an original value, then apply the delta - * to the latest stored value */ - if (stored_col != NULL) { - const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); - if (orig_var != NULL) { - const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); - if (stored_var != NULL) { - int origval = atoi(orig_var->value); - int ourval = atoi(var->value); - int storedval = atoi(stored_var->value); - int delta = ourval - origval; - int newval = storedval + delta; - - if (newval < 0) newval = 0; /* Counters never go below zero. */ - - var->value = apr_psprintf(msr->mp, "%d", newval); - var->value_len = strlen(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var->name, var->name_len), - origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); - } - } - } - } - - // Allocate blob_size for keys - len = var->name_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - - // Allocate blob_size for values - len = var->value_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - } - - /* Now generate the binary object. */ - blob = apr_pcalloc(msr->mp, blob_size); - if (blob == NULL) { - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - - blob[0] = 0x49; - blob[1] = 0x52; - blob[2] = 0x01; - - blob_offset = 3; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - len = var->name_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->name, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - len = var->value_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->value, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - } - - blob[blob_offset] = 0; - blob[blob_offset + 1] = 0; - - /* And, finally, store it. */ - key.dptr = var_key->value; - key.dsize = var_key->value_len + 1; - - value.dptr = (char *)blob; - value.dsize = blob_size; - - rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - } - - return 0; - -error: - return -1; -} - -/** - * - */ -int collections_remove_stale(modsec_rec *msr, const char *col_name) { - char *dbm_filename = NULL; - apr_sdbm_datum_t key, value; - apr_sdbm_t *dbm = NULL; - apr_status_t rc; - apr_array_header_t *keys_arr; - char **keys; - apr_time_t now = apr_time_sec(msr->request_time); - int i; - char *userinfo = get_username(msr->mp); - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. - * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " - * "define data directory first.", log_escape(msr->mp, col_name)); - */ - goto error; - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - - /* First get a list of all keys. */ - keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - -#ifndef GLOBAL_COLLECTION_LOCK - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* No one can write to the file while doing this so - * do it as fast as possible. - */ - rc = apr_sdbm_firstkey(dbm, &key); - while(rc == APR_SUCCESS) { - if (key.dsize) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); - *(char **)apr_array_push(keys_arr) = s; - } - rc = apr_sdbm_nextkey(dbm, &key); - } -#ifndef GLOBAL_COLLECTION_LOCK - apr_sdbm_unlock(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, - log_escape(msr->mp, dbm_filename)); - } - - /* Now retrieve the entires one by one. */ - keys = (char **)keys_arr->elts; - for (i = 0; i < keys_arr->nelts; i++) { - key.dptr = keys[i]; - key.dsize = strlen(key.dptr) + 1; - - rc = apr_sdbm_fetch(dbm, &value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - goto error; - } - - if (value.dptr != NULL) { - apr_table_t *col = NULL; - msc_string *var = NULL; - - col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); - if (col == NULL) { - goto error; - } - - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var == NULL) { - msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " - "__expire_KEY (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } else { - unsigned int expiry_time = atoi(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), - expiry_time - now); - } - - if (expiry_time <= now) { - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto error; - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " - "key \"%s\").", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } - } - } - } else { - /* Ignore entry not found - it may have been removed in the meantime. */ - } - } - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - return 1; - -error: - - if (dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return -1; -} +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); + } + + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); + } + + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, + log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + apr_time_t time_before = apr_time_now(); + apr_table_t *rtable = NULL; + + rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); + + msr->time_storage_read += apr_time_now() - time_before; + + return rtable; +} + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", + apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + // Allocate blob_size for keys + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + // Allocate blob_size for values + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); + else + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } + rc = apr_sdbm_nextkey(dbm, &key); + } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto error; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return -1; +} From 0708339359c8481751160a287c65ae4e595667a0 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 17:22:24 +0200 Subject: [PATCH 304/477] Centralized function to get user name, compatible with Linux & Windows (also with mpm-itk & mod_ruid2) --- apache2/msc_util.c | 11 + apache2/msc_util.h | 2 + apache2/persist_dbm.c | 1649 ++++++++++++++++++++--------------------- 3 files changed, 821 insertions(+), 841 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index cf9a393517..0ce58f919e 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2843,3 +2843,14 @@ char* strtok_r( } #endif +// Function compatible with Linux & Windows, also with mpm-itk & mod_ruid2 +char* get_username(apr_pool_t* mp) { + char* username; + apr_uid_t uid; + apr_gid_t gid; + int rc = apr_uid_current(&uid, &gid, mp); + if (rc != APR_SUCCESS) return "apache"; + rc = apr_uid_name_get(&username, uid, mp); + if (rc != APR_SUCCESS) return "apache"; + return username; +} diff --git a/apache2/msc_util.h b/apache2/msc_util.h index f7e1280f21..e4e043de16 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -159,6 +159,8 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, int DSOLOCAL ip_tree_from_param(apr_pool_t *pool, char *param, TreeRoot **rtree, char **error_msg); +char DSOLOCAL *get_username(apr_pool_t* mp); + #ifdef WITH_CURL int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index e4f8036f6f..0690ef80b8 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -1,841 +1,808 @@ -/* -* ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) -* -* You may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* If any of the files related to licensing are missing or if you have any -* other questions related to licensing please contact Trustwave Holdings, Inc. -* directly using the email address security@modsecurity.org. -*/ - -#include "persist_dbm.h" -#include "apr_sdbm.h" - -/** - * - */ -static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, - int log_vars) -{ - apr_table_t *col = NULL; - unsigned int blob_offset; - - col = apr_table_make(msr->mp, 32); - if (col == NULL) return NULL; - - /* ENH verify the first 3 bytes (header) */ - - blob_offset = 3; - while (blob_offset + 1 < blob_size) { - msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); - - var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - if (var->name_len == 0) { - /* Is the length a name length, or just the end of the blob? */ - if (blob_offset < blob_size - 2) { - /* This should never happen as the name length - * includes the terminating NUL and should be 1 for "" - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); - } - break; - } - else if (var->name_len > 65536) { - /* This should never happen as the length is restricted on store - * to 65536. - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); - break; - } - - blob_offset += 2; - if (blob_offset + var->name_len > blob_size) return NULL; - var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); - blob_offset += var->name_len; - var->name_len--; - - var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - blob_offset += 2; - - if (blob_offset + var->value_len > blob_size) return NULL; - var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); - blob_offset += var->value_len; - var->value_len--; - - if (log_vars && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - - apr_table_addn(col, var->name, (void *)var); - } - - return col; -} - -/** - * - */ -static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - char *dbm_filename = NULL; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t *value = NULL; - apr_sdbm_t *dbm = NULL; - apr_table_t *col = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int expired = 0; - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len)); - goto cleanup; - } - - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - - key.dptr = (char *)col_key; - key.dsize = col_key_len + 1; - - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); - rc = apr_sdbm_fetch(dbm, value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, - dbm_filename), get_apr_error(msr->mp, rc)); - goto cleanup; - } - - if (value->dptr == NULL) { /* Key not found in DBM file. */ - goto cleanup; - } - - /* ENH Need expiration (and perhaps other metadata) accessible in blob - * form to determine if converting to a table is needed. This will - * save some cycles. - */ - - /* Transform raw data into a table. */ - col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); - if (col == NULL) { - goto cleanup; - } - - /* Close after "value" used from fetch or memory may be overwritten. */ - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - /* Remove expired variables. */ - do { - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - if (strncmp(te[i].key, "__expire_", 9) == 0) { - msc_string *var = (msc_string *)te[i].val; - int expiry_time = atoi(var->value); - - if (expiry_time <= apr_time_sec(msr->request_time)) { - char *key_to_expire = te[i].key; - - /* Done early if the col expired */ - if (strcmp(key_to_expire, "__expire_KEY") == 0) { - expired = 1; - } - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); - } - - apr_table_unset(col, key_to_expire + 9); - apr_table_unset(col, key_to_expire); - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); - } - - break; - } - } - } - } while(!expired && (i != arr->nelts)); - - /* Delete the collection if the variable "KEY" does not exist. - * - * ENH It would probably be more efficient to hold the DBM - * open until determined if it needs deleted than to open a second - * time. - */ - if (apr_table_get(col, "KEY") == NULL) { - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto cleanup; - } - - - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - if (expired && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, - log_escape_ex(msr->mp, col_key, col_key_len)); - } - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - goto cleanup; - } - - /* Update UPDATE_RATE */ - { - msc_string *var; - int create_time, counter; - - var = (msc_string *)apr_table_get(col, "CREATE_TIME"); - if (var == NULL) { - /* Error. */ - } else { - create_time = atoi(var->value); - var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - if (var == NULL) { - /* Error. */ - } else { - apr_time_t td; - counter = atoi(var->value); - - /* UPDATE_RATE is removed on store, so add it back here */ - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_RATE"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - - /* NOTE: No rate if there has been no time elapsed */ - td = (apr_time_sec(apr_time_now()) - create_time); - if (td == 0) { - var->value = apr_psprintf(msr->mp, "%d", 0); - } - else { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, - (apr_time_t)((60 * counter)/td)); - } - var->value_len = strlen(var->value); - } - } - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - - if ((existing_dbm == NULL) && dbm) { - /* Should not ever get here */ - msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return col; - -cleanup: - - if ((existing_dbm == NULL) && dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return NULL; -} - -/** - * - */ -apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - apr_time_t time_before = apr_time_now(); - apr_table_t *rtable = NULL; - - rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); - - msr->time_storage_read += apr_time_now() - time_before; - - return rtable; -} - -/** - * - */ -int collection_store(modsec_rec *msr, apr_table_t *col) { - char *dbm_filename = NULL; - msc_string *var_name = NULL, *var_key = NULL; - unsigned char *blob = NULL; - unsigned int blob_size, blob_offset; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t value; - apr_sdbm_t *dbm = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int i; - const apr_table_t *stored_col = NULL; - const apr_table_t *orig_col = NULL; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { - goto error; - } - - var_key = (msc_string *)apr_table_get(col, "__key"); - if (var_key == NULL) { - goto error; - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - goto error; - } - - // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* Delete IS_NEW on store. */ - apr_table_unset(col, "IS_NEW"); - - /* Delete UPDATE_RATE on store to save space as it is calculated */ - apr_table_unset(col, "UPDATE_RATE"); - - /* Update the timeout value. */ - { - msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); - if (var != NULL) { - int timeout = atoi(var->value); - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var != NULL) { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); - var->value_len = strlen(var->value); - } - } - } - - /* LAST_UPDATE_TIME */ - { - msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "LAST_UPDATE_TIME"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); - var->value_len = strlen(var->value); - } - - /* UPDATE_COUNTER */ - { - msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - int counter = 0; - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_COUNTER"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } else { - counter = atoi(var->value); - } - var->value = apr_psprintf(msr->mp, "%d", counter + 1); - var->value_len = strlen(var->value); - } - - /* ENH Make the expiration timestamp accessible in blob form so that - * it is easier/faster to determine expiration without having to - * convert back to table form - */ - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - -#ifndef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* If there is an original value, then create a delta and - * apply the delta to the current value */ - orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); - if (orig_col != NULL) { - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", - apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); - } - - stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); - } - - /* Merge deltas and calculate the size first. */ - blob_size = 3 + 2; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - /* If there is an original value, then apply the delta - * to the latest stored value */ - if (stored_col != NULL) { - const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); - if (orig_var != NULL) { - const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); - if (stored_var != NULL) { - int origval = atoi(orig_var->value); - int ourval = atoi(var->value); - int storedval = atoi(stored_var->value); - int delta = ourval - origval; - int newval = storedval + delta; - - if (newval < 0) newval = 0; /* Counters never go below zero. */ - - var->value = apr_psprintf(msr->mp, "%d", newval); - var->value_len = strlen(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var->name, var->name_len), - origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); - } - } - } - } - - // Allocate blob_size for keys - len = var->name_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - - // Allocate blob_size for values - len = var->value_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - } - - /* Now generate the binary object. */ - blob = apr_pcalloc(msr->mp, blob_size); - if (blob == NULL) { - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - - blob[0] = 0x49; - blob[1] = 0x52; - blob[2] = 0x01; - - blob_offset = 3; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - len = var->name_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->name, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - len = var->value_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->value, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - } - - blob[blob_offset] = 0; - blob[blob_offset + 1] = 0; - - /* And, finally, store it. */ - key.dptr = var_key->value; - key.dsize = var_key->value_len + 1; - - value.dptr = (char *)blob; - value.dsize = blob_size; - - rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - } - - return 0; - -error: - return -1; -} - -/** - * - */ -int collections_remove_stale(modsec_rec *msr, const char *col_name) { - char *dbm_filename = NULL; - apr_sdbm_datum_t key, value; - apr_sdbm_t *dbm = NULL; - apr_status_t rc; - apr_array_header_t *keys_arr; - char **keys; - apr_time_t now = apr_time_sec(msr->request_time); - int i; - - /** - * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations - */ - char *userinfo; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, msr->mp); - rc = apr_uid_name_get(&userinfo, uid, msr->mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(msr->mp, "%u", uid); - } - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. - * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " - * "define data directory first.", log_escape(msr->mp, col_name)); - */ - goto error; - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - - /* First get a list of all keys. */ - keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - -#ifndef GLOBAL_COLLECTION_LOCK - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* No one can write to the file while doing this so - * do it as fast as possible. - */ - rc = apr_sdbm_firstkey(dbm, &key); - while(rc == APR_SUCCESS) { - if (key.dsize) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); - *(char **)apr_array_push(keys_arr) = s; - } - rc = apr_sdbm_nextkey(dbm, &key); - } -#ifndef GLOBAL_COLLECTION_LOCK - apr_sdbm_unlock(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, - log_escape(msr->mp, dbm_filename)); - } - - /* Now retrieve the entires one by one. */ - keys = (char **)keys_arr->elts; - for (i = 0; i < keys_arr->nelts; i++) { - key.dptr = keys[i]; - key.dsize = strlen(key.dptr) + 1; - - rc = apr_sdbm_fetch(dbm, &value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - goto error; - } - - if (value.dptr != NULL) { - apr_table_t *col = NULL; - msc_string *var = NULL; - - col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); - if (col == NULL) { - goto error; - } - - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var == NULL) { - msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " - "__expire_KEY (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } else { - unsigned int expiry_time = atoi(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), - expiry_time - now); - } - - if (expiry_time <= now) { - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto error; - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " - "key \"%s\").", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } - } - } - } else { - /* Ignore entry not found - it may have been removed in the meantime. */ - } - } - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - return 1; - -error: - - if (dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return -1; -} +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); + } + + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); + } + + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, + log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +ÿ�nd罎 + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + apr_time_t time_before = apr_time_now(); + apr_table_t *rtable = NULL; + + rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); + + msr->time_storage_read += apr_time_now() - time_before; + + return rtable; +} + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + char *userinfo = get_username(msr->mp); + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", + apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + // Allocate blob_size for keys + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + // Allocate blob_size for values + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + char *userinfo = get_username(msr->mp); + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); + else + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } + rc = apr_sdbm_nextkey(dbm, &key); + } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto error; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return -1; +} From 0d5a8dec2af8ac230cb12975500ec55a0992b0e5 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 11 Aug 2023 17:41:04 +0200 Subject: [PATCH 305/477] Compatibility with libyajl decoding the buffer inline --- apache2/msc_json.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 17f938b64e..f80fc18d73 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -354,7 +354,9 @@ int json_init(modsec_rec *msr, char **error_msg) { int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; - base_offset=buf; + // Take a copy in case libyajl decodes the buffer inline + base_offset = apr_pstrmemdup(msr->mp, buf, size); + if (!base_offset) return -1; /* Feed our parser and catch any errors */ msr->json->status = yajl_parse(msr->json->handle, buf, size); From 7575eae3f52e60cdf4e6105939caa3d8c455bf46 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 14 Aug 2023 16:57:21 +0200 Subject: [PATCH 306/477] Check return code of apr_procattr_io_set() --- apache2/apache2_util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index cdae2b5808..d76da7558d 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -99,7 +99,12 @@ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char * return -1; } - apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); + rc = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Exec: apr_procattr_io_set failed: %d (%s)", rc, get_apr_error(r->pool, rc)); + return -1; + } + apr_procattr_cmdtype_set(procattr, APR_SHELLCMD); if (msr->txcfg->debuglog_level >= 9) { From 25a60e259ad10e0c83c6f2ffb1737c4da53bb76e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 16 Aug 2023 08:25:50 +0200 Subject: [PATCH 307/477] Fixed 2 memory leaks --- apache2/re.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..35b89a7fc4 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -386,8 +386,13 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } else { target = strdup(p); - if(target == NULL) - return NULL; + if(target == NULL) { + if(target_list != NULL) + free(target_list); + if(replace != NULL) + free(replace); + return NULL; + } is_negated = is_counting = 0; param = name = value = NULL; @@ -421,6 +426,8 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r free(target_list); if(replace != NULL) free(replace); + if(target != NULL) + free(target); if(msr) { msr_log(msr, 9, "Error to update target - [%s] is not valid target", name); } From 541707c0aa8ca3ec61952823cfa9d04312b1fa25 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 16 Aug 2023 08:28:12 +0200 Subject: [PATCH 308/477] removed useless code --- apache2/re.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 35b89a7fc4..6a3de38fa2 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -519,18 +519,12 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } end: - if(target_list != NULL) { + if(target_list != NULL) free(target_list); - target_list = NULL; - } - if(replace != NULL) { + if(replace != NULL) free(replace); - replace = NULL; - } - if(target != NULL) { + if(target != NULL) free(target); - target = NULL; - } return NULL; } From 82c69ccf4968d45528d8c9a067d24bbb54938c6d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 16 Aug 2023 08:50:09 +0200 Subject: [PATCH 309/477] Fix for DEBUG_CONF compile flag --- apache2/re.c | 5 ++++- apache2/re.h | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..cac54779aa 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -637,7 +637,10 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) { /** * Generate an action string from an actionset. */ -static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { +#ifndef DEBUG_CONF + static +#endif +char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { const apr_array_header_t *tarr = NULL; const apr_table_entry_t *telts = NULL; char *actions = NULL; diff --git a/apache2/re.h b/apache2/re.h index c0c5433965..e268d8a210 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -75,6 +75,10 @@ int DSOLOCAL rule_id_in_range(int ruleid, const char *range); msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); +#ifdef DEBUG_CONF + char DSOLOCAL* msre_actionset_generate_action_string(apr_pool_t* pool, const msre_actionset* actionset); +#endif + #if defined(WITH_LUA) apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); From ba227fa7313def25403a9b4cb9cc533e220d308f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 16 Aug 2023 16:54:55 +0200 Subject: [PATCH 310/477] Fix for https://github.com/SpiderLabs/ModSecurity/issues/610 --- apache2/msc_pcre.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 6f1a9a186c..86bb16010c 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -31,11 +31,7 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { } #else if (regex->pe != NULL) { -#if defined(VERSION_NGINX) pcre_free(regex->pe); -#else - free(regex->pe); -#endif regex->pe = NULL; } if (regex->re != NULL) { @@ -152,19 +148,15 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - pe = pcre_study(regex->re, PCRE_STUDY_JIT_COMPILE, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED|PCRE_STUDY_JIT_COMPILE, &errptr); #else - pe = pcre_study(regex->re, 0, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED, &errptr); #endif #endif /* Setup the pcre_extra record if pcre_study did not already do it */ if (pe == NULL) { -#if defined(VERSION_NGINX) - pe = pcre_malloc(sizeof(pcre_extra)); -#else - pe = malloc(sizeof(pcre_extra)); -#endif + pe = (pcre_extra*)pcre_malloc(sizeof(pcre_extra)); if (pe == NULL) { return NULL; } From 1a552bcc5d33a2c75a66d5b05928dd10947fb1fd Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 18 Aug 2023 16:47:00 +0200 Subject: [PATCH 311/477] Update msc_json.c --- apache2/msc_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index f80fc18d73..16a2fa10dc 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -359,7 +359,7 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char if (!base_offset) return -1; /* Feed our parser and catch any errors */ - msr->json->status = yajl_parse(msr->json->handle, buf, size); + msr->json->status = yajl_parse(msr->json->handle, (unsigned char*)base_offset, size); if (msr->json->status != yajl_status_ok) { if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; From ea1d78c80e327e8c9ddb6d99468e3dc60e40c8b0 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 18 Aug 2023 16:48:25 +0200 Subject: [PATCH 312/477] Update msc_json.c --- apache2/msc_json.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 16a2fa10dc..e9d0c99d0d 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -364,7 +364,7 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; } else { - char *yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); + char *yajl_err = yajl_get_error(msr->json->handle, 0, base_offset, size); *error_msg = apr_pstrdup(msr->mp, yajl_err); yajl_free_error(msr->json->handle, yajl_err); } From 063fc9f5c89e09b4a3be0881a9f68093f1674da6 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 18 Aug 2023 16:54:19 +0200 Subject: [PATCH 313/477] Update msc_logging.c --- apache2/msc_logging.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 7f286500f9..cdd116f8ff 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -234,15 +234,7 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations * It also changes the return statement. */ - char *userinfo; - apr_status_t rc; - apr_uid_t uid; - apr_gid_t gid; - apr_uid_current(&uid, &gid, mp); - rc = apr_uid_name_get(&userinfo, uid, mp); - if (rc != APR_SUCCESS) { - userinfo = apr_psprintf(mp, "%u", uid); - } + char *userinfo = get_username(mp); apr_time_exp_lt(&t, apr_time_now()); From afe4e1282824bb5238b8a57daf6cd333ec10d199 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 18 Aug 2023 17:16:18 +0200 Subject: [PATCH 314/477] Update persist_dbm.c --- apache2/persist_dbm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 0690ef80b8..edd41c11ab 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -334,7 +334,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -ÿ�nd罎 +#endif } return NULL; From 9c0d05f73470b3e6acb1078d8b59a837b363731a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 21 Aug 2023 09:33:27 +0200 Subject: [PATCH 315/477] Update re_operators.c --- apache2/re_operators.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 07dca7df43..77b1b4132f 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1535,10 +1535,10 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l url = apr_palloc(pool, len + 1); data = apr_palloc(pool, len + 1); - memset(data, 0, len+1); - memset(url, 0, len+1); - + data[0] = '\0'; + memcpy(url, domain, len); + url[len] = 0; while(( pos = strstr(url , "/./" )) != NULL) { match = 1; From 931f8b6ed455fa91d5eead31a34c6320e3cfc1ca Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 21 Aug 2023 09:39:42 +0200 Subject: [PATCH 316/477] Update re_operators.c --- apache2/re_operators.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 77b1b4132f..7cdf58961a 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -751,7 +751,6 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v char *my_error_msg = NULL; int ovector[33]; int rc; - const char *pattern = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT int jit; @@ -781,8 +780,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); - pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { + const char *pattern = log_escape_re(msr->mp, re_pattern->value); msr_log(msr, 6, "Escaping pattern [%s]",pattern); } From eab780e992578a50e256d09a71abcb354bad636a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 21 Aug 2023 10:01:46 +0200 Subject: [PATCH 317/477] typo --- apache2/re.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 6a3de38fa2..39f3786297 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -378,7 +378,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } #if !defined(MSC_TEST) else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find varibale to replace"); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find variable to replace"); } #endif goto end; From 18efc80bdd65b59111056275588cc819a99c03fd Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 21 Aug 2023 10:30:36 +0200 Subject: [PATCH 318/477] Double memory allocation: 'current_targets' is allocated in ruleset->mp. 'rule->p1' is a copy of current_targets, but we strdup it in the same memory pool as 'current_targets'. So, simply assign 'current_targets' to 'rule->p1'. --- apache2/re.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..aafb2b5ad4 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -499,7 +499,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if(var_appended == 1) { current_targets = msre_generate_target_string(ruleset->mp, rule); rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, current_targets, NULL, NULL); - rule->p1 = apr_pstrdup(ruleset->mp, current_targets); + rule->p1 = current_targets; if(msr) { msr_log(msr, 9, "Successfully appended variable"); } From d4310f54cc2bc0b0eb55b9f6f503b446536740a5 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Thu, 24 Aug 2023 15:01:14 -0700 Subject: [PATCH 319/477] Configure: do not check for pcre1 if pcre2 requested --- build/find_pcre.m4 | 110 +++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index 0c42fed60a..2cff8f3ccb 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -21,69 +21,73 @@ AC_ARG_WITH( [test_paths="${with_pcre}"], [test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr"]) -AC_MSG_CHECKING([for libpcre config script]) - -dnl # Determine pcre lib directory -if test -z "${with_pcre}"; then - test_paths="/usr/local/pcre /usr/local /usr" +if test "x${with_pcre2}" != "x" && test "x${with_pcre2}" != "xno"; then + AC_MSG_NOTICE([pcre2 specified; omitting check for pcre]) else - test_paths="${with_pcre}" -fi + AC_MSG_CHECKING([for libpcre config script]) -for x in ${test_paths}; do - dnl # Determine if the script was specified and use it directly - if test ! -d "$x" -a -e "$x"; then - PCRE_CONFIG=$x - pcre_path="no" - break + dnl # Determine pcre lib directory + if test -z "${with_pcre}"; then + test_paths="/usr/local/pcre /usr/local /usr" + else + test_paths="${with_pcre}" fi - dnl # Try known config script names/locations - for PCRE_CONFIG in pcre-config; do - if test -e "${x}/bin/${PCRE_CONFIG}"; then - pcre_path="${x}/bin" + for x in ${test_paths}; do + dnl # Determine if the script was specified and use it directly + if test ! -d "$x" -a -e "$x"; then + PCRE_CONFIG=$x + pcre_path="no" break - elif test -e "${x}/${PCRE_CONFIG}"; then - pcre_path="${x}" + fi + + dnl # Try known config script names/locations + for PCRE_CONFIG in pcre-config; do + if test -e "${x}/bin/${PCRE_CONFIG}"; then + pcre_path="${x}/bin" + break + elif test -e "${x}/${PCRE_CONFIG}"; then + pcre_path="${x}" + break + else + pcre_path="" + fi + done + if test -n "$pcre_path"; then break - else - pcre_path="" fi done - if test -n "$pcre_path"; then - break - fi -done -if test -n "${pcre_path}"; then - if test "${pcre_path}" != "no"; then - PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}" + if test -n "${pcre_path}"; then + if test "${pcre_path}" != "no"; then + PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}" + fi + AC_MSG_RESULT([${PCRE_CONFIG}]) + PCRE_VERSION="`${PCRE_CONFIG} --version`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre VERSION: $PCRE_VERSION); fi + PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi + PCRE_LDADD="`${PCRE_CONFIG} --libs`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre LDADD: $PCRE_LDADD); fi + PCRE_LD_PATH="/`${PCRE_CONFIG} --libs | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre PCRE_LD_PATH: $PCRE_LD_PATH); fi + else + AC_MSG_RESULT([no]) fi - AC_MSG_RESULT([${PCRE_CONFIG}]) - PCRE_VERSION="`${PCRE_CONFIG} --version`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre VERSION: $PCRE_VERSION); fi - PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi - PCRE_LDADD="`${PCRE_CONFIG} --libs`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre LDADD: $PCRE_LDADD); fi - PCRE_LD_PATH="/`${PCRE_CONFIG} --libs | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre PCRE_LD_PATH: $PCRE_LD_PATH); fi -else - AC_MSG_RESULT([no]) -fi -AC_SUBST(PCRE_CONFIG) -AC_SUBST(PCRE_VERSION) -AC_SUBST(PCRE_CPPFLAGS) -AC_SUBST(PCRE_CFLAGS) -AC_SUBST(PCRE_LDFLAGS) -AC_SUBST(PCRE_LDADD) -AC_SUBST(PCRE_LD_PATH) + AC_SUBST(PCRE_CONFIG) + AC_SUBST(PCRE_VERSION) + AC_SUBST(PCRE_CPPFLAGS) + AC_SUBST(PCRE_CFLAGS) + AC_SUBST(PCRE_LDFLAGS) + AC_SUBST(PCRE_LDADD) + AC_SUBST(PCRE_LD_PATH) -if test -z "${PCRE_VERSION}"; then - AC_MSG_NOTICE([*** pcre library not found.]) -else - AC_MSG_NOTICE([using pcre v${PCRE_VERSION}]) - ifelse([$1], , , $1) -fi + if test -z "${PCRE_VERSION}"; then + AC_MSG_NOTICE([*** pcre library not found.]) + else + AC_MSG_NOTICE([using pcre v${PCRE_VERSION}]) + ifelse([$1], , , $1) + fi +fi ]) From 0dbdc2b3d00e3cf18a871779378946f04dab2921 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 11 Sep 2023 08:07:49 -0700 Subject: [PATCH 320/477] Check return code of apr_procattr_io_set() --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 15ea1c2ff1..f5893a8912 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Check return code of apr_procattr_io_set() + [Issue #2958 - @marcstern] * Do not escape special chars in rx pattern with macro [Issue #2357 - @marcstern, @martinhsv] * Substitute two equals-equals operators in build From 077d1bd0b73fc729c29b509cab78a1900903cb70 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 25 Sep 2023 16:00:17 +0200 Subject: [PATCH 321/477] if WITH_PCRE2 id defined, jit was not initialized --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index cfd8952539..b5e0d73e27 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -958,7 +958,7 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit; + int rc, jit = 0; #endif #endif From 1d9ad64a565e8c67da79d782ec826fbe573c7ab7 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 25 Sep 2023 16:15:19 +0200 Subject: [PATCH 322/477] if WITH_PCRE2 id defined, jit was not initialized --- apache2/re_operators.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b5e0d73e27..d2a725da32 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -688,7 +688,7 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit; + int rc, jit = 0; #endif #endif @@ -764,7 +764,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v const char *pattern = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -1028,7 +1028,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -2841,7 +2841,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -3171,7 +3171,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -3485,7 +3485,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif From 40c6f80ccffb16cf16c6e7ec525aea5fa8f5e828 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 3 Oct 2023 16:50:12 +0200 Subject: [PATCH 323/477] Avoid some useless code and memory allocation in case no macro is present --- apache2/re_actions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 02ec07d222..94909c5591 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -273,6 +273,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t next_text_start = p + 1; } } else { + if (arr->nelts == 0) return 0; /* no macro */ /* Text part. */ part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); part->value = apr_pstrdup(mptmp, text_start); From d644ebee0a45102d3237f98d02b3916a4ed9e1a7 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 5 Oct 2023 14:48:24 +0200 Subject: [PATCH 324/477] Implemented msre_action_phase_validate() --- apache2/re_actions.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 02ec07d222..e4b2d2ba55 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -755,8 +755,15 @@ static char *msre_action_allow_validate(msre_engine *engine, apr_pool_t *mp, msr /* phase */ static char *msre_action_phase_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { - /* ENH Add validation. */ - return NULL; + if (strcasecmp(action->param, "request") == 0) return NULL; + if (strcasecmp(action->param, "response") == 0) return NULL; + if (strcasecmp(action->param, "logging") == 0) return NULL; + if (strcasecmp(action->param, "1") == 0) return NULL; + if (strcasecmp(action->param, "2") == 0) return NULL; + if (strcasecmp(action->param, "3") == 0) return NULL; + if (strcasecmp(action->param, "4") == 0) return NULL; + if (strcasecmp(action->param, "5") == 0) return NULL; + return apr_psprintf(mp, "Invalid parameter for phase: %s", action->param);; } static apr_status_t msre_action_phase_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, From 29dbf829cd6342139fb9ffc713402c7a211102ae Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Thu, 12 Oct 2023 07:55:56 -0700 Subject: [PATCH 325/477] Add CHANGES entry for previous merge --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index f5893a8912..1946c2a420 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Configure: do not check for pcre1 if pcre2 requested + [Issue #2975 - @zhaoshikui, @martinhsv] * Check return code of apr_procattr_io_set() [Issue #2958 - @marcstern] * Do not escape special chars in rx pattern with macro From e4acb3c39178867e9eec0de444ca4a150f664d64 Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Mon, 16 Oct 2023 12:45:36 -0700 Subject: [PATCH 326/477] Allow lua version 5.4 --- CHANGES | 2 ++ apache2/msc_lua.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGES b/CHANGES index 1946c2a420..3a75c62c87 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Allow lua version 5.4 + [Issue #2996 - @3eka, @martinhsv] * Configure: do not check for pcre1 if pcre2 requested [Issue #2975 - @zhaoshikui, @martinhsv] * Check return code of apr_procattr_io_set() diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index 51be1745b2..2f05df651d 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -429,12 +429,12 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul #else /* Create new state. */ -#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 501 +#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504 || LUA_VERSION_NUM == 501 L = luaL_newstate(); #elif LUA_VERSION_NUM == 500 L = lua_open(); #else -#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. +#error We are only tested under Lua 5.0, 5.1, 5.2, 5.3, or 5.4. #endif luaL_openlibs(L); @@ -459,10 +459,10 @@ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rul /* Register functions. */ #if LUA_VERSION_NUM == 500 || LUA_VERSION_NUM == 501 luaL_register(L, "m", mylib); -#elif LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 +#elif LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 || LUA_VERSION_NUM == 504 luaL_setfuncs(L, mylib, 0); #else -#error We are only tested under Lua 5.0, 5.1, 5.2, or 5.3. +#error We are only tested under Lua 5.0, 5.1, 5.2, 5.3, or 5.4. #endif lua_setglobal(L, "m"); From 5c9d8cd7760b6bcc679bf4c009e279ad60acc67d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 17 Oct 2023 14:06:56 +0200 Subject: [PATCH 327/477] Add context info to error message --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..8efea2d15e 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -353,11 +353,11 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { if(msr) { - msr_log(msr, 9, "Error parsing rule targets to replace variable"); + msr_log(msr, 9, "Error parsing rule targets to replace variable: %s", my_error_msg); } #if !defined(MSC_TEST) else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable"); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable: %s", my_error_msg); } #endif goto end; From 5e17e6dfc485b3ffd055bf461109ab083da3517e Mon Sep 17 00:00:00 2001 From: Martin Vierula <martin.vierula@trustwave.com> Date: Tue, 17 Oct 2023 06:37:08 -0700 Subject: [PATCH 328/477] Configure: correct log message typo --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 81a1a6b62e..7c11873c77 100644 --- a/configure.ac +++ b/configure.ac @@ -245,7 +245,7 @@ AC_ARG_ENABLE(mlogc, CHECK_CURL() if test -z "${CURL_VERSION}"; then - AC_MSG_NOTICE([NOTE: mlgoc compilation was disabled.]) + AC_MSG_NOTICE([NOTE: mlogc compilation was disabled.]) build_mlogc=0 fi From 6a24bc47d511ade77a264cc219634ed7a529a107 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 26 Oct 2023 09:22:22 +0200 Subject: [PATCH 329/477] Ignore empty action instead of storing it --- apache2/re.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..d65b0fef8f 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1054,6 +1054,12 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, /* ignore whitespace */ while(isspace(*p)) p++; if (*p == '\0') return count; + + /* ignore empty action */ + if (*p == ',') { + p++; + continue; + } /* we are at the beginning of the name */ name = p; From 608cd1d09dc68d8e20cd520206b836676be919a1 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 26 Oct 2023 14:21:32 +0200 Subject: [PATCH 330/477] Avoid last loop and storing an empty value in case nothing after last %{..} macro --- apache2/re_actions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 02ec07d222..6bd8665553 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -279,7 +279,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t part->value_len = strlen(part->value); *(msc_string **)apr_array_push(arr) = part; } - } while (p != NULL); + } while (p != NULL && *next_text_start); /* If there's more than one member of the array that * means there was at least one macro present. Combine From 31dae62f4145604da0bc94b2beed0af3dce04218 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 26 Oct 2023 15:00:10 +0200 Subject: [PATCH 331/477] Don't store empty string before macro and empty macro result --- apache2/re_actions.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 6bd8665553..d3e60c97de 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -228,18 +228,20 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t msre_var *var_resolved = NULL; /* Add the text part before the macro to the array. */ + if (p != text_start) { part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); if (part == NULL) return -1; part->value_len = p - text_start; part->value = apr_pstrmemdup(mptmp, text_start, part->value_len); *(msc_string **)apr_array_push(arr) = part; + } /* Resolve the macro and add that to the array. */ var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value, msr, &my_error_msg); if (var_resolved != NULL) { var_generated = generate_single_var(msr, var_resolved, NULL, rule, mptmp); - if (var_generated != NULL) { + if (var_generated != NULL && var_generated->value_len) { part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); if (part == NULL) return -1; part->value_len = var_generated->value_len; From 029fdedc67ecc788126381d69f2d1186f1a406b4 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 26 Oct 2023 15:55:57 +0200 Subject: [PATCH 332/477] useless (and now incorrect) check --- apache2/re_actions.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index d3e60c97de..8818f0b336 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -283,11 +283,9 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t } } while (p != NULL && *next_text_start); - /* If there's more than one member of the array that - * means there was at least one macro present. Combine - * text parts into a single string now. + /* Combine text parts into a single string now. + * If no macro was present, we already returned */ - if (arr->nelts > 1) { /* Figure out the required size for the string. */ var->value_len = 0; for(i = 0; i < arr->nelts; i++) { @@ -307,7 +305,6 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t offset += part->value_len; } var->value[offset] = '\0'; - } return 1; } From 9977870bc57e6cfe2a2bdfb64456abafeb1c5f2d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 31 Oct 2023 12:55:07 +0100 Subject: [PATCH 333/477] avoid useless loops --- apache2/re.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re.c b/apache2/re.c index 9ded3be796..fb49e6f361 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -575,6 +575,7 @@ int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) { &my_error_msg); if (rc >= 0) { match = 1; + break; } } } From 285f7efdfaddf1861ac447a7262a7bdbbfbc7215 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 31 Oct 2023 13:01:19 +0100 Subject: [PATCH 334/477] avoid useless loops --- apache2/re.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re.c b/apache2/re.c index fb49e6f361..1fc897697c 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2132,6 +2132,7 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, &my_error_msg); if (rc >= 0) { remove_rule = 1; + break; } } } From a6d3397b512560512978edf5f986f3fa954a9d4c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 2 Nov 2023 13:21:39 +0100 Subject: [PATCH 335/477] removeByTag wasn't executed if no rule id is present in the rule --- apache2/re.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 1fc897697c..9b9df85547 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -76,7 +76,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(rule->actionset == NULL) return 0; - if(rule->actionset->id !=NULL) { + { myvar = apr_pstrdup(msr->mp, var->name); From bacb0f3d767c6d4cf73150d5aec251cc7e6ca76f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 2 Nov 2023 13:30:16 +0100 Subject: [PATCH 336/477] Revert "avoid useless loops" This reverts commit 9977870bc57e6cfe2a2bdfb64456abafeb1c5f2d. --- apache2/re.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 9b9df85547..4130982d13 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -575,7 +575,6 @@ int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) { &my_error_msg); if (rc >= 0) { match = 1; - break; } } } @@ -2132,7 +2131,6 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, &my_error_msg); if (rc >= 0) { remove_rule = 1; - break; } } } From b687f51840a855d3c08989799b27c503b670193a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sat, 27 Jan 2024 17:09:43 +0100 Subject: [PATCH 337/477] Set the minimum security protocol version for SecRemoteRules --- CHANGES | 2 ++ apache2/msc_remote_rules.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 3a75c62c87..517e76b74c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Set the minimum security protocol version for SecRemoteRules + [Issue security/code-scanning/2 - @airween] * Allow lua version 5.4 [Issue #2996 - @3eka, @martinhsv] * Configure: do not check for pcre1 if pcre2 requested diff --git a/apache2/msc_remote_rules.c b/apache2/msc_remote_rules.c index 99968f0405..37b8864842 100644 --- a/apache2/msc_remote_rules.c +++ b/apache2/msc_remote_rules.c @@ -331,8 +331,8 @@ int msc_remote_download_content(apr_pool_t *mp, const char *uri, const char *key headers_chunk = curl_slist_append(headers_chunk, header_key); } - /* Make it TLS 1.x only. */ - curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); + /* Make it TLS 1.2 at least. */ + curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); #ifdef WIN32 res_len = SearchPathA(NULL, "curl-ca-bundle.crt", NULL, (2048 + 1), buf, &ptr); From 91c535c96b7f66a39d4c528ffe1965956ba3c4c1 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sun, 28 Jan 2024 09:40:40 +0100 Subject: [PATCH 338/477] Replace the organization name in references; change the security e-mail --- README.md | 4 ++-- doc/README.txt | 2 +- iis/dependencies/howto.txt | 2 +- iis/installer.wxs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d489f846b7..7223af738a 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,12 @@ Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) You may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 -If any of the files related to licensing are missing or if you have any other questions related to licensing please contact Trustwave Holdings, Inc. directly using the email address: security@modsecurity.org. +If any of the files related to licensing are missing or if you have any other questions related to licensing please contact Trustwave Holdings, Inc. directly using the email address: modsecurity@owasp.org. ## Documentation -Please refer to: [the documentation folder](https://github.com/SpiderLabs/ModSecurity/tree/v2/master/doc) for the reference manual. +Please refer to: [the documentation folder](https://github.com/owasp-modsecurity/ModSecurity/tree/v2/master/doc) for the reference manual. ## Sponsor Note diff --git a/doc/README.txt b/doc/README.txt index ec0ed3572d..75bfac094c 100644 --- a/doc/README.txt +++ b/doc/README.txt @@ -8,4 +8,4 @@ Please access the ModSecurity Github space to access the below documentation. * Reference Manual * RoadMap -https://github.com/SpiderLabs/ModSecurity/wiki/ +https://github.com/owasp-modsecurity/ModSecurity/wiki/ diff --git a/iis/dependencies/howto.txt b/iis/dependencies/howto.txt index 55f9184bf4..830851f95a 100644 --- a/iis/dependencies/howto.txt +++ b/iis/dependencies/howto.txt @@ -38,7 +38,7 @@ ssdeep-2.13 -------------------------------------- -1. Create working directory (e.g. c:\work) and drop the latest clone from ModSecurity's 2.x Github (https://github.com/SpiderLabs/ModSecurity/archive/v2/master.zip) +1. Create working directory (e.g. c:\work) and drop the latest clone from ModSecurity's 2.x Github (https://github.com/owasp-modsecurity/ModSecurity/archive/v2/master.zip) 2. Make sure the prerequisites mentioned above are all set 3. If you haven't download the dependency files before, uncomment the "@call download_files.bat" line on build_dependencies.bat to have them downloaded prior 4. Open a command prompt (cmd.exe) and head to the "iis" folder inside ModSecurity tree working directory (e.g. cd c:\work\ModSecurity\iis) diff --git a/iis/installer.wxs b/iis/installer.wxs index 6ef3c05e6f..17ed02c047 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -616,8 +616,8 @@ <Control Id="Title" Type="Text" X="15" Y="6" Width="210" Height="15" Transparent="yes" NoPrefix="yes" Text="{\WixUI_Font_Title}IIS Setup" /> <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Choose to configure ModSecurity on IIS or not." /> <Control Id="Text" Type="Text" X="25" Y="55" Width="320" Height="50" Text="ModSecurityIIS needs to be configured under IIS as a module. It is recommended to perform this configuration during the installation. However, if you are facing problems in the installation, the recomendation is to disable this step. This will facilitate the debugging process since the files will be installed in place. Note that some scripts will be installed along with ModSecurity common files that can be later used to help this configuration/debugging process." /> - <Control Type="CheckBox" Id="ConfigureIIS" Width="200" Height="14" X="25" Y="124" CheckBoxValue="1" Property="IIS_SETUP" Text="Perform ModSecurityIIS configuration." /> - <Control Type="Text" Id="troubleshooting" Width="314" Height="67" X="26" Y="161" Text="For further information about problems during the installation, have a look at ModSecurityIIS Troubleshooting guide. Available at: https://github.com/SpiderLabs/ModSecurity/wiki/IIS-Troubleshooting. ATTENTION: This installation process no longer install OWASP CRS. Please refer to the OWASP CRS Project to understand how to install it. " /> + <Control Type="CheckBox" Id="ConfigureIIS" Width="200" Height="14" X="25" Y="124" CheckBoxValue="1" Property="IIS_SETUP" Text="Perform ModSecurityIIS configuration." /> + <Control Type="Text" Id="troubleshooting" Width="314" Height="67" X="26" Y="161" Text="For further information about problems during the installation, have a look at ModSecurityIIS Troubleshooting guide. Available at: https://github.com/owasp-modsecurity/ModSecurity/wiki/IIS-Troubleshooting. ATTENTION: This installation process no longer install OWASP CRS. Please refer to the OWASP CRS Project to understand how to install it. " /> </Dialog> <Binary Id="bannrbmp" SourceFile="wix\banner.jpg" /> <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" /> From 35e97b51459ab95d845e72ef55428b662bba0ee9 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 1 Feb 2024 11:48:21 +0100 Subject: [PATCH 339/477] When there's a problem writing a collection key (it's too big for instance), we have no info on the involved key. This adds the key name in the log (and its size, as this is the problem most of the time). --- apache2/apache2_config.c | 3 +++ apache2/persist_dbm.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 74c76a5810..6b71dea7eb 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1749,6 +1749,9 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME, mp); + if (config_orig_path == NULL) { + return apr_psprintf(mp, "ModSecurity: failed to duplicate filename in parser_conn_limits_operator"); + } if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) || (strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) { diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index edd41c11ab..b71796bd58 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -608,8 +608,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s (key=%s, length=%d)", dbm_filename, + get_apr_error(msr->mp, rc), key.dptr, value.dsize); if (dbm != NULL) { #ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); From 47e28af184296734f2c93c281b1fdddb5e63621c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 1 Feb 2024 12:18:08 +0100 Subject: [PATCH 340/477] ; incorrectly replaced by space in cmdline --- apache2/re_tfns.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apache2/re_tfns.c b/apache2/re_tfns.c index 63068dae8c..3bfc0be5d9 100644 --- a/apache2/re_tfns.c +++ b/apache2/re_tfns.c @@ -57,7 +57,6 @@ static int msre_fn_cmdline_execute(apr_pool_t *mptmp, unsigned char *input, /* replace some characters to space (only one) */ case ' ': case ',': - case ';': case '\t': case '\r': case '\n': From 864f54c643fe7a2f200a4643b967b6ca4c7435b8 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 2 Feb 2024 13:05:10 +0100 Subject: [PATCH 341/477] Updated CHANGES --- CHANGES | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CHANGES b/CHANGES index 517e76b74c..1703d3ebac 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,34 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Support for PCRE2 in Windows + [PR #2931, @leancz] + * Fix ; incorrectly replaced by space in t:cmdline + [PR #3051, @marcstern] + * Add some syntax validation + [PR #2994, @marcstern] + * Optimize macro processing + [PR #2992/3004, @marcstern] + * Add detailed error message when writing collections + [PR #3050, @marcstern] + * Add context info to error message + [PR #2997, @marcstern] + * Fix ctl:ruleRemoveByTag that isn't executed if no rule id is present + [PR #3012, @marcstern] + * Ignore empty action instead of storing it + [PR #3003, @marcstern] + * Fixed memory leak if builded modsecurity with --enable-pcre-study + [Issue #610, @marcstern] + * Remove useless code + [PR #2953/2954, @marcstern] + * Centralized function to get user name, compatible with Linux & Windows + [PR #2956, @marcstern] + * Compatibility with libyajl decoding the buffer inline + [PR #2957, @marcstern] + * Fixed memory leaks + [PR #2960/2963/2969, @marcstern] + * Fixed uninitialized variable + [PR #2987, @marcstern] * Set the minimum security protocol version for SecRemoteRules [Issue security/code-scanning/2 - @airween] * Allow lua version 5.4 From 0cd8b15c5a780951714e83f9dc907f93562df268 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 5 Feb 2024 10:36:04 +0100 Subject: [PATCH 342/477] Fixed variable definition scope (compile error) --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 138a17d6ff..76aefb41e9 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -780,8 +780,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); + const char *pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - const char *pattern = log_escape_re(msr->mp, re_pattern->value); msr_log(msr, 6, "Escaping pattern [%s]",pattern); } From e406bcadcde84b14f2ecba28ea55b653efb3d25a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 6 Feb 2024 09:54:07 +0100 Subject: [PATCH 343/477] Fixed compilation issue (variable scope definition) --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 138a17d6ff..76aefb41e9 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -780,8 +780,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); + const char *pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - const char *pattern = log_escape_re(msr->mp, re_pattern->value); msr_log(msr, 6, "Escaping pattern [%s]",pattern); } From 07f4076f4609463b3c9989f6e7662f5c1e2cae77 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 7 Feb 2024 12:04:50 +0100 Subject: [PATCH 344/477] Check for NULL pointers --- apache2/apache2_config.c | 16 +-- apache2/msc_tree.c | 1 + apache2/re_operators.c | 285 ++++++++++++++++++++------------------- 3 files changed, 151 insertions(+), 151 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 74c76a5810..a14ab39288 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -906,16 +906,16 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, */ rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset, rule->actionset, 1); + if (rule->actionset == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); + } /* Keep track of the parent action for "block" */ - if (rule->actionset) { - rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; - rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; - } + rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; + rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; /* Must NOT specify a disruptive action in logging phase. */ - if ((rule->actionset != NULL) - && (rule->actionset->phase == PHASE_LOGGING) + if ( (rule->actionset->phase == PHASE_LOGGING) && (rule->actionset->intercept_action != ACTION_ALLOW) && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST) && (rule->actionset->intercept_action != ACTION_NONE) @@ -926,9 +926,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, if (dcfg->tmp_chain_starter != NULL) { rule->chain_starter = dcfg->tmp_chain_starter; - if (rule->actionset) { - rule->actionset->phase = rule->chain_starter->actionset->phase; - } + rule->actionset->phase = rule->chain_starter->actionset->phase; } if (rule->actionset->is_chained != 1) { diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index 232a363e2c..61f2c916a3 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -656,6 +656,7 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig } node = CPTRetriveNode(msr, ipdata, ip_bitmask, node); + if (node == NULL) return NULL; if (node && node->bit != ip_bitmask) { if (msr && msr->txcfg->debuglog_level >= 9) { diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 76aefb41e9..cbf5c2db79 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1098,26 +1098,28 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c } /* Are we supposed to capture subexpressions? */ - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + if (rule->actionset) { + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0; - if(!matched) - matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0; + matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0; + if(!matched) + matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0; - /* Show when the regex captures but "capture" is not set */ - if (msr->txcfg->debuglog_level >= 6) { - int capcount = 0; + /* Show when the regex captures but "capture" is not set */ + if (msr->txcfg->debuglog_level >= 6) { + int capcount = 0; #ifdef WITH_PCRE2 - rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); + rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); #else - rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); + rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); #endif - if (msr->txcfg->debuglog_level >= 6) { - if ((capture == 0) && (capcount > 0)) { - msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); + if (msr->txcfg->debuglog_level >= 6) { + if ((capture == 0) && (capcount > 0)) { + msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); + } } } } @@ -2934,52 +2936,51 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * if (rule->actionset) { matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + } } - } + } } } @@ -3264,51 +3265,51 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var if (rule->actionset) { matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + } } - } + } } } @@ -3578,51 +3579,51 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var if (rule->actionset) { matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - } - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); + } } - } + } } } From d1d7aa945b6ff31ff5b337a4d9d01d75485f3637 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 22:37:16 +0100 Subject: [PATCH 345/477] Revert "; incorrectly replaced by space in cmdline" --- apache2/re_tfns.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re_tfns.c b/apache2/re_tfns.c index 3bfc0be5d9..63068dae8c 100644 --- a/apache2/re_tfns.c +++ b/apache2/re_tfns.c @@ -57,6 +57,7 @@ static int msre_fn_cmdline_execute(apr_pool_t *mptmp, unsigned char *input, /* replace some characters to space (only one) */ case ' ': case ',': + case ';': case '\t': case '\r': case '\n': From 4b936128c3dcd992e594d8c3f789267dfd1a3211 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 22:40:39 +0100 Subject: [PATCH 346/477] Revert "Detailed error message when writing collections" --- apache2/apache2_config.c | 3 --- apache2/persist_dbm.c | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 6b71dea7eb..74c76a5810 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1749,9 +1749,6 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME, mp); - if (config_orig_path == NULL) { - return apr_psprintf(mp, "ModSecurity: failed to duplicate filename in parser_conn_limits_operator"); - } if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) || (strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) { diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index b71796bd58..edd41c11ab 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -608,8 +608,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s (key=%s, length=%d)", dbm_filename, - get_apr_error(msr->mp, rc), key.dptr, value.dsize); + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); if (dbm != NULL) { #ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); From b124641a988378da9587db69c982f159350cc5b9 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:01:07 +0100 Subject: [PATCH 347/477] Revert "Adding PCRE2 support for windows build in Makefile.win" --- apache2/Makefile.win | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/apache2/Makefile.win b/apache2/Makefile.win index 9efa74f8fb..ed4bfc9ed2 100644 --- a/apache2/Makefile.win +++ b/apache2/Makefile.win @@ -1,37 +1,29 @@ ########################################################################### # -# Usage: NMAKE -f Makefile.win APACHE={httpd installion dir} PCRE|PCRE2={pcre dir} LIBXML2={LibXML2 dir} [ LUA={Lua dir} ] +# Usage: NMAKE -f Makefile.win APACHE={httpd installion dir} PCRE={pcre dir} LIBXML2={LibXML2 dir} [ LUA={Lua dir} ] # -!IF "$(PCRE2)" != "" -PCRE = $(PCRE2) -!ENDIF - !IF "$(APACHE)" == "" || "$(PCRE)" == "" || "$(LIBXML2)" == "" || "$(CURL)" == "" -!ERROR NMAKE arguments: APACHE=dir PCRE|PCRE2=dir LIBXML2=dir CURL=dir are required to build mod_security2 for Windows +!ERROR NMAKE arguments: APACHE=dir PCRE=dir LIBXML2=dir CURL=dir are required to build mod_security2 for Windows !ENDIF # Linking libraries LIBS = $(APACHE)\lib\libhttpd.lib \ $(APACHE)\lib\libapr-1.lib \ $(APACHE)\lib\libaprutil-1.lib \ - $(CURL)\libcurl.lib \ + $(PCRE)\pcre.lib \ + $(CURL)\libcurl.lib \ $(LIBXML2)\win32\bin.msvc\libxml2.lib \ Ws2_32.lib \ "iphlpapi.lib" -!IF "$(PCRE2)" != "" -LIBS =$(LIBS) $(PCRE2)\lib\pcre2-8.lib -!ELSE -LIBS =$(LIBS) $(PCRE)\lib\pcre.lib -!ENDIF ########################################################################### ########################################################################### - -!IF "$(IIS_BUILD)" == "yes" -DEFS=$(DEFS) -DVERSION_IIS -!ENDIF - + +!IF "$(IIS_BUILD)" == "yes" +DEFS=$(DEFS) -DVERSION_IIS +!ENDIF + CC = CL MT = mt @@ -45,14 +37,9 @@ INCLUDES = -I. -I.. \ -I$(PCRE)\include -I$(PCRE) \ -I$(LIBXML2)\include \ -I$(APACHE)\include - -# Enables support for SecRemoteRules and external resources. -DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES - -# Enable PCRE2 -!IF "$(PCRE2)" != "" -DEFS =$(DEFS) -DWITH_PCRE2 -!ENDIF + +# Enables support for SecRemoteRules and external resources. +DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES # Lua is optional !IF "$(LUA)" != "" @@ -78,8 +65,8 @@ OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \ msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \ msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_crypt.obj msc_tree.obj msc_unicode.obj acmp.obj msc_lua.obj \ msc_release.obj \ - msc_status_engine.obj \ - msc_remote_rules.obj \ + msc_status_engine.obj \ + msc_remote_rules.obj \ msc_json.obj \ libinjection/libinjection_html5.obj \ libinjection/libinjection_sqli.obj \ From dfce12b992e746e3aa1ed665143cefe6901afa95 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:02:10 +0100 Subject: [PATCH 348/477] Revert "Implement msre_action_phase_validate()" --- apache2/re_actions.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 01ba99383a..fca67ed00d 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -755,15 +755,8 @@ static char *msre_action_allow_validate(msre_engine *engine, apr_pool_t *mp, msr /* phase */ static char *msre_action_phase_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { - if (strcasecmp(action->param, "request") == 0) return NULL; - if (strcasecmp(action->param, "response") == 0) return NULL; - if (strcasecmp(action->param, "logging") == 0) return NULL; - if (strcasecmp(action->param, "1") == 0) return NULL; - if (strcasecmp(action->param, "2") == 0) return NULL; - if (strcasecmp(action->param, "3") == 0) return NULL; - if (strcasecmp(action->param, "4") == 0) return NULL; - if (strcasecmp(action->param, "5") == 0) return NULL; - return apr_psprintf(mp, "Invalid parameter for phase: %s", action->param);; + /* ENH Add validation. */ + return NULL; } static apr_status_t msre_action_phase_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, From dd552d243487639baf0e400a62ee462220722520 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:02:37 +0100 Subject: [PATCH 349/477] Revert "Optimization: Avoid last loop and storing an empty value in case nothing after last %{..} macro" --- apache2/re_actions.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index fca67ed00d..658b42cf1a 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -228,20 +228,18 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t msre_var *var_resolved = NULL; /* Add the text part before the macro to the array. */ - if (p != text_start) { part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); if (part == NULL) return -1; part->value_len = p - text_start; part->value = apr_pstrmemdup(mptmp, text_start, part->value_len); *(msc_string **)apr_array_push(arr) = part; - } /* Resolve the macro and add that to the array. */ var_resolved = msre_create_var_ex(mptmp, msr->modsecurity->msre, var_name, var_value, msr, &my_error_msg); if (var_resolved != NULL) { var_generated = generate_single_var(msr, var_resolved, NULL, rule, mptmp); - if (var_generated != NULL && var_generated->value_len) { + if (var_generated != NULL) { part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); if (part == NULL) return -1; part->value_len = var_generated->value_len; @@ -282,11 +280,13 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t part->value_len = strlen(part->value); *(msc_string **)apr_array_push(arr) = part; } - } while (p != NULL && *next_text_start); + } while (p != NULL); - /* Combine text parts into a single string now. - * If no macro was present, we already returned + /* If there's more than one member of the array that + * means there was at least one macro present. Combine + * text parts into a single string now. */ + if (arr->nelts > 1) { /* Figure out the required size for the string. */ var->value_len = 0; for(i = 0; i < arr->nelts; i++) { @@ -306,6 +306,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t offset += part->value_len; } var->value[offset] = '\0'; + } return 1; } From eaa7ca70442358dbcd48d3afa53bf38a1da41f4e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:03:23 +0100 Subject: [PATCH 350/477] Revert "Optimization: Avoid last loop and storing an empty value in case nothing after last %{..} macro" From aa6aa77ba94695b95019aa2ea48785c53c8faeb5 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:03:48 +0100 Subject: [PATCH 351/477] Revert "Avoid some useless code and memory allocation in case no macro is present" --- apache2/re_actions.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 658b42cf1a..5b6b9dd184 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -273,7 +273,6 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t next_text_start = p + 1; } } else { - if (arr->nelts == 0) return 0; /* no macro */ /* Text part. */ part = (msc_string *)apr_pcalloc(mptmp, sizeof(msc_string)); part->value = apr_pstrdup(mptmp, text_start); From e834d7751e0341fcc6428f17d7c3b1635d7ab3a2 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:04:14 +0100 Subject: [PATCH 352/477] Revert "Detailed error message when writing collections" From c3688dd8c4cff56b0ad680255a88b23ee41b8a9d Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:04:47 +0100 Subject: [PATCH 353/477] Revert "Add context info to error message" --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 41e1eb1412..5bdbeda07c 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -353,11 +353,11 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { if(msr) { - msr_log(msr, 9, "Error parsing rule targets to replace variable: %s", my_error_msg); + msr_log(msr, 9, "Error parsing rule targets to replace variable"); } #if !defined(MSC_TEST) else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable: %s", my_error_msg); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable"); } #endif goto end; From 43cb827084defd0fcabfb78deb16e96ef187ff78 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:05:28 +0100 Subject: [PATCH 354/477] Revert "ctl:ruleRemoveByTag isn't executed if no rule id is present in the rule" --- apache2/re.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 5bdbeda07c..9c9c538e03 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -76,7 +76,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(rule->actionset == NULL) return 0; - { + if(rule->actionset->id !=NULL) { myvar = apr_pstrdup(msr->mp, var->name); From d778fbf8b75575b558d79564d9d3d6cc108905c8 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:06:16 +0100 Subject: [PATCH 355/477] Revert "Ignore (consistently) empty actions" --- apache2/re.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 9c9c538e03..ace655df76 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -1058,12 +1058,6 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable, /* ignore whitespace */ while(isspace(*p)) p++; if (*p == '\0') return count; - - /* ignore empty action */ - if (*p == ',') { - p++; - continue; - } /* we are at the beginning of the name */ name = p; From b034f5ad98556df14b84197abe74ad1df618db24 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:06:42 +0100 Subject: [PATCH 356/477] Revert "Fix for https://github.com/SpiderLabs/ModSecurity/issues/610" --- apache2/msc_pcre.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 86bb16010c..6f1a9a186c 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -31,7 +31,11 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { } #else if (regex->pe != NULL) { +#if defined(VERSION_NGINX) pcre_free(regex->pe); +#else + free(regex->pe); +#endif regex->pe = NULL; } if (regex->re != NULL) { @@ -148,15 +152,19 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED|PCRE_STUDY_JIT_COMPILE, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_JIT_COMPILE, &errptr); #else - pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED, &errptr); + pe = pcre_study(regex->re, 0, &errptr); #endif #endif /* Setup the pcre_extra record if pcre_study did not already do it */ if (pe == NULL) { - pe = (pcre_extra*)pcre_malloc(sizeof(pcre_extra)); +#if defined(VERSION_NGINX) + pe = pcre_malloc(sizeof(pcre_extra)); +#else + pe = malloc(sizeof(pcre_extra)); +#endif if (pe == NULL) { return NULL; } From e04e8c4934dfb95782dd74e5825932f77c646b9a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:07:14 +0100 Subject: [PATCH 357/477] Revert "remove useless apr_pstrdup()" --- apache2/re_actions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 5b6b9dd184..02ec07d222 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -183,9 +183,9 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t * no macros in the input data. */ - data = var->value; + data = apr_pstrdup(mptmp, var->value); /* IMP1 Are we modifying data anywhere? */ arr = apr_array_make(mptmp, 16, sizeof(msc_string *)); - if (arr == NULL) return -1; + if ((data == NULL)||(arr == NULL)) return -1; text_start = next_text_start = data; do { From 3f8d21c4b1f41accb0ad45225217f04d4e24ffa4 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:08:06 +0100 Subject: [PATCH 358/477] Revert "Centralized function to get user name" --- apache2/msc_logging.c | 10 +- apache2/msc_util.c | 11 - apache2/msc_util.h | 2 - apache2/persist_dbm.c | 1649 +++++++++++++++++++++-------------------- 4 files changed, 850 insertions(+), 822 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index cdd116f8ff..7f286500f9 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -234,7 +234,15 @@ static char *construct_auditlog_filename(apr_pool_t *mp, const char *uniqueid) { * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations * It also changes the return statement. */ - char *userinfo = get_username(mp); + char *userinfo; + apr_status_t rc; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, mp); + rc = apr_uid_name_get(&userinfo, uid, mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(mp, "%u", uid); + } apr_time_exp_lt(&t, apr_time_now()); diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 0ce58f919e..cf9a393517 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2843,14 +2843,3 @@ char* strtok_r( } #endif -// Function compatible with Linux & Windows, also with mpm-itk & mod_ruid2 -char* get_username(apr_pool_t* mp) { - char* username; - apr_uid_t uid; - apr_gid_t gid; - int rc = apr_uid_current(&uid, &gid, mp); - if (rc != APR_SUCCESS) return "apache"; - rc = apr_uid_name_get(&username, uid, mp); - if (rc != APR_SUCCESS) return "apache"; - return username; -} diff --git a/apache2/msc_util.h b/apache2/msc_util.h index e4e043de16..f7e1280f21 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -159,8 +159,6 @@ int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, int DSOLOCAL ip_tree_from_param(apr_pool_t *pool, char *param, TreeRoot **rtree, char **error_msg); -char DSOLOCAL *get_username(apr_pool_t* mp); - #ifdef WITH_CURL int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index edd41c11ab..e4f8036f6f 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -1,808 +1,841 @@ -/* -* ModSecurity for Apache 2.x, http://www.modsecurity.org/ -* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) -* -* You may not use this file except in compliance with -* the License. You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* If any of the files related to licensing are missing or if you have any -* other questions related to licensing please contact Trustwave Holdings, Inc. -* directly using the email address security@modsecurity.org. -*/ - -#include "persist_dbm.h" -#include "apr_sdbm.h" - -/** - * - */ -static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, - int log_vars) -{ - apr_table_t *col = NULL; - unsigned int blob_offset; - - col = apr_table_make(msr->mp, 32); - if (col == NULL) return NULL; - - /* ENH verify the first 3 bytes (header) */ - - blob_offset = 3; - while (blob_offset + 1 < blob_size) { - msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); - - var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - if (var->name_len == 0) { - /* Is the length a name length, or just the end of the blob? */ - if (blob_offset < blob_size - 2) { - /* This should never happen as the name length - * includes the terminating NUL and should be 1 for "" - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); - } - break; - } - else if (var->name_len > 65536) { - /* This should never happen as the length is restricted on store - * to 65536. - */ - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); - } - msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); - break; - } - - blob_offset += 2; - if (blob_offset + var->name_len > blob_size) return NULL; - var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); - blob_offset += var->name_len; - var->name_len--; - - var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; - blob_offset += 2; - - if (blob_offset + var->value_len > blob_size) return NULL; - var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); - blob_offset += var->value_len; - var->value_len--; - - if (log_vars && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - - apr_table_addn(col, var->name, (void *)var); - } - - return col; -} - -/** - * - */ -static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - char *dbm_filename = NULL; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t *value = NULL; - apr_sdbm_t *dbm = NULL; - apr_table_t *col = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int expired = 0; - int i; - char *userinfo = get_username(msr->mp); - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len)); - goto cleanup; - } - - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - - key.dptr = (char *)col_key; - key.dsize = col_key_len + 1; - - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); - rc = apr_sdbm_fetch(dbm, value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, - dbm_filename), get_apr_error(msr->mp, rc)); - goto cleanup; - } - - if (value->dptr == NULL) { /* Key not found in DBM file. */ - goto cleanup; - } - - /* ENH Need expiration (and perhaps other metadata) accessible in blob - * form to determine if converting to a table is needed. This will - * save some cycles. - */ - - /* Transform raw data into a table. */ - col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); - if (col == NULL) { - goto cleanup; - } - - /* Close after "value" used from fetch or memory may be overwritten. */ - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - /* Remove expired variables. */ - do { - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - if (strncmp(te[i].key, "__expire_", 9) == 0) { - msc_string *var = (msc_string *)te[i].val; - int expiry_time = atoi(var->value); - - if (expiry_time <= apr_time_sec(msr->request_time)) { - char *key_to_expire = te[i].key; - - /* Done early if the col expired */ - if (strcmp(key_to_expire, "__expire_KEY") == 0) { - expired = 1; - } - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); - msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); - } - - apr_table_unset(col, key_to_expire + 9); - apr_table_unset(col, key_to_expire); - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); - } - - break; - } - } - } - } while(!expired && (i != arr->nelts)); - - /* Delete the collection if the variable "KEY" does not exist. - * - * ENH It would probably be more efficient to hold the DBM - * open until determined if it needs deleted than to open a second - * time. - */ - if (apr_table_get(col, "KEY") == NULL) { - if (existing_dbm == NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } -#endif - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - dbm = NULL; -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - goto cleanup; - } - } - else { - dbm = existing_dbm; - } - - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto cleanup; - } - - - if (existing_dbm == NULL) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - dbm = NULL; - } - - if (expired && (msr->txcfg->debuglog_level >= 9)) { - msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, - log_escape_ex(msr->mp, col_key, col_key_len)); - } - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - goto cleanup; - } - - /* Update UPDATE_RATE */ - { - msc_string *var; - int create_time, counter; - - var = (msc_string *)apr_table_get(col, "CREATE_TIME"); - if (var == NULL) { - /* Error. */ - } else { - create_time = atoi(var->value); - var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - if (var == NULL) { - /* Error. */ - } else { - apr_time_t td; - counter = atoi(var->value); - - /* UPDATE_RATE is removed on store, so add it back here */ - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_RATE"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - - /* NOTE: No rate if there has been no time elapsed */ - td = (apr_time_sec(apr_time_now()) - create_time); - if (td == 0) { - var->value = apr_psprintf(msr->mp, "%d", 0); - } - else { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, - (apr_time_t)((60 * counter)/td)); - } - var->value_len = strlen(var->value); - } - } - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - } - - if ((existing_dbm == NULL) && dbm) { - /* Should not ever get here */ - msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return col; - -cleanup: - - if ((existing_dbm == NULL) && dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return NULL; -} - -/** - * - */ -apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, - const char *col_key, int col_key_len) -{ - apr_time_t time_before = apr_time_now(); - apr_table_t *rtable = NULL; - - rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); - - msr->time_storage_read += apr_time_now() - time_before; - - return rtable; -} - -/** - * - */ -int collection_store(modsec_rec *msr, apr_table_t *col) { - char *dbm_filename = NULL; - msc_string *var_name = NULL, *var_key = NULL; - unsigned char *blob = NULL; - unsigned int blob_size, blob_offset; - apr_status_t rc; - apr_sdbm_datum_t key; - apr_sdbm_datum_t value; - apr_sdbm_t *dbm = NULL; - const apr_array_header_t *arr; - apr_table_entry_t *te; - int i; - const apr_table_t *stored_col = NULL; - const apr_table_t *orig_col = NULL; - char *userinfo = get_username(msr->mp); - - var_name = (msc_string *)apr_table_get(col, "__name"); - if (var_name == NULL) { - goto error; - } - - var_key = (msc_string *)apr_table_get(col, "__key"); - if (var_key == NULL) { - goto error; - } - - if (msr->txcfg->data_dir == NULL) { - msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " - "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - goto error; - } - - // ENH: lowercase the var name in the filename - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* Delete IS_NEW on store. */ - apr_table_unset(col, "IS_NEW"); - - /* Delete UPDATE_RATE on store to save space as it is calculated */ - apr_table_unset(col, "UPDATE_RATE"); - - /* Update the timeout value. */ - { - msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); - if (var != NULL) { - int timeout = atoi(var->value); - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var != NULL) { - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); - var->value_len = strlen(var->value); - } - } - } - - /* LAST_UPDATE_TIME */ - { - msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "LAST_UPDATE_TIME"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } - var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); - var->value_len = strlen(var->value); - } - - /* UPDATE_COUNTER */ - { - msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); - int counter = 0; - if (var == NULL) { - var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - var->name = "UPDATE_COUNTER"; - var->name_len = strlen(var->name); - apr_table_setn(col, var->name, (void *)var); - } else { - counter = atoi(var->value); - } - var->value = apr_psprintf(msr->mp, "%d", counter + 1); - var->value_len = strlen(var->value); - } - - /* ENH Make the expiration timestamp accessible in blob form so that - * it is easier/faster to determine expiration without having to - * convert back to table form - */ - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - -#ifndef GLOBAL_COLLECTION_LOCK - /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* If there is an original value, then create a delta and - * apply the delta to the current value */ - orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); - if (orig_col != NULL) { - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", - apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); - } - - stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); - } - - /* Merge deltas and calculate the size first. */ - blob_size = 3 + 2; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - /* If there is an original value, then apply the delta - * to the latest stored value */ - if (stored_col != NULL) { - const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); - if (orig_var != NULL) { - const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); - if (stored_var != NULL) { - int origval = atoi(orig_var->value); - int ourval = atoi(var->value); - int storedval = atoi(stored_var->value); - int delta = ourval - origval; - int newval = storedval + delta; - - if (newval < 0) newval = 0; /* Counters never go below zero. */ - - var->value = apr_psprintf(msr->mp, "%d", newval); - var->value_len = strlen(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var->name, var->name_len), - origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); - } - } - } - } - - // Allocate blob_size for keys - len = var->name_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - - // Allocate blob_size for values - len = var->value_len + 1; - if (len >= 65536) len = 65536; - blob_size += len + 2; - } - - /* Now generate the binary object. */ - blob = apr_pcalloc(msr->mp, blob_size); - if (blob == NULL) { - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - - blob[0] = 0x49; - blob[1] = 0x52; - blob[2] = 0x01; - - blob_offset = 3; - arr = apr_table_elts(col); - te = (apr_table_entry_t *)arr->elts; - for (i = 0; i < arr->nelts; i++) { - msc_string *var = (msc_string *)te[i].val; - int len; - - len = var->name_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->name, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - len = var->value_len + 1; - if (len >= 65536) len = 65536; - - blob[blob_offset + 0] = (len & 0xff00) >> 8; - blob[blob_offset + 1] = len & 0x00ff; - memcpy(blob + blob_offset + 2, var->value, len - 1); - blob[blob_offset + 2 + len - 1] = '\0'; - blob_offset += 2 + len; - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", - log_escape_ex(msr->mp, var->name, var->name_len), - log_escape_ex(msr->mp, var->value, var->value_len)); - } - } - - blob[blob_offset] = 0; - blob[blob_offset + 1] = 0; - - /* And, finally, store it. */ - key.dptr = var_key->value; - key.dsize = var_key->value_len + 1; - - value.dptr = (char *)blob; - value.dsize = blob_size; - - rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, - get_apr_error(msr->mp, rc)); - if (dbm != NULL) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - } - - return -1; - } - -#ifdef GLOBAL_COLLECTION_LOCK - apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#else - apr_sdbm_unlock(dbm); - apr_sdbm_close(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", - log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); - } - - return 0; - -error: - return -1; -} - -/** - * - */ -int collections_remove_stale(modsec_rec *msr, const char *col_name) { - char *dbm_filename = NULL; - apr_sdbm_datum_t key, value; - apr_sdbm_t *dbm = NULL; - apr_status_t rc; - apr_array_header_t *keys_arr; - char **keys; - apr_time_t now = apr_time_sec(msr->request_time); - int i; - char *userinfo = get_username(msr->mp); - - if (msr->txcfg->data_dir == NULL) { - /* The user has been warned about this problem enough times already by now. - * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " - * "define data directory first.", log_escape(msr->mp, col_name)); - */ - goto error; - } - - if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); - else - dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), - log_escape(msr->mp, dbm_filename)); - } - -#ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, - CREATEMODE, msr->mp); - if (rc != APR_SUCCESS) { -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - dbm = NULL; - goto error; - } - - /* First get a list of all keys. */ - keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); - -#ifndef GLOBAL_COLLECTION_LOCK - rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), - get_apr_error(msr->mp, rc)); - goto error; - } -#endif - - /* No one can write to the file while doing this so - * do it as fast as possible. - */ - rc = apr_sdbm_firstkey(dbm, &key); - while(rc == APR_SUCCESS) { - if (key.dsize) { - char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); - *(char **)apr_array_push(keys_arr) = s; - } - rc = apr_sdbm_nextkey(dbm, &key); - } -#ifndef GLOBAL_COLLECTION_LOCK - apr_sdbm_unlock(dbm); -#endif - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, - log_escape(msr->mp, dbm_filename)); - } - - /* Now retrieve the entires one by one. */ - keys = (char **)keys_arr->elts; - for (i = 0; i < keys_arr->nelts; i++) { - key.dptr = keys[i]; - key.dsize = strlen(key.dptr) + 1; - - rc = apr_sdbm_fetch(dbm, &value, key); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", - log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); - goto error; - } - - if (value.dptr != NULL) { - apr_table_t *col = NULL; - msc_string *var = NULL; - - col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); - if (col == NULL) { - goto error; - } - - var = (msc_string *)apr_table_get(col, "__expire_KEY"); - if (var == NULL) { - msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " - "__expire_KEY (name \"%s\", key \"%s\").", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } else { - unsigned int expiry_time = atoi(var->value); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", - log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), - expiry_time - now); - } - - if (expiry_time <= now) { - rc = apr_sdbm_delete(dbm, key); - if (rc != APR_SUCCESS) { -#ifdef LOG_NO_COLL_DELET_PB - if (msr->txcfg->debuglog_level >= 9) -#endif - msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " - "key \"%s\"): %s", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); - msr->msc_sdbm_delete_error = 1; - goto error; - } - - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " - "key \"%s\").", log_escape(msr->mp, col_name), - log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); - } - } - } - } else { - /* Ignore entry not found - it may have been removed in the meantime. */ - } - } - - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - return 1; - -error: - - if (dbm) { - apr_sdbm_close(dbm); -#ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); -#endif - } - - return -1; -} +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "persist_dbm.h" +#include "apr_sdbm.h" + +/** + * + */ +static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, + int log_vars) +{ + apr_table_t *col = NULL; + unsigned int blob_offset; + + col = apr_table_make(msr->mp, 32); + if (col == NULL) return NULL; + + /* ENH verify the first 3 bytes (header) */ + + blob_offset = 3; + while (blob_offset + 1 < blob_size) { + msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); + + var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + if (var->name_len == 0) { + /* Is the length a name length, or just the end of the blob? */ + if (blob_offset < blob_size - 2) { + /* This should never happen as the name length + * includes the terminating NUL and should be 1 for "" + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); + } + break; + } + else if (var->name_len > 65536) { + /* This should never happen as the length is restricted on store + * to 65536. + */ + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); + } + msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); + break; + } + + blob_offset += 2; + if (blob_offset + var->name_len > blob_size) return NULL; + var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); + blob_offset += var->name_len; + var->name_len--; + + var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; + blob_offset += 2; + + if (blob_offset + var->value_len > blob_size) return NULL; + var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); + blob_offset += var->value_len; + var->value_len--; + + if (log_vars && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + + apr_table_addn(col, var->name, (void *)var); + } + + return col; +} + +/** + * + */ +static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + char *dbm_filename = NULL; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t *value = NULL; + apr_sdbm_t *dbm = NULL; + apr_table_t *col = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int expired = 0; + int i; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len)); + goto cleanup; + } + + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + + key.dptr = (char *)col_key; + key.dsize = col_key_len + 1; + + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t)); + rc = apr_sdbm_fetch(dbm, value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp, + dbm_filename), get_apr_error(msr->mp, rc)); + goto cleanup; + } + + if (value->dptr == NULL) { /* Key not found in DBM file. */ + goto cleanup; + } + + /* ENH Need expiration (and perhaps other metadata) accessible in blob + * form to determine if converting to a table is needed. This will + * save some cycles. + */ + + /* Transform raw data into a table. */ + col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1); + if (col == NULL) { + goto cleanup; + } + + /* Close after "value" used from fetch or memory may be overwritten. */ + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + /* Remove expired variables. */ + do { + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + if (strncmp(te[i].key, "__expire_", 9) == 0) { + msc_string *var = (msc_string *)te[i].val; + int expiry_time = atoi(var->value); + + if (expiry_time <= apr_time_sec(msr->request_time)) { + char *key_to_expire = te[i].key; + + /* Done early if the col expired */ + if (strcmp(key_to_expire, "__expire_KEY") == 0) { + expired = 1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9); + msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire); + } + + apr_table_unset(col, key_to_expire + 9); + apr_table_unset(col, key_to_expire); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9); + } + + break; + } + } + } + } while(!expired && (i != arr->nelts)); + + /* Delete the collection if the variable "KEY" does not exist. + * + * ENH It would probably be more efficient to hold the DBM + * open until determined if it needs deleted than to open a second + * time. + */ + if (apr_table_get(col, "KEY") == NULL) { + if (existing_dbm == NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto cleanup; + } +#endif + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + dbm = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + goto cleanup; + } + } + else { + dbm = existing_dbm; + } + + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto cleanup; + } + + + if (existing_dbm == NULL) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + dbm = NULL; + } + + if (expired && (msr->txcfg->debuglog_level >= 9)) { + msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name, + log_escape_ex(msr->mp, col_key, col_key_len)); + } + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + goto cleanup; + } + + /* Update UPDATE_RATE */ + { + msc_string *var; + int create_time, counter; + + var = (msc_string *)apr_table_get(col, "CREATE_TIME"); + if (var == NULL) { + /* Error. */ + } else { + create_time = atoi(var->value); + var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + if (var == NULL) { + /* Error. */ + } else { + apr_time_t td; + counter = atoi(var->value); + + /* UPDATE_RATE is removed on store, so add it back here */ + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_RATE"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + + /* NOTE: No rate if there has been no time elapsed */ + td = (apr_time_sec(apr_time_now()) - create_time); + if (td == 0) { + var->value = apr_psprintf(msr->mp, "%d", 0); + } + else { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, + (apr_time_t)((60 * counter)/td)); + } + var->value_len = strlen(var->value); + } + } + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + } + + if ((existing_dbm == NULL) && dbm) { + /* Should not ever get here */ + msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len)); + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return col; + +cleanup: + + if ((existing_dbm == NULL) && dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return NULL; +} + +/** + * + */ +apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, + const char *col_key, int col_key_len) +{ + apr_time_t time_before = apr_time_now(); + apr_table_t *rtable = NULL; + + rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len); + + msr->time_storage_read += apr_time_now() - time_before; + + return rtable; +} + +/** + * + */ +int collection_store(modsec_rec *msr, apr_table_t *col) { + char *dbm_filename = NULL; + msc_string *var_name = NULL, *var_key = NULL; + unsigned char *blob = NULL; + unsigned int blob_size, blob_offset; + apr_status_t rc; + apr_sdbm_datum_t key; + apr_sdbm_datum_t value; + apr_sdbm_t *dbm = NULL; + const apr_array_header_t *arr; + apr_table_entry_t *te; + int i; + const apr_table_t *stored_col = NULL; + const apr_table_t *orig_col = NULL; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + var_name = (msc_string *)apr_table_get(col, "__name"); + if (var_name == NULL) { + goto error; + } + + var_key = (msc_string *)apr_table_get(col, "__key"); + if (var_key == NULL) { + goto error; + } + + if (msr->txcfg->data_dir == NULL) { + msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use " + "SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + goto error; + } + + // ENH: lowercase the var name in the filename + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", var_name->value, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* Delete IS_NEW on store. */ + apr_table_unset(col, "IS_NEW"); + + /* Delete UPDATE_RATE on store to save space as it is calculated */ + apr_table_unset(col, "UPDATE_RATE"); + + /* Update the timeout value. */ + { + msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT"); + if (var != NULL) { + int timeout = atoi(var->value); + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var != NULL) { + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout)); + var->value_len = strlen(var->value); + } + } + } + + /* LAST_UPDATE_TIME */ + { + msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME"); + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "LAST_UPDATE_TIME"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } + var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()))); + var->value_len = strlen(var->value); + } + + /* UPDATE_COUNTER */ + { + msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER"); + int counter = 0; + if (var == NULL) { + var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + var->name = "UPDATE_COUNTER"; + var->name_len = strlen(var->name); + apr_table_setn(col, var->name, (void *)var); + } else { + counter = atoi(var->value); + } + var->value = apr_psprintf(msr->mp, "%d", counter + 1); + var->value_len = strlen(var->value); + } + + /* ENH Make the expiration timestamp accessible in blob form so that + * it is easier/faster to determine expiration without having to + * convert back to table form + */ + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + +#ifndef GLOBAL_COLLECTION_LOCK + /* Need to lock to pull in the stored data again and apply deltas. */ + rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* If there is an original value, then create a delta and + * apply the delta to the current value */ + orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value); + if (orig_col != NULL) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s", + apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value)); + } + + stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len); + } + + /* Merge deltas and calculate the size first. */ + blob_size = 3 + 2; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + /* If there is an original value, then apply the delta + * to the latest stored value */ + if (stored_col != NULL) { + const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name); + if (orig_var != NULL) { + const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name); + if (stored_var != NULL) { + int origval = atoi(orig_var->value); + int ourval = atoi(var->value); + int storedval = atoi(stored_var->value); + int delta = ourval - origval; + int newval = storedval + delta; + + if (newval < 0) newval = 0; /* Counters never go below zero. */ + + var->value = apr_psprintf(msr->mp, "%d", newval); + var->value_len = strlen(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var->name, var->name_len), + origval, ourval, delta, storedval, delta, newval, var->value, var->value_len); + } + } + } + } + + // Allocate blob_size for keys + len = var->name_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + + // Allocate blob_size for values + len = var->value_len + 1; + if (len >= 65536) len = 65536; + blob_size += len + 2; + } + + /* Now generate the binary object. */ + blob = apr_pcalloc(msr->mp, blob_size); + if (blob == NULL) { + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + + blob[0] = 0x49; + blob[1] = 0x52; + blob[2] = 0x01; + + blob_offset = 3; + arr = apr_table_elts(col); + te = (apr_table_entry_t *)arr->elts; + for (i = 0; i < arr->nelts; i++) { + msc_string *var = (msc_string *)te[i].val; + int len; + + len = var->name_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->name, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + len = var->value_len + 1; + if (len >= 65536) len = 65536; + + blob[blob_offset + 0] = (len & 0xff00) >> 8; + blob[blob_offset + 1] = len & 0x00ff; + memcpy(blob + blob_offset + 2, var->value, len - 1); + blob[blob_offset + 2 + len - 1] = '\0'; + blob_offset += 2 + len; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".", + log_escape_ex(msr->mp, var->name, var->name_len), + log_escape_ex(msr->mp, var->value, var->value_len)); + } + } + + blob[blob_offset] = 0; + blob[blob_offset + 1] = 0; + + /* And, finally, store it. */ + key.dptr = var_key->value; + key.dsize = var_key->value_len + 1; + + value.dptr = (char *)blob; + value.dsize = blob_size; + + rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename, + get_apr_error(msr->mp, rc)); + if (dbm != NULL) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + } + + return -1; + } + +#ifdef GLOBAL_COLLECTION_LOCK + apr_sdbm_close(dbm); + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#else + apr_sdbm_unlock(dbm); + apr_sdbm_close(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + log_escape_ex(msr->mp, var_name->value, var_name->value_len), + log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + } + + return 0; + +error: + return -1; +} + +/** + * + */ +int collections_remove_stale(modsec_rec *msr, const char *col_name) { + char *dbm_filename = NULL; + apr_sdbm_datum_t key, value; + apr_sdbm_t *dbm = NULL; + apr_status_t rc; + apr_array_header_t *keys_arr; + char **keys; + apr_time_t now = apr_time_sec(msr->request_time); + int i; + + /** + * This is required for mpm-itk & mod_ruid2, though should be harmless for other implementations + */ + char *userinfo; + apr_uid_t uid; + apr_gid_t gid; + apr_uid_current(&uid, &gid, msr->mp); + rc = apr_uid_name_get(&userinfo, uid, msr->mp); + if (rc != APR_SUCCESS) { + userinfo = apr_psprintf(msr->mp, "%u", uid); + } + + if (msr->txcfg->data_dir == NULL) { + /* The user has been warned about this problem enough times already by now. + * msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to " + * "define data directory first.", log_escape(msr->mp, col_name)); + */ + goto error; + } + + if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE")) + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", msr->txcfg->webappid, "_", col_name, NULL); + else + dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", userinfo, "-", col_name, NULL); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name), + log_escape(msr->mp, dbm_filename)); + } + +#ifdef GLOBAL_COLLECTION_LOCK + rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, + CREATEMODE, msr->mp); + if (rc != APR_SUCCESS) { +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + dbm = NULL; + goto error; + } + + /* First get a list of all keys. */ + keys_arr = apr_array_make(msr->mp, 256, sizeof(char *)); + +#ifndef GLOBAL_COLLECTION_LOCK + rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), + get_apr_error(msr->mp, rc)); + goto error; + } +#endif + + /* No one can write to the file while doing this so + * do it as fast as possible. + */ + rc = apr_sdbm_firstkey(dbm, &key); + while(rc == APR_SUCCESS) { + if (key.dsize) { + char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1); + *(char **)apr_array_push(keys_arr) = s; + } + rc = apr_sdbm_nextkey(dbm, &key); + } +#ifndef GLOBAL_COLLECTION_LOCK + apr_sdbm_unlock(dbm); +#endif + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts, + log_escape(msr->mp, dbm_filename)); + } + + /* Now retrieve the entires one by one. */ + keys = (char **)keys_arr->elts; + for (i = 0; i < keys_arr->nelts; i++) { + key.dptr = keys[i]; + key.dsize = strlen(key.dptr) + 1; + + rc = apr_sdbm_fetch(dbm, &value, key); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s", + log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); + goto error; + } + + if (value.dptr != NULL) { + apr_table_t *col = NULL; + msc_string *var = NULL; + + col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0); + if (col == NULL) { + goto error; + } + + var = (msc_string *)apr_table_get(col, "__expire_KEY"); + if (var == NULL) { + msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no " + "__expire_KEY (name \"%s\", key \"%s\").", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } else { + unsigned int expiry_time = atoi(var->value); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.", + log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1), + expiry_time - now); + } + + if (expiry_time <= now) { + rc = apr_sdbm_delete(dbm, key); + if (rc != APR_SUCCESS) { +#ifdef LOG_NO_COLL_DELET_PB + if (msr->txcfg->debuglog_level >= 9) +#endif + msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", " + "key \"%s\"): %s", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc)); + msr->msc_sdbm_delete_error = 1; + goto error; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", " + "key \"%s\").", log_escape(msr->mp, col_name), + log_escape_ex(msr->mp, key.dptr, key.dsize - 1)); + } + } + } + } else { + /* Ignore entry not found - it may have been removed in the meantime. */ + } + } + + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + return 1; + +error: + + if (dbm) { + apr_sdbm_close(dbm); +#ifdef GLOBAL_COLLECTION_LOCK + apr_global_mutex_unlock(msr->modsecurity->dbm_lock); +#endif + } + + return -1; +} From 7073c262b8c55f5094b43ca9a89b5eca7bb1ad4a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:08:46 +0100 Subject: [PATCH 359/477] Revert "Compatibility with libyajl decoding the buffer inline" --- apache2/msc_json.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index e9d0c99d0d..17f938b64e 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -354,17 +354,15 @@ int json_init(modsec_rec *msr, char **error_msg) { int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; - // Take a copy in case libyajl decodes the buffer inline - base_offset = apr_pstrmemdup(msr->mp, buf, size); - if (!base_offset) return -1; + base_offset=buf; /* Feed our parser and catch any errors */ - msr->json->status = yajl_parse(msr->json->handle, (unsigned char*)base_offset, size); + msr->json->status = yajl_parse(msr->json->handle, buf, size); if (msr->json->status != yajl_status_ok) { if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; } else { - char *yajl_err = yajl_get_error(msr->json->handle, 0, base_offset, size); + char *yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); *error_msg = apr_pstrdup(msr->mp, yajl_err); yajl_free_error(msr->json->handle, yajl_err); } From 7828c63205f6c28092a1c1bb275bd8f8affe7d08 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:09:05 +0100 Subject: [PATCH 360/477] Revert "Fixed 2 memory leaks" --- apache2/re.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index ace655df76..d70903e65c 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -378,7 +378,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } #if !defined(MSC_TEST) else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find variable to replace"); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find varibale to replace"); } #endif goto end; @@ -386,13 +386,8 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } else { target = strdup(p); - if(target == NULL) { - if(target_list != NULL) - free(target_list); - if(replace != NULL) - free(replace); - return NULL; - } + if(target == NULL) + return NULL; is_negated = is_counting = 0; param = name = value = NULL; @@ -426,8 +421,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r free(target_list); if(replace != NULL) free(replace); - if(target != NULL) - free(target); if(msr) { msr_log(msr, 9, "Error to update target - [%s] is not valid target", name); } @@ -519,12 +512,18 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } end: - if(target_list != NULL) + if(target_list != NULL) { free(target_list); - if(replace != NULL) + target_list = NULL; + } + if(replace != NULL) { free(replace); - if(target != NULL) + replace = NULL; + } + if(target != NULL) { free(target); + target = NULL; + } return NULL; } From 7eabbb2b72e162adf24e1b62bebfe7cece9f2f64 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:09:34 +0100 Subject: [PATCH 361/477] Revert " Fix for DEBUG_CONF compile flag" --- apache2/re.c | 5 +---- apache2/re.h | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index d70903e65c..aafb2b5ad4 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -637,10 +637,7 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) { /** * Generate an action string from an actionset. */ -#ifndef DEBUG_CONF - static -#endif -char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { +static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { const apr_array_header_t *tarr = NULL; const apr_table_entry_t *telts = NULL; char *actions = NULL; diff --git a/apache2/re.h b/apache2/re.h index e268d8a210..c0c5433965 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -75,10 +75,6 @@ int DSOLOCAL rule_id_in_range(int ruleid, const char *range); msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); -#ifdef DEBUG_CONF - char DSOLOCAL* msre_actionset_generate_action_string(apr_pool_t* pool, const msre_actionset* actionset); -#endif - #if defined(WITH_LUA) apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); From 5cbd7e6e6c9c7b6752e977db0e7286ba0e941182 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:09:59 +0100 Subject: [PATCH 362/477] Revert "Double memory allocation" --- apache2/re.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index aafb2b5ad4..9ded3be796 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -499,7 +499,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if(var_appended == 1) { current_targets = msre_generate_target_string(ruleset->mp, rule); rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, current_targets, NULL, NULL); - rule->p1 = current_targets; + rule->p1 = apr_pstrdup(ruleset->mp, current_targets); if(msr) { msr_log(msr, 9, "Successfully appended variable"); } From ac332cc79d2f24f323f0da6fae4524dd0c3648ae Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 7 Feb 2024 23:10:22 +0100 Subject: [PATCH 363/477] Revert "'jit' variable not initialized when WITH_PCRE2 is defined" --- apache2/re_operators.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 76aefb41e9..c3dcfea385 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -678,7 +678,7 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit = 0; + int rc, jit; #endif #endif @@ -753,7 +753,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v int rc; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit = 0; + int jit; #endif #endif @@ -947,7 +947,7 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit = 0; + int rc, jit; #endif #endif @@ -1017,7 +1017,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit = 0; + int jit; #endif #endif @@ -2830,7 +2830,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit = 0; + int jit; #endif #endif @@ -3160,7 +3160,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit = 0; + int jit; #endif #endif @@ -3474,7 +3474,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit = 0; + int jit; #endif #endif From a2c4813814cea5fd7ddc1403c2c7e2086fc5689b Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:00:25 +0100 Subject: [PATCH 364/477] Revert "Fixed variable definition scope (compile error)" This reverts commit 0cd8b15c5a780951714e83f9dc907f93562df268. --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index c3dcfea385..7cdf58961a 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -780,8 +780,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); - const char *pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { + const char *pattern = log_escape_re(msr->mp, re_pattern->value); msr_log(msr, 6, "Escaping pattern [%s]",pattern); } From 892033237fb04e184667c98925ebb192f9e56238 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:05:00 +0100 Subject: [PATCH 365/477] Revert "Update re_operators.c" This reverts commit 931f8b6ed455fa91d5eead31a34c6320e3cfc1ca. --- apache2/re_operators.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 7cdf58961a..77b1b4132f 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -751,6 +751,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v char *my_error_msg = NULL; int ovector[33]; int rc; + const char *pattern = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT int jit; @@ -780,8 +781,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); + pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - const char *pattern = log_escape_re(msr->mp, re_pattern->value); msr_log(msr, 6, "Escaping pattern [%s]",pattern); } From 6dafdb2b97247771737546c3788c3ec64c356ef0 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:07:20 +0100 Subject: [PATCH 366/477] Revert "remove useless memset" This reverts commit 3dc5ff5f6532a9222bc9607f5f2dd34b28ca6fe4. --- apache2/re_operators.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 77b1b4132f..899290c450 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -630,13 +630,18 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, } if(msr->stream_input_data != NULL && input_body == 1) { + memset(msr->stream_input_data, 0x0, msr->stream_input_length); free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = 0; -#endif + + msr->stream_input_data = (char *)malloc(size); +#else msr->stream_input_data = (char *)malloc(size+1); +#endif + if(msr->stream_input_data == NULL) { return -1; } @@ -644,11 +649,16 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_length = size; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = size; + memset(msr->stream_input_data, 0x0, size); +#else + memset(msr->stream_input_data, 0x0, size+1); #endif msr->if_stream_changed = 1; memcpy(msr->stream_input_data, data, size); +#ifndef MSC_LARGE_STREAM_INPUT msr->stream_input_data[size] = '\0'; +#endif var->value_len = size; var->value = msr->stream_input_data; From 2812553a4502d43373c78b98ba7bc2ecf41b5035 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:10:25 +0100 Subject: [PATCH 367/477] Revert "Update re_operators.c" This reverts commit 9c0d05f73470b3e6acb1078d8b59a837b363731a. --- apache2/re_operators.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 899290c450..cfd8952539 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1545,10 +1545,10 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l url = apr_palloc(pool, len + 1); data = apr_palloc(pool, len + 1); - data[0] = '\0'; - + memset(data, 0, len+1); + memset(url, 0, len+1); + memcpy(url, domain, len); - url[len] = 0; while(( pos = strstr(url , "/./" )) != NULL) { match = 1; From 1d682c0e03c575e7178375f0cf8c74a3fe0b946e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:14:10 +0100 Subject: [PATCH 368/477] Revert "Updated CHANGES" This reverts commit 864f54c643fe7a2f200a4643b967b6ca4c7435b8. --- CHANGES | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/CHANGES b/CHANGES index 1703d3ebac..517e76b74c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,34 +1,6 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- - * Support for PCRE2 in Windows - [PR #2931, @leancz] - * Fix ; incorrectly replaced by space in t:cmdline - [PR #3051, @marcstern] - * Add some syntax validation - [PR #2994, @marcstern] - * Optimize macro processing - [PR #2992/3004, @marcstern] - * Add detailed error message when writing collections - [PR #3050, @marcstern] - * Add context info to error message - [PR #2997, @marcstern] - * Fix ctl:ruleRemoveByTag that isn't executed if no rule id is present - [PR #3012, @marcstern] - * Ignore empty action instead of storing it - [PR #3003, @marcstern] - * Fixed memory leak if builded modsecurity with --enable-pcre-study - [Issue #610, @marcstern] - * Remove useless code - [PR #2953/2954, @marcstern] - * Centralized function to get user name, compatible with Linux & Windows - [PR #2956, @marcstern] - * Compatibility with libyajl decoding the buffer inline - [PR #2957, @marcstern] - * Fixed memory leaks - [PR #2960/2963/2969, @marcstern] - * Fixed uninitialized variable - [PR #2987, @marcstern] * Set the minimum security protocol version for SecRemoteRules [Issue security/code-scanning/2 - @airween] * Allow lua version 5.4 From 8752f6bba3b021727e4898957d90306a851dd325 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:39:57 +0100 Subject: [PATCH 369/477] Initial release of CI worklow --- .github/ci.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/ci.yml diff --git a/.github/ci.yml b/.github/ci.yml new file mode 100644 index 0000000000..e969db32b0 --- /dev/null +++ b/.github/ci.yml @@ -0,0 +1,30 @@ +name: Quality Assurance + +on: + push: + pull_request: + +jobs: + build-linux: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04] + platform: [x64] + compiler: [gcc] + configure: + - {label: "with pcre2", opt: "--with-pcre2" } + - {label: "with lua", opt: "--with-lua" } + steps: + - name: Setup Dependencies + run: | + sudo apt-get update -y -qq + sudo apt-get install -y apache2-dev libxml2-dev liblua5.1-0-dev libcurl4-gnutls-dev libpcre2-dev pkg-config libyajl-dev + - uses: actions/checkout@v2 + - name: build.sh + run: ./build.sh + - name: configure ${{ matrix.configure.label }} + run: ./configure ${{ matrix.configure.opt }} + - uses: ammaraskar/gcc-problem-matcher@master + - name: make + run: make -j `nproc` From 6a34c89a30ab993dfe242b74c5f7ebc64327e0bd Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:46:53 +0100 Subject: [PATCH 370/477] Add new flag: --without-lua --- .github/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ci.yml b/.github/ci.yml index e969db32b0..ecd8496af9 100644 --- a/.github/ci.yml +++ b/.github/ci.yml @@ -13,8 +13,9 @@ jobs: platform: [x64] compiler: [gcc] configure: - - {label: "with pcre2", opt: "--with-pcre2" } - - {label: "with lua", opt: "--with-lua" } + - {label: "with pcre2", opt: "--with-pcre2" } + - {label: "with lua", opt: "--with-lua" } + - {label: "wo lua", opt: "--without-lua" } steps: - name: Setup Dependencies run: | From 92cc83b171c155c6940200b1561be11e5a2d58a2 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 00:53:06 +0100 Subject: [PATCH 371/477] Move ci file to correct directory --- .github/{ => workflows}/ci.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{ => workflows}/ci.yml (100%) diff --git a/.github/ci.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/ci.yml rename to .github/workflows/ci.yml From 6870df446d07d6f2ae05227ff67eeab22e91fb50 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 01:01:41 +0100 Subject: [PATCH 372/477] Set correct generate script --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecd8496af9..a47ebdfb77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,8 +22,8 @@ jobs: sudo apt-get update -y -qq sudo apt-get install -y apache2-dev libxml2-dev liblua5.1-0-dev libcurl4-gnutls-dev libpcre2-dev pkg-config libyajl-dev - uses: actions/checkout@v2 - - name: build.sh - run: ./build.sh + - name: autogen.sh + run: ./autogen.sh - name: configure ${{ matrix.configure.label }} run: ./configure ${{ matrix.configure.opt }} - uses: ammaraskar/gcc-problem-matcher@master From 6b9ea5a1e6cf6b5b9a8932c0c31eedb6f88b82bd Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 8 Feb 2024 23:53:30 +0100 Subject: [PATCH 373/477] Add more steps: install built module and restart the server --- .github/security2.conf | 6 ++++++ .github/workflows/ci.yml | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 .github/security2.conf diff --git a/.github/security2.conf b/.github/security2.conf new file mode 100644 index 0000000000..a503848acd --- /dev/null +++ b/.github/security2.conf @@ -0,0 +1,6 @@ +LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so + +<IfModule security2_module> + SecDataDir /var/cache/modsecurity + Include /etc/apache2/modsecurity.conf +</IfModule> diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a47ebdfb77..8b18bfb78d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Dependencies run: | sudo apt-get update -y -qq - sudo apt-get install -y apache2-dev libxml2-dev liblua5.1-0-dev libcurl4-gnutls-dev libpcre2-dev pkg-config libyajl-dev + sudo apt-get install -y apache2-dev libxml2-dev liblua5.1-0-dev libcurl4-gnutls-dev libpcre2-dev pkg-config libyajl-dev apache2 apache2-bin apache2-data - uses: actions/checkout@v2 - name: autogen.sh run: ./autogen.sh @@ -29,3 +29,16 @@ jobs: - uses: ammaraskar/gcc-problem-matcher@master - name: make run: make -j `nproc` + - name: install module + run: sudo make install + - name: prepare config + run: | + sudo cp .github/security2.conf /etc/apache2/mods-enabled/ + sudo cp modsecurity.conf-recommended /etc/apache2/modsecurity.conf + sudo cp unicode.mapping /etc/apache2/ + sudo mkdir -p /var/cache/modsecurity + sudo chown -R www-data:www-data /var/cache/modsecurity + - name: start apache with module + run: | + sudo systemctl restart apache2.service + From 91da5872c1173f6cf42d888be6819f3b180305d2 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 20 Feb 2024 13:15:52 +0100 Subject: [PATCH 374/477] Many null pointer checks --- apache2/apache2_config.c | 49 ++-- apache2/apache2_io.c | 20 +- apache2/apache2_util.c | 14 + apache2/mod_security2.c | 32 ++- apache2/modsecurity.c | 11 + apache2/msc_crypt.c | 15 +- apache2/msc_geo.c | 4 + apache2/msc_json.c | 10 +- apache2/msc_logging.c | 19 +- apache2/msc_lua.c | 6 +- apache2/msc_multipart.c | 22 +- apache2/msc_parsers.c | 9 + apache2/msc_reqbody.c | 24 ++ apache2/msc_tree.c | 25 +- apache2/msc_util.c | 7 + apache2/msc_util.h | 1 + apache2/msc_xml.c | 9 +- apache2/persist_dbm.c | 8 + apache2/re.c | 66 +++-- apache2/re_actions.c | 65 ++++- apache2/re_operators.c | 535 +++++++++++++++++++++++++-------------- apache2/re_variables.c | 521 +++++++++++++++++++++++++++++++++++++- 22 files changed, 1181 insertions(+), 291 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index a14ab39288..615d0c38e4 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -30,6 +30,13 @@ APLOG_USE_MODULE(security2); #endif +// Returns the rule id if existing, otherwise the file name & line number +static const char* id_log(msre_rule* rule) { + const char* id = rule->actionset->id; + if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + return id; +} + /* -- Directory context creation and initialisation -- */ /** @@ -239,19 +246,19 @@ static void copy_rules_phase(apr_pool_t *mp, if (copy > 0) { #ifdef DEBUG_CONF - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, id_log(rule)); #endif /* Copy the rule. */ *(msre_rule **)apr_array_push(child_phase_arr) = rule; - if (rule->actionset && rule->actionset->is_chained) mode = 2; + if (rule->actionset->is_chained) mode = 2; } else { - if (rule->actionset && rule->actionset->is_chained) mode = 1; + if (rule->actionset->is_chained) mode = 1; } } else { if (mode == 2) { #ifdef DEBUG_CONF - ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, id_log(rule->chain_starter)); #endif /* Copy the rule (it belongs to the chain we want to include. */ @@ -906,9 +913,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, */ rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset, rule->actionset, 1); - if (rule->actionset == NULL) { - return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); - } + if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); /* Keep track of the parent action for "block" */ rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; @@ -965,8 +970,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, - "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P - ? "(none)" : rule->actionset->id)); + "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, id_log(rule)); #endif /* Add rule to the recipe. */ @@ -1040,8 +1044,7 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, for (p = PHASE_FIRST; p <= PHASE_LAST; p++) { #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, - "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P - ? "(none)" : rule->actionset->id)); + "Adding marker %pp phase=%d id=\"%s\".", rule, p, id_log(rule)); #endif if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) { @@ -1089,11 +1092,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, return NULL; } - /* Check the rule actionset */ - /* ENH: Can this happen? */ - if (rule->actionset == NULL) { - return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1); - } + assert(rule->actionset != NULL); /* Create a new actionset */ new_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p2, &my_error_msg); @@ -1115,9 +1114,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Update rule %pp id=\"%s\" old action: \"%s\"", - rule, - (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), - actions); + rule, id_log(rule), actions); } #endif @@ -1125,6 +1122,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, /* ENH: Will this leak the old actionset? */ rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, rule->actionset, new_actionset, 1); + if (rule->actionset == NULL) return apr_psprintf(cmd->pool, "ModSecurity: cannot merge actionset (memory full?)."); msre_actionset_set_defaults(rule->actionset); /* Update the unparsed rule */ @@ -1135,9 +1133,7 @@ static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Update rule %pp id=\"%s\" new action: \"%s\"", - rule, - (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), - actions); + rule, id_log(rule), actions); } #endif @@ -1744,6 +1740,9 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, config_orig_path = apr_pstrndup(mp, filename, strlen(filename) - strlen(apr_filepath_name_get(filename))); + if (config_orig_path == NULL) { + return apr_psprintf(mp, "ModSecurity: failed to duplicate filename in parser_conn_limits_operator"); + } apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME, mp); @@ -2450,8 +2449,12 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { directory_config *dcfg = (directory_config *)_dcfg; - rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); if (dcfg == NULL) return NULL; + rule_exception* re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (re == NULL) { + ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, "cmd_rule_remove_by_id: Cannot allocate memory"); + return NULL; + } re->type = RULE_EXCEPTION_REMOVE_ID; re->param = p1; diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 6490d61b5d..b8117d91ce 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -179,12 +179,13 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, * Reads request body from a client. */ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert( error_msg!= NULL); request_rec *r = msr->r; unsigned int finished_reading; apr_bucket_brigade *bb_in; apr_bucket *bucket; - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->reqbody_should_exist != 1) { @@ -368,6 +369,8 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { * run or not. */ static int output_filter_should_run(modsec_rec *msr, request_rec *r) { + assert(msr != NULL); + assert(r != NULL); char *content_type = NULL; /* Check configuration. */ @@ -429,10 +432,13 @@ static int output_filter_should_run(modsec_rec *msr, request_rec *r) { static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, apr_bucket_brigade *bb_in) { + assert(msr != NULL); + assert(f != NULL); request_rec *r = f->r; const char *s_content_length = NULL; apr_status_t rc; + assert(msr != NULL); msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc); if (msr->of_brigade == NULL) { msr_log(msr, 1, "Output filter: Failed to create brigade."); @@ -496,6 +502,8 @@ static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, * and to the client. */ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); apr_status_t rc; rc = ap_pass_brigade(f->next, msr->of_brigade); @@ -537,6 +545,8 @@ static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { * */ static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); apr_bucket *b; if (msr->txcfg->content_injection_enabled && msr->stream_output_data != NULL) { @@ -563,6 +573,8 @@ static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { * */ static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + assert(msr != NULL); + assert(f != NULL); if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) { apr_bucket *bucket_ci = NULL; @@ -1008,6 +1020,12 @@ apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) { /* Now send data down the filter stream * (full-buffering only). */ + if (!eos_bucket) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal Error: eos_bucket is NULL."); + return APR_EGENERAL; + } + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { if(msr->of_stream_changed == 1) { inject_content_to_of_brigade(msr,f); diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index d76da7558d..20ea940ee5 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -25,6 +25,8 @@ * Sends a brigade with an error bucket down the filter chain. */ apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { + assert(msr != NULL); + assert(f != NULL); apr_bucket_brigade *brigade = NULL; apr_bucket *bucket = NULL; @@ -61,6 +63,9 @@ apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { * the "output" parameter. */ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { + assert(msr != NULL); + assert(command != NULL); + apr_procattr_t *procattr = NULL; apr_proc_t *procnew = NULL; apr_status_t rc = APR_SUCCESS; @@ -204,6 +209,9 @@ char *get_env_var(request_rec *r, char *name) { static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr, int level, int fixup, const char *text, va_list ap) { + assert(r != NULL); + assert(msr != NULL); + assert(text != NULL); apr_size_t nbytes, nbytes_written; apr_file_t *debuglog_fd = NULL; int filter_debug_level = 0; @@ -303,6 +311,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * * Apache error log if the message is important enough. */ void msr_log(modsec_rec *msr, int level, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); @@ -316,6 +326,8 @@ void msr_log(modsec_rec *msr, int level, const char *text, ...) { * Apache error log. This is intended for error callbacks. */ void msr_log_error(modsec_rec *msr, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); @@ -330,6 +342,8 @@ void msr_log_error(modsec_rec *msr, const char *text, ...) { * The 'text' will first be escaped. */ void msr_log_warn(modsec_rec *msr, const char *text, ...) { + assert(msr != NULL); + assert(text != NULL); va_list ap; va_start(ap, text); diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 7786543a12..091aa0e040 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -475,6 +475,8 @@ static modsec_rec *retrieve_tx_context(request_rec *r) { * phases, redirections, or subrequests. */ static void store_tx_context(modsec_rec *msr, request_rec *r) { + assert(msr != NULL); + assert(r != NULL); apr_table_setn(r->notes, NOTE_MSR, (void *)msr); } @@ -491,7 +493,10 @@ static modsec_rec *create_tx_context(request_rec *r) { apr_allocator_create(&allocator); apr_allocator_max_free_set(allocator, 1024); apr_pool_create_ex(&msr->mp, r->pool, NULL, allocator); - if (msr->mp == NULL) return NULL; + if (msr->mp == NULL) { + apr_allocator_destroy(allocator); + return NULL; + } apr_allocator_owner_set(allocator, msr->mp); msr->modsecurity = modsecurity; @@ -862,7 +867,13 @@ static int hook_request_early(request_rec *r) { * create the initial configuration. */ msr = create_tx_context(r); - if (msr == NULL) return DECLINED; + if (msr == NULL) { + msr_log(msr, 9, "Failed to create context after request failure."); + return DECLINED; + } + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Context created after request failure."); + } #ifdef REQUEST_EARLY @@ -1150,17 +1161,16 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s #endif if (msr_ap_server) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - msr = create_tx_context((request_rec *)info->r); + msr = create_tx_context((request_rec*)info->r); #else - msr = create_tx_context((request_rec *)r); + msr = create_tx_context((request_rec*)r); #endif - if (msr != NULL && msr->txcfg->debuglog_level >= 9) { - if (msr == NULL) { - msr_log(msr, 9, "Failed to create context after request failure."); - } - else { - msr_log(msr, 9, "Context created after request failure."); - } + if (msr == NULL) { + msr_log(msr, 9, "Failed to create context after request failure."); + return; + } + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Context created after request failure."); } } if (msr == NULL) return; diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index af5294668b..d6f2034990 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -41,6 +41,8 @@ int DSOLOCAL *unicode_map_table = NULL; const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message, const char *rule_message) { + assert(msr != NULL); + assert(actionset != NULL); const char *message = NULL; if (rule_message == NULL) rule_message = "Unknown error."; @@ -63,6 +65,8 @@ const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message, const char *rule_message) { + assert(msr != NULL); + assert(actionset != NULL); const char *message = msc_alert_message(msr, actionset, action_message, rule_message); msr_log(msr, level, "%s", message); @@ -126,6 +130,11 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { apr_status_t rc; + msce->auditlog_lock = msce->geo_lock = NULL; +#ifdef GLOBAL_COLLECTION_LOCK + msce->geo_lock = NULL; +#endif + /** * Notice that curl is initialized here but never cleaned up. First version * of this implementation curl was initialized and cleaned for every @@ -547,6 +556,7 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) { * */ static int is_response_status_relevant(modsec_rec *msr, int status) { + assert(msr != NULL); char *my_error_msg = NULL; apr_status_t rc; char buf[32]; @@ -780,6 +790,7 @@ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) { * in the modsec_rec structure. */ apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) { + assert(msr != NULL); /* Check if we should run. */ if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) { if (msr->txcfg->debuglog_level >= 4) { diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 3fe18c78b4..3287eeff2e 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -32,14 +32,12 @@ * \retval NULL on fail */ char *normalize_path(modsec_rec *msr, char *input) { + assert(msr != NULL); + assert(input != NULL); xmlURI *uri = NULL; char *parsed_content = NULL; char *content = NULL; - if(msr == NULL) return NULL; - - if(input == NULL) return NULL; - uri = xmlParseURI(input); if(uri != NULL && uri->path) { @@ -195,6 +193,8 @@ char *mschmac(modsec_rec *msr, const char *key, int key_len, char *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen) { #endif + assert(msr != NULL); + assert(msg != NULL); apr_sha1_ctx_t ctx; unsigned char digest[APR_SHA1_DIGESTSIZE]; unsigned char hmac_ipad[HMAC_PAD_SIZE], hmac_opad[HMAC_PAD_SIZE]; @@ -346,6 +346,8 @@ int init_response_body_html_parser(modsec_rec *msr) { * \retval -1 on fail */ int do_hash_method(modsec_rec *msr, char *link, int type) { + assert(msr != NULL); + assert(link != NULL); hash_method **em = NULL; int i = 0; char *error_msg = NULL; @@ -1051,6 +1053,7 @@ int hash_response_body_links(modsec_rec *msr) { * \retval -1 On fail */ int inject_hashed_response_body(modsec_rec *msr, int elts) { + assert(msr != NULL); xmlOutputBufferPtr output_buf = NULL; xmlCharEncodingHandlerPtr handler = NULL; char *p = NULL; @@ -1290,13 +1293,13 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { * \retval NULL on fail */ char *do_hash_link(modsec_rec *msr, char *link, int type) { + assert(msr != NULL); + assert(link != NULL); char *mac_link = NULL; char *path_chunk = NULL; char *hash_value = NULL; char *qm = NULL; - if(msr == NULL) return NULL; - if(strlen(link) > 7 && strncmp("http:",(char*)link,5)==0){ path_chunk = strchr(link+7,'/'); if(path_chunk != NULL) { diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index a849b4f9e2..e77e4f5056 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -263,6 +263,10 @@ int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg) */ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg) { + assert(msr != NULL); + assert(georec != NULL); + assert(target != NULL); + assert(error_msg != NULL); apr_sockaddr_t *addr; long ipnum = 0; char *targetip = NULL; diff --git a/apache2/msc_json.c b/apache2/msc_json.c index e9d0c99d0d..b42aa96a80 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -20,6 +20,7 @@ const char *base_offset=NULL; int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { + assert(msr != NULL); msc_arg *arg = (msc_arg *) NULL; /** @@ -298,6 +299,8 @@ static int yajl_end_map(void *ctx) * Initialise JSON parser. */ int json_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); /** * yajl configuration and callbacks */ @@ -315,7 +318,6 @@ int json_init(modsec_rec *msr, char **error_msg) { yajl_end_array }; - if (error_msg == NULL) return -1; *error_msg = NULL; msr_log(msr, 4, "JSON parser initialization"); @@ -352,7 +354,8 @@ int json_init(modsec_rec *msr, char **error_msg) { * Feed one chunk of data to the JSON parser. */ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; // Take a copy in case libyajl decodes the buffer inline base_offset = apr_pstrmemdup(msr->mp, buf, size); @@ -378,9 +381,10 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char * Finalise JSON parsing. */ int json_complete(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); char *json_data = (char *) NULL; - if (error_msg == NULL) return -1; *error_msg = NULL; /* Wrap up the parsing process */ diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index cdd116f8ff..1e537b6d95 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -35,6 +35,7 @@ * the size counters, update the hash context. */ static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int len) { + assert(msr != NULL); apr_size_t nbytes_written, nbytes = len; apr_status_t rc; @@ -86,6 +87,8 @@ static int sec_auditlog_write(modsec_rec *msr, const char *data, unsigned int le * some of the fields to make the log line shorter than _limit bytes. */ char *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited) { + assert(msr != NULL); + assert(was_limited != NULL); char *hostname; char *local_user, *remote_user; char *referer, *user_agent, *uniqueid; @@ -397,6 +400,7 @@ static void sec_auditlog_write_producer_header(modsec_rec *msr) { * Ouput the Producer header into a JSON generator */ static void sec_auditlog_write_producer_header_json(modsec_rec *msr, yajl_gen g) { + assert(msr != NULL); char **signatures = NULL; int i; @@ -512,6 +516,7 @@ static msre_rule *return_chained_rule(const msre_rule *current, modsec_rec *msr) * \retval 1 On Success */ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { + assert(msr != NULL); int i = 0; const msre_rule *rule = NULL; @@ -530,6 +535,7 @@ static int chained_is_matched(modsec_rec *msr, const msre_rule *next_rule) { * Write detailed information about performance metrics into a JSON generator */ static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { + assert(msr != NULL); yajl_string(g, "stopwatch"); yajl_gen_map_open(g); @@ -550,6 +556,8 @@ static void format_performance_variables_json(modsec_rec *msr, yajl_gen g) { * Write detailed information about a rule and its actionset into a JSON generator */ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) { + assert(msr != NULL); + assert(rule != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int been_opened = 0; @@ -740,10 +748,13 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Lock the mutex, but only if we are using serial format. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", - get_apr_error(msr->mp, rc)); + if (!msr->modsecurity->auditlog_lock) msr_log(msr, 1, "Audit log: Global mutex was not created"); + else { + rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", + get_apr_error(msr->mp, rc)); + } } } diff --git a/apache2/msc_lua.c b/apache2/msc_lua.c index 2f05df651d..e1715c03b5 100644 --- a/apache2/msc_lua.c +++ b/apache2/msc_lua.c @@ -154,6 +154,8 @@ static int l_log(lua_State *L) { * */ static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) { + assert(msr != NULL); + assert(mp != NULL); apr_array_header_t *tfn_arr = NULL; msre_tfn_metadata *tfn = NULL; char *name = NULL; @@ -406,11 +408,13 @@ static const struct luaL_Reg mylib[] = { * */ int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg) { + assert(script != NULL); + assert(msr != NULL); + assert(error_msg != NULL); apr_time_t time_before; lua_State *L = NULL; int rc = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->txcfg->debuglog_level >= 8) { diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 9309d4df29..e40136b4fd 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -21,6 +21,7 @@ #include "msc_parsers.h" void validate_quotes(modsec_rec *msr, char *data, char quote) { + assert(msr != NULL); int i, len; if(msr == NULL) @@ -84,6 +85,8 @@ static char *multipart_construct_filename(modsec_rec *msr) { * */ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) { + assert(msr != NULL); + assert(c_d_value != NULL); char *p = NULL, *t = NULL; /* accept only what we understand */ @@ -255,9 +258,10 @@ static int multipart_parse_content_disposition(modsec_rec *msr, char *c_d_value) * */ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); int i, len, rc; - if (error_msg == NULL) return -1; *error_msg = NULL; /* Check for nul bytes. */ @@ -454,11 +458,12 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { * */ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); char *p = msr->mpd->buf + (MULTIPART_BUF_SIZE - msr->mpd->bufleft); char localreserve[2] = { '\0', '\0' }; /* initialized to quiet warning */ int bytes_reserved = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; msr->mpd->mpp_substate_part_data_read = 1; @@ -628,6 +633,8 @@ static int multipart_process_part_data(modsec_rec *msr, char **error_msg) { * */ static char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t *value_parts) { + assert(msr != NULL); + assert(value_parts != NULL); value_part_t **parts = NULL; char *rval = apr_palloc(msr->mp, msr->mpd->mpp->length + 1); unsigned long int offset; @@ -652,6 +659,7 @@ static char *multipart_combine_value_parts(modsec_rec *msr, apr_array_header_t * * */ static int multipart_process_boundary(modsec_rec *msr, int last_part, char **error_log) { + assert(msr != NULL); /* if there was a part being built finish it */ if (msr->mpd->mpp != NULL) { /* close the temp file */ @@ -788,7 +796,8 @@ static int multipart_count_boundary_params(apr_pool_t *mp, const char *header_va * */ int multipart_init(modsec_rec *msr, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; msr->mpd = (multipart_data *)apr_pcalloc(msr->mp, sizeof(multipart_data)); @@ -952,6 +961,8 @@ int multipart_init(modsec_rec *msr, char **error_msg) { * is clear that there is no more data to be processed. */ int multipart_complete(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); if (msr->mpd == NULL) return 1; if (msr->txcfg->debuglog_level >= 4) { @@ -1055,10 +1066,12 @@ int multipart_complete(modsec_rec *msr, char **error_msg) { int multipart_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { + assert(msr != NULL); + assert(buf != NULL); + assert(error_msg != NULL); char *inptr = (char *)buf; unsigned int inleft = size; - if (error_msg == NULL) return -1; *error_msg = NULL; if (size == 0) return 1; @@ -1433,6 +1446,7 @@ apr_status_t multipart_cleanup(modsec_rec *msr) { * */ int multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments) { + assert(msr != NULL); multipart_part **parts; int i; diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 8bbf972689..894c84b9de 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -21,6 +21,9 @@ int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies, const char *delim) { + assert(msr != NULL); + assert(cookies != NULL); + assert(delim != NULL); char *attr_name = NULL, *attr_value = NULL; char *cookie_header; char *saveptr = NULL; @@ -95,6 +98,8 @@ int parse_cookies_v0(modsec_rec *msr, char *_cookie_header, int parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies) { + assert(msr != NULL); + assert(cookies != NULL); char *attr_name = NULL, *attr_value = NULL, *p = NULL; char *prev_attr_name = NULL; char *cookie_header = NULL; @@ -239,6 +244,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, int argument_separator, const char *origin, apr_table_t *arguments, int *invalid_count) { + assert(msr != NULL); msc_arg *arg; apr_size_t i, j; char *value = NULL; @@ -340,6 +346,9 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, */ void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) { + assert(msr != NULL); + assert(arguments != NULL); + assert(arg != NULL); if (msr->txcfg->debuglog_level >= 5) { msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"", arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index e84c33a391..ba8bdfd416 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -41,6 +41,8 @@ void msre_engine_reqbody_processor_register(msre_engine *engine, * Prepare to accept the request body (part 2). */ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { @@ -80,6 +82,8 @@ static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char ** * Prepare to accept the request body (part 1). */ apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; msr->msc_reqbody_length = 0; msr->stream_input_length = 0; @@ -161,6 +165,8 @@ apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) { static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); apr_size_t i; *error_msg = NULL; @@ -181,6 +187,8 @@ static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr, static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Would storing this chunk mean going over the limit? */ @@ -309,6 +317,8 @@ static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr, apr_status_t modsecurity_request_body_store(modsec_rec *msr, const char *data, apr_size_t length, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* If we have a processor for this request body send @@ -428,6 +438,8 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, } apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); #ifndef MSC_LARGE_STREAM_INPUT char *stream_input_body = NULL; char *data = NULL; @@ -541,6 +553,8 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf * Replace a bunch of chunks holding a request body with a single large chunk. */ static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); msc_data_chunk **chunks, *one_chunk; char *d; int i, sofar; @@ -614,6 +628,8 @@ static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **err * */ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); int invalid_count = 0; *error_msg = NULL; @@ -643,6 +659,8 @@ static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, cha * Stops receiving the request body. */ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Close open file descriptors, if any. */ @@ -753,6 +771,8 @@ apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) { * Prepares to forward the request body. */ apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) { @@ -821,6 +841,8 @@ apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) { apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk, long int nbytes, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); msc_data_chunk **chunks; *error_msg = NULL; @@ -922,6 +944,8 @@ apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr, * */ apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Release memory we used to store request body data. */ diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index 61f2c916a3..f8610b39e3 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -535,6 +535,8 @@ int TreeCheckData(TreePrefix *prefix, CPTData *prefix_data, unsigned int netmask } int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, int flag) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); CPTData *prefix_data = NULL; int ret = 0; @@ -574,6 +576,8 @@ int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, } TreeNode *CPTRetriveNode(modsec_rec *msr, unsigned char *buffer, unsigned int ip_bitmask, TreeNode *node) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); unsigned int x, y; if(node == NULL) { @@ -620,6 +624,8 @@ TreeNode *CPTRetriveParentNode(TreeNode *node) { } TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsigned char ip_bitmask, TreeNode *node) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); TreeNode *netmask_node = NULL; int mask = 0, bytes = 0; int i = 0, j = 0; @@ -656,16 +662,22 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig } node = CPTRetriveNode(msr, ipdata, ip_bitmask, node); - if (node == NULL) return NULL; + if (!node) { + if (msr && msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "CPTFindElementIPNetblock: No tree node found."); + } + return NULL; + } + - if (node && node->bit != ip_bitmask) { + if (node->bit != ip_bitmask) { if (msr && msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but netmask is different."); } return NULL; } - if (node && node->prefix == NULL) { + if (node->prefix == NULL) { if (msr && msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but prefix is NULL."); } @@ -701,6 +713,8 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig } TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); TreeNode *node = NULL; int mask = 0, bytes = 0; unsigned char temp_data[NETMASK_256-1]; @@ -782,6 +796,8 @@ TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip } TreeNode *CPTIpMatch(modsec_rec *msr, unsigned char *ipdata, CPTTree *tree, int type) { + // msr can be NULL; + assert(!msr || msr->txcfg != NULL); if(tree == NULL) { if (msr && msr->txcfg->debuglog_level >= 9) { @@ -840,6 +856,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { *(ip_strv4 + (sizeof(ip_strv4) - 1)) = '\0'; ptr = strdup(ip_strv4); + if (ptr == NULL) return NULL; // No way to return a clean error message netmask_v4 = is_netmask_v4(ptr); if (netmask_v4 > NETMASK_32) { @@ -876,6 +893,7 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { *(ip_strv6 + sizeof(ip_strv6) - 1) = '\0'; ptr = strdup(ip_strv6); + if (ptr == NULL) return NULL; // No way to return a clean error message netmask_v6 = is_netmask_v6(ptr); if (netmask_v6 > NETMASK_128) { @@ -912,4 +930,3 @@ TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { return NULL; } - diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 0ce58f919e..535975718f 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -667,6 +667,7 @@ int convert_to_int(const char c) * \retval 0 On Sucess|Fail */ int set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n) { + assert(msr != NULL); if (capture) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -2378,6 +2379,7 @@ apr_fileperms_t mode2fileperms(int mode) { * Generate a single variable. */ char *construct_single_var(modsec_rec *msr, char *name) { + assert(msr != NULL); char *varname = NULL; char *param = NULL; msre_var *var = NULL; @@ -2386,6 +2388,7 @@ char *construct_single_var(modsec_rec *msr, char *name) { /* Extract variable name and its parameter from the script. */ varname = apr_pstrdup(msr->mp, name); + if (varname == NULL) return NULL; param = strchr(varname, '.'); if (param != NULL) { *param = '\0'; @@ -2703,6 +2706,10 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, int tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree, const char *value, modsec_rec *msr, char **error_msg) { + assert(mp != NULL); + assert(value != NULL); + // msr can be NULL; + assert(error_msg != NULL); struct in_addr in; #if APR_HAVE_IPV6 struct in6_addr in6; diff --git a/apache2/msc_util.h b/apache2/msc_util.h index e4e043de16..cd2016e89e 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -15,6 +15,7 @@ #ifndef _UTIL_H_ #define _UTIL_H_ +#include <assert.h> #include <sys/types.h> #include <apr_file_info.h> diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 5b5bbb1a25..808f7e9097 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -24,9 +24,10 @@ xml_unload_external_entity(const char *URI, xmlCharEncoding enc) { * Initialise XML parser. */ int xml_init(modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(error_msg != NULL); xmlParserInputBufferCreateFilenameFunc entity; - if (error_msg == NULL) return -1; *error_msg = NULL; msr->xml = apr_pcalloc(msr->mp, sizeof(xml_data)); @@ -59,7 +60,8 @@ static void xml_receive_sax_error(void *data, const char *msg, ...) { * Feed one chunk of data to the XML parser. */ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* We want to initialise our parsing context here, to @@ -107,7 +109,8 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char * Finalise XML parsing. */ int xml_complete(modsec_rec *msr, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(error_msg != NULL); *error_msg = NULL; /* Only if we have a context, meaning we've done some work. */ diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index edd41c11ab..fd9c4fc72b 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -21,6 +21,8 @@ static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, int log_vars) { + assert(msr != NULL); + assert(blob != NULL); apr_table_t *col = NULL; unsigned int blob_offset; @@ -90,6 +92,8 @@ static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name, const char *col_key, int col_key_len) { + assert(msr != NULL); + assert(col_name != NULL); char *dbm_filename = NULL; apr_status_t rc; apr_sdbm_datum_t key; @@ -346,6 +350,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, const char *col_key, int col_key_len) { + assert(msr != NULL); apr_time_t time_before = apr_time_now(); apr_table_t *rtable = NULL; @@ -360,6 +365,7 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name, * */ int collection_store(modsec_rec *msr, apr_table_t *col) { + assert(msr != NULL); char *dbm_filename = NULL; msc_string *var_name = NULL, *var_key = NULL; unsigned char *blob = NULL; @@ -647,6 +653,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { * */ int collections_remove_stale(modsec_rec *msr, const char *col_name) { + assert(msr != NULL); + assert(col_name != NULL); char *dbm_filename = NULL; apr_sdbm_datum_t key, value; apr_sdbm_t *dbm = NULL; diff --git a/apache2/re.c b/apache2/re.c index 41e1eb1412..77ea8ead16 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -57,6 +57,7 @@ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr); * \param targets Exception list. */ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *var, const char *exceptions) { + assert(msr != NULL); const char *targets = NULL; char *savedptr = NULL, *target = NULL; char *c = NULL, *name = NULL, *value = NULL; @@ -64,9 +65,6 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va char *myvalue = NULL, *myname = NULL; int match = 0; - if(msr == NULL) - return 0; - if(var == NULL) return 0; @@ -76,6 +74,8 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(rule->actionset == NULL) return 0; + assert(exceptions != NULL); + { myvar = apr_pstrdup(msr->mp, var->name); @@ -162,6 +162,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va * \param p3 Pointer to configuration option REPLACED_TARGET */ char *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re, const char *p2, const char *p3) { + assert(msr != NULL); char *err; if(ruleset == NULL) @@ -203,6 +204,8 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, apr_array_header_t *phase_arr, const char *p2, const char *p3) { + assert(msr != NULL); + assert(ruleset != NULL); msre_rule **rules; int i, j, mode; char *err; @@ -238,6 +241,8 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2, const char *p3) { + assert(msr != NULL); + assert(ruleset != NULL); msre_var **targets = NULL; const char *current_targets = NULL; @@ -948,6 +953,9 @@ msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char * static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param, modsec_rec *msr, char **error_msg) { + assert(msr != NULL); + assert(ruleset != NULL); + assert(error_msg != NULL); msre_var *var = msre_create_var_ex(ruleset->mp, ruleset->engine, name, param, msr, error_msg); if (var == NULL) return NULL; @@ -1549,6 +1557,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re #if defined(PERFORMANCE_MEASUREMENT) apr_time_t time1 = 0; #endif + assert(rule->actionset != NULL); /* Reset the rule interception flag */ msr->rule_was_intercepted = 0; @@ -1767,11 +1776,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re fn = apr_psprintf(p, " [file \"%s\"] [line \"%d\"]", rule->filename, rule->line_num); } - if (rule->actionset != NULL && rule->actionset->id != NULL) { + if (rule->actionset->id != NULL) { id = apr_psprintf(p, " [id \"%s\"]", rule->actionset->id); } - if (rule->actionset != NULL && rule->actionset->rev != NULL) { + if (rule->actionset->rev != NULL) { rev = apr_psprintf(p, " [rev \"%s\"]", rule->actionset->rev); } @@ -1905,13 +1914,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re else if (rc < 0) { const char *id = ""; const char *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) { - id = rule->actionset->id; - } - if (rule->actionset->msg) { - msg = rule->actionset->msg; - } + if (rule->actionset->id) { + id = rule->actionset->id; + } + if (rule->actionset->msg) { + msg = rule->actionset->msg; } msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); @@ -1919,7 +1926,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re apr_table_clear(msr->matched_vars); return -1; } else { - if (rule->actionset && rule->actionset->is_chained) { + if (rule->actionset->is_chained) { /* If the current rule is part of a chain then * we need to skip over all the rules in the chain. */ @@ -1945,13 +1952,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re else { const char *id = ""; const char *msg = ""; - if (rule->actionset) { - if (rule->actionset->id) { - id = rule->actionset->id; - } - if (rule->actionset->msg) { - msg = rule->actionset->msg; - } + if (rule->actionset->id) { + id = rule->actionset->id; + } + if (rule->actionset->msg) { + msg = rule->actionset->msg; } msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); apr_table_clear(msr->matched_vars); @@ -2091,6 +2096,8 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; + assert(rule != NULL); + assert(rule->actionset != NULL); if (mode == 0) { /* Looking for next rule. */ int remove_rule = 0; @@ -2099,7 +2106,7 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, if (rule->placeholder == RULE_PH_NONE) { switch(re->type) { case RULE_EXCEPTION_REMOVE_ID : - if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { + if (rule->actionset->id != NULL) { int ruleid = atoi(rule->actionset->id); if (rule_id_in_range(ruleid, re->param)) { @@ -2152,9 +2159,9 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, if (remove_rule) { /* Do not increment j. */ removed_count++; - if (rule->actionset && rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ + if (rule->actionset->is_chained) mode = 2; /* Remove rules in this chain. */ } else { - if (rule->actionset && rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ + if (rule->actionset->is_chained) mode = 1; /* Keep rules in this chain. */ rules[j++] = rules[i]; } } else { /* Handling rule that is part of a chain. */ @@ -2211,6 +2218,7 @@ static const char *msre_format_severity(int severity) { * Creates a string containing the metadata of the supplied rule. */ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) { + assert(msr != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; char *id = ""; @@ -2507,6 +2515,8 @@ msre_rule *msre_rule_lua_create(msre_ruleset *ruleset, static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule, msre_actionset *actionset, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(actionset != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int i; @@ -2529,6 +2539,8 @@ static void msre_perform_nondisruptive_actions(modsec_rec *msr, msre_rule *rule, static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, msre_actionset *actionset, apr_pool_t *mptmp, const char *message) { + assert(msr != NULL); + assert(actionset != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int i; @@ -2613,6 +2625,14 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, msre_actionset *acting_actionset, apr_pool_t *mptmp) { + assert(var != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->op_metadata != NULL); + assert(rule->op_metadata->execute != NULL); + assert(msr != NULL); + assert(acting_actionset != NULL); + assert(mptmp != NULL); apr_time_t time_before_op = 0; char *my_error_msg = NULL; const char *full_varname = NULL; diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 5b6b9dd184..149c73dbb1 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -51,6 +51,7 @@ static void msre_engine_action_register(msre_engine *engine, const char *name, msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); apr_table_t *vartab = NULL; const apr_table_entry_t *te = NULL; const apr_array_header_t *arr = NULL; @@ -108,6 +109,7 @@ msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; apr_table_t *vartab = NULL, *tvartab = NULL; @@ -169,6 +171,8 @@ apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header * in the given variable. */ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); char *data = NULL; apr_array_header_t *arr = NULL; char *p = NULL, *q = NULL, *t = NULL; @@ -316,6 +320,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t * value that is set. */ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var) { + assert(msr != NULL); apr_table_t *table = NULL; msc_string *var = NULL; const char *var_name = NULL; @@ -628,6 +633,8 @@ static apr_status_t msre_action_redirect_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_redirect_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; var = apr_pcalloc(mptmp, sizeof(msc_string)); @@ -660,6 +667,8 @@ static apr_status_t msre_action_proxy_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; var = apr_pcalloc(mptmp, sizeof(msc_string)); @@ -968,6 +977,8 @@ static apr_status_t msre_action_ctl_init(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *name = NULL; char *value = NULL; @@ -1236,13 +1247,21 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, msr_log(msr, 4, "Ctl: ruleRemoveTargetById id=%s targets=%s", p1, p2); } if (p2 == NULL) { - msr_log(msr, 1, "ModSecurity: Missing target for id \"%s\"", p1); + msr_log(msr, 1, "Ctl: ruleRemoveTargetById: Missing target for id \"%s\"", p1); return -1; } re = apr_pcalloc(msr->mp, sizeof(rule_exception)); + if (re == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } re->type = RULE_EXCEPTION_REMOVE_ID; re->param = (const char *)apr_pstrdup(msr->mp, p1); + if (re->param == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else @@ -1336,6 +1355,8 @@ static char *msre_action_xmlns_validate(msre_engine *engine, apr_pool_t *mp, msr static apr_status_t msre_action_sanitizeArg_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); const char *sargname = NULL; const apr_array_header_t *tarr; const apr_table_entry_t *telts; @@ -1364,6 +1385,8 @@ static apr_status_t msre_action_sanitizeArg_execute(modsec_rec *msr, apr_pool_t static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); const char *sargname = NULL; const apr_array_header_t *tarr; const apr_table_entry_t *telts; @@ -1439,6 +1462,8 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo static apr_status_t msre_action_sanitizeRequestHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); apr_table_set(msr->request_headers_to_sanitize, action->param, "1"); return 1; } @@ -1447,6 +1472,8 @@ static apr_status_t msre_action_sanitizeRequestHeader_execute(modsec_rec *msr, a static apr_status_t msre_action_sanitizeResponseHeader_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); apr_table_set(msr->response_headers_to_sanitize, action->param, "1"); return 1; } @@ -1455,6 +1482,8 @@ static apr_status_t msre_action_sanitizeResponseHeader_execute(modsec_rec *msr, static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *env_name = NULL, *env_value = NULL; char *s = NULL; @@ -1528,6 +1557,9 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, char *var_name, char *var_value) { + assert(msr != NULL); + assert(var_name != NULL); + assert(var_value != NULL); char *col_name = NULL; char *s = NULL; apr_table_t *target_col = NULL; @@ -1549,9 +1581,13 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, var->value_len = strlen(var->value); expand_macros(msr, var, rule, mptmp); var_name = log_escape_nq_ex(msr->mp, var->value, var->value_len); + if (var_name == NULL) { + msr_log(msr, 1, "Failed to allocate space to expand name macros"); + return -1; + } /* Handle the exclamation mark. */ - if (var_name != NULL && var_name[0] == '!') { + if (var_name[0] == '!') { var_name = var_name + 1; is_negated = 1; } @@ -1711,6 +1747,8 @@ apr_status_t msre_action_setvar_execute(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1736,6 +1774,8 @@ static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1833,6 +1873,8 @@ static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *m static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1967,6 +2009,8 @@ static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, const char *col_name, const char *col_key, unsigned int col_key_len) { + assert(msr != NULL); + assert(real_col_name != NULL); apr_table_t *table = NULL; msc_string *var = NULL; @@ -1980,7 +2024,6 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, /* Init collection from storage. */ table = collection_retrieve(msr, real_col_name, col_key, col_key_len); - if (table == NULL) { /* Does not exist yet - create new. */ @@ -2101,6 +2144,8 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); char *data = apr_pstrdup(msr->mp, action->param); char *col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2132,6 +2177,8 @@ static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mpt static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2156,6 +2203,8 @@ static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptm static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2180,6 +2229,8 @@ static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptm static apr_status_t msre_action_setrsc_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2228,7 +2279,9 @@ static char *msre_action_exec_validate(msre_engine *engine, apr_pool_t *mp, msre static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { - #if defined(WITH_LUA) + assert(msr != NULL); + assert(action != NULL); +#if defined(WITH_LUA) if (action->param_data != NULL) { /* Lua */ msc_script *script = (msc_script *)action->param_data; char *my_error_msg = NULL; @@ -2256,6 +2309,8 @@ static apr_status_t msre_action_exec_execute(modsec_rec *msr, apr_pool_t *mptmp, static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; /* Expand any macros in the text */ @@ -2276,6 +2331,8 @@ static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mpt static apr_status_t msre_action_append_execute(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action) { + assert(msr != NULL); + assert(action != NULL); msc_string *var = NULL; /* Expand any macros in the text */ diff --git a/apache2/re_operators.c b/apache2/re_operators.c index cbf5c2db79..b5c171f430 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -70,6 +70,7 @@ msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(error_msg != NULL); *error_msg = "Unconditional match in SecAction."; /* Always match. */ @@ -81,6 +82,7 @@ static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(error_msg != NULL); *error_msg = "No match."; /* Never match. */ @@ -131,13 +133,13 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); TreeRoot *rtree = NULL; int res = 0; - if (error_msg == NULL) - return -1; - else - *error_msg = NULL; + *error_msg = NULL; if (rule == NULL || rule->ip_op == NULL) { msr_log(msr, 1, "ipMatch Internal Error: ipmatch value is null."); @@ -258,14 +260,14 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg) */ static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); TreeRoot *rtree = (TreeRoot *)rule->op_param_data; int res = 0; - if (error_msg == NULL) - return -1; - else - *error_msg = NULL; + *error_msg = NULL; if (rtree == NULL) { @@ -469,8 +471,20 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!str) { + msr_log(msr, 1, "rsub: Memory allocation error"); + return -1; + } msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "rsub: Memory allocation error"); + return -1; + } char *offset = NULL; char *data = NULL, *pattern = NULL; char *data_out = NULL; @@ -483,7 +497,6 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, regmatch_t pmatch[AP_MAX_REG_MATCH]; #endif - if (error_msg == NULL) return -1; *error_msg = NULL; if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) { @@ -741,8 +754,16 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On fail */ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "validateHash: Memory allocation error"); + return -1; + } const char *target; const char *errptr = NULL; int erroffset; @@ -757,8 +778,6 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (msr->txcfg->hash_enforcement == HASH_DISABLED || msr->txcfg->hash_is_enabled == HASH_DISABLED) @@ -999,8 +1018,21 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + if (!regex) { + msr_log(msr, 1, "rx: Memory allocation error"); + return -1; + } msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!re_pattern) { + msr_log(msr, 1, "rx: Memory allocation error"); + return -1; + } const char *target; const char *errptr = NULL; int erroffset; @@ -1021,8 +1053,6 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -1097,29 +1127,30 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c target_length = var->value_len; } - /* Are we supposed to capture subexpressions? */ - if (rule->actionset) { + if (rule->actionset->actions) { + /* Are we supposed to capture subexpressions? */ capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) + if (!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; matched = apr_table_get(rule->actionset->actions, "sanitizeMatched") ? 1 : 0; - if(!matched) + if (!matched) matched = apr_table_get(rule->actionset->actions, "sanitiseMatched") ? 1 : 0; + } + else capture = 0; - /* Show when the regex captures but "capture" is not set */ - if (msr->txcfg->debuglog_level >= 6) { - int capcount = 0; + /* Show when the regex captures but "capture" is not set */ + if (msr->txcfg->debuglog_level >= 6) { + int capcount = 0; #ifdef WITH_PCRE2 - rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); + rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); #else - rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); + rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); #endif - if (msr->txcfg->debuglog_level >= 6) { - if ((capture == 0) && (capcount > 0)) { - msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); - } + if (msr->txcfg->debuglog_level >= 6) { + if ((capture == 0) && (capcount > 0)) { + msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled."); } } } @@ -1447,6 +1478,11 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; apr_status_t rc = 0; int capture; @@ -1456,7 +1492,9 @@ static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c if ((var->value == NULL) || (var->value_len == 0)) return 0; /* Are we supposed to capture subexpressions? */ - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + if (rule->actionset->actions) + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + else capture = 0; if (rule->op_param_data == NULL) { @@ -1633,6 +1671,9 @@ static const char *gsb_reduce_char(apr_pool_t *pool, const char *domain) { * \retval 0 On No Match */ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned int match_length) { + assert(gsb != NULL); + assert(msr != NULL); + assert(match != NULL); apr_md5_ctx_t ctx; apr_status_t rc; unsigned char digest[APR_MD5_DIGESTSIZE]; @@ -1710,6 +1751,10 @@ static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; char *my_error_msg = NULL; int ovector[33]; @@ -2056,7 +2101,6 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va unsigned int target_length = 0; unsigned int i, i_max; - if (error_msg == NULL) return -1; *error_msg = NULL; str->value = (char *)rule->op_param; @@ -2119,15 +2163,22 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va /* contains */ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2198,7 +2249,13 @@ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var * */ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->actionset->actions != NULL); + assert(var != NULL); + assert(var != NULL); + assert(error_msg != NULL); char fingerprint[8]; int issqli; int capture; @@ -2230,6 +2287,11 @@ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var */ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->actionset->actions != NULL); + assert(error_msg != NULL); int capture; int is_xss; @@ -2256,16 +2318,23 @@ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var /* containsWord */ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; int rc = 0; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2273,7 +2342,6 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2351,14 +2419,21 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v /* streq */ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (!str) { + msr_log(msr, 1, "streq: Memory allocation error"); + return -1; + } const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2366,7 +2441,6 @@ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2407,14 +2481,21 @@ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var /* beginsWith */ static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2470,14 +2551,19 @@ static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var /* endsWith */ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + assert(msr != NULL); + assert(rule != NULL); const char *match = NULL; const char *target; unsigned int match_length; unsigned int target_length; + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (str == NULL) { + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } str->value = (char *)rule->op_param; - if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2485,7 +2571,6 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var * str->value_len = strlen(str->value); - if (error_msg == NULL) return -1; *error_msg = NULL; expand_macros(msr, str, rule, msr->mp); @@ -2562,12 +2647,15 @@ static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { } static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; const char *target; unsigned int target_length; const char *rc; - if (error_msg == NULL) return -1; *error_msg = NULL; if (compiled_pattern == NULL) { @@ -2610,6 +2698,10 @@ static int msre_op_validateDTD_init(msre_rule *rule, char **error_msg) { static int msre_op_validateDTD_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); xmlValidCtxtPtr cvp; xmlDtdPtr dtd; @@ -2680,6 +2772,10 @@ static int msre_op_validateSchema_init(msre_rule *rule, char **error_msg) { static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); xmlSchemaParserCtxtPtr parserCtx; xmlSchemaValidCtxtPtr validCtx; xmlSchemaPtr schema; @@ -2817,6 +2913,10 @@ static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { } static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -2836,7 +2936,6 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * #endif #endif - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -2844,6 +2943,8 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -2934,53 +3035,51 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); - } + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); } - } + } } @@ -3146,6 +3245,11 @@ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -3165,8 +3269,6 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var #endif #endif - - if (error_msg == NULL) return -1; *error_msg = NULL; if (regex == NULL) { @@ -3174,6 +3276,8 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -3241,11 +3345,11 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var /* Verify a match. */ if (rc > 0) { - const char *match = target + ovector[0]; + const char* match = target + ovector[0]; int length = ovector[1] - ovector[0]; int i = 0; - offset = ovector[2*i]; + offset = ovector[2 * i]; /* Check CPF using the match string */ is_cpf = cpf_verify(match, length); @@ -3263,58 +3367,57 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if (!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for (; i < rc; i++) { + msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void*)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); - } + if ((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void*)mparm); } + else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void*)mparm); + } } + } } /* Unset the remaining TX vars (from previous invocations). */ - for(; i <= 9; i++) { + for (; i <= 9; i++) { char buf[24]; apr_snprintf(buf, sizeof(buf), "%i", i); apr_table_unset(msr->tx_vars, buf); @@ -3349,6 +3452,8 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var * \retval 1 On Valid SSN */ static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) { + assert(msr != NULL); + assert(ssnumber != NULL); int i; int num[9]; int digits = 0; @@ -3460,6 +3565,11 @@ static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { * \retval 0 On No Match */ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; const char *target; unsigned int target_length; @@ -3488,6 +3598,8 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var return -1; } + assert(rule->actionset != NULL); + memset(ovector, 0, sizeof(ovector)); #ifdef WITH_PCRE_STUDY @@ -3577,53 +3689,51 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var * and we are done. */ - if (rule->actionset) { - matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if(!matched_bytes) - matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; - - if (apr_table_get(rule->actionset->actions, "capture")) { - for(; i < rc; i++) { - msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); - if (s == NULL) return -1; - s->name = apr_psprintf(msr->mp, "%d", i); - if (s->name == NULL) return -1; - s->name_len = strlen(s->name); - s->value = apr_pstrmemdup(msr->mp, match, length); - if (s->value == NULL) return -1; - s->value_len = length; - - apr_table_setn(msr->tx_vars, s->name, (void *)s); - - if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); - } + matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; + if(!matched_bytes) + matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; + + if (apr_table_get(rule->actionset->actions, "capture")) { + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + if (s == NULL) return -1; + s->name = apr_psprintf(msr->mp, "%d", i); + if (s->name == NULL) return -1; + s->name_len = strlen(s->name); + s->value = apr_pstrmemdup(msr->mp, match, length); + if (s->value == NULL) return -1; + s->value_len = length; + + apr_table_setn(msr->tx_vars, s->name, (void *)s); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, + log_escape_nq_ex(msr->mp, s->value, s->value_len)); + } - if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { - qspos = apr_psprintf(msr->mp, "%s", var->name); - parm = strstr(qspos, ":"); - if (parm != NULL) { - parm++; - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - mparm->pad_1 = rule->actionset->arg_min; - mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); - } else { - mparm = apr_palloc(msr->mp, sizeof(msc_parm)); - if (mparm == NULL) - continue; - - mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); - } + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + qspos = apr_psprintf(msr->mp, "%s", var->name); + parm = strstr(qspos, ":"); + if (parm != NULL) { + parm++; + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + mparm->pad_1 = rule->actionset->arg_min; + mparm->pad_2 = rule->actionset->arg_max; + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { + mparm = apr_palloc(msr->mp, sizeof(msc_parm)); + if (mparm == NULL) + continue; + + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); } - } + } } @@ -3658,6 +3768,9 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); geo_rec rec; geo_db *geo = msr->txcfg->geo; const char *geo_host = var->value; @@ -3784,6 +3897,11 @@ static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var /* rbl */ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(var != NULL); + assert(error_msg != NULL); unsigned int h0, h1, h2, h3; unsigned int high8bits = 0; char *name_to_check = NULL; @@ -3792,10 +3910,11 @@ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, apr_status_t rc; int capture = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; - capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + if (rule->actionset->actions) + capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; + else capture = 0; /* ENH Add IPv6 support. */ @@ -4072,18 +4191,16 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); #ifdef WITH_SSDEEP char result[FUZZY_MAX_RESULT]; struct fuzzy_hash_param_data *param = rule->op_param_data; struct fuzzy_hash_chunk *chunk = param->head; #endif - if (error_msg == NULL) - { - return -1; - } - *error_msg = NULL; #ifdef WITH_SSDEEP @@ -4164,7 +4281,10 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { - if (error_msg == NULL) return -1; + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); *error_msg = NULL; if (rule->op_param_data == NULL) { @@ -4288,10 +4408,13 @@ static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) { static int msre_op_validateByteRange_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); char *table = rule->op_param_data; unsigned int i, count; - if (error_msg == NULL) return -1; *error_msg = NULL; if (table == NULL) { @@ -4362,6 +4485,9 @@ static int validate_url_encoding(const char *input, long int input_length) { static int msre_op_validateUrlEncoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); int rc = validate_url_encoding(var->value, var->value_len); switch(rc) { case 1 : @@ -4482,6 +4608,9 @@ static int detect_utf8_character(const unsigned char *p_read, unsigned int lengt static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(var != NULL); + assert(error_msg != NULL); unsigned int i, bytes_left; bytes_left = var->value_len; @@ -4539,6 +4668,9 @@ static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4577,6 +4709,10 @@ static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4620,16 +4756,14 @@ static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; - if ((var->value == NULL)||(rule->op_param == NULL)) { - /* NULL values do not match anything. */ - return 0; - } - - if (error_msg == NULL) return -1; *error_msg = NULL; if ((var->value == NULL)||(rule->op_param == NULL)) { @@ -4663,6 +4797,10 @@ static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4706,6 +4844,10 @@ static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string str; int left, right; char *target = NULL; @@ -4715,7 +4857,6 @@ static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, return 0; } - if (error_msg == NULL) return -1; *error_msg = NULL; if ((var->value == NULL)||(rule->op_param == NULL)) { diff --git a/apache2/re_variables.c b/apache2/re_variables.c index a53140b2c1..5aa7589a2b 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -99,6 +99,10 @@ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -144,6 +148,10 @@ static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; unsigned int combined_size = 0; @@ -171,6 +179,10 @@ static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -214,6 +226,10 @@ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -262,6 +278,10 @@ static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -308,6 +328,10 @@ static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -356,6 +380,10 @@ static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -402,10 +430,14 @@ static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_actionset *actionset = NULL; - if (rule == NULL) return 0; - actionset = rule->actionset; if (rule->chain_starter != NULL) actionset = rule->chain_starter->actionset; @@ -437,13 +469,13 @@ static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, return var_simple_generate(var, vartab, mptmp, value); } - return 0; } /* ENV */ static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { + assert(ruleset != NULL); if (var->param == NULL) { return apr_psprintf(ruleset->mp, "Parameter required for ENV."); } @@ -458,6 +490,8 @@ static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); char *value = get_env_var(msr->r, (char *)var->param); if (value != NULL) { return var_simple_generate(var, vartab, mptmp, value); @@ -470,6 +504,7 @@ static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri); } @@ -478,6 +513,8 @@ static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_uniqueid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = get_env_var(msr->r, "UNIQUE_ID"); if (value != NULL) { return var_simple_generate(var, vartab, mptmp, value); @@ -492,10 +529,18 @@ static int var_uniqueid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) /* dynamic */ { + assert(msr != NULL); + assert(msr->r != NULL); char *value = NULL; if (msr->r->parsed_uri.query == NULL) value = msr->r->parsed_uri.path; - else value = apr_pstrcat(mptmp, msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL); + else { + value = apr_pstrcat(mptmp, msr->r->parsed_uri.path, "?", msr->r->parsed_uri.query, NULL); + if (!value) { + msr_log(msr, 1, "REQUEST_URI: Memory allocation error"); + return -1; + } + } return var_simple_generate(var, vartab, mptmp, value); } @@ -505,7 +550,12 @@ static int var_request_uri_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_PROCESSOR: Memory allocation error"); + return -1; + } if (msr->msc_reqbody_processor == NULL) { rvar->value = apr_pstrdup(mptmp, ""); @@ -524,9 +574,22 @@ static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_r static int var_sdbm_delete_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "SDBM_DELETE_ERROR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", msr->msc_sdbm_delete_error); + if (!rvar->value) { + msr_log(msr, 1, "SDBM_DELETE_ERROR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -538,7 +601,12 @@ static int var_sdbm_delete_error_generate(modsec_rec *msr, msre_var *var, msre_r static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_ERROR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_error); rvar->value_len = strlen(rvar->value); @@ -552,7 +620,16 @@ static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQBODY_ERROR_MSG: Memory allocation error"); + return -1; + } if (msr->msc_reqbody_error_msg == NULL) { rvar->value = apr_pstrdup(mptmp, ""); @@ -581,6 +658,13 @@ static char *var_xml_validate(msre_ruleset *ruleset, msre_var *var) { static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(var->name != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; xmlXPathContextPtr xpathCtx; @@ -667,9 +751,19 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, content = (char *)xmlNodeGetContent(nodes->nodeTab[i]); if (content != NULL) { + xmlFree(content); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "XML: Memory allocation error"); + count = -1; + goto var_xml_generate_Error; + } rvar->value = apr_pstrdup(mptmp, content); - xmlFree(content); + if (!rvar->value) { + msr_log(msr, 1, "XML: Memory allocation error"); + count = -1; + goto var_xml_generate_Error; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -677,6 +771,7 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, } } +var_xml_generate_Error: xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); @@ -688,6 +783,11 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(var->name != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; int i, count = 0; @@ -698,7 +798,15 @@ static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre fem = format_error_log_message(mptmp, em); if (fem != NULL) { rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "WEBSERVER_ERROR_LOG: Memory allocation error"); + return -1; + } rvar->value = apr_pstrdup(mptmp, fem); + if (!rvar->value) { + msr_log(msr, 1, "WEBSERVER_ERROR_LOG: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -713,6 +821,7 @@ static int var_webserver_error_log_generate(modsec_rec *msr, msre_var *var, msre static int var_useragent_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->useragent_ip ? msr->useragent_ip : "0.0.0.0"); } #endif @@ -722,6 +831,7 @@ static int var_useragent_ip_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); #if !defined(MSC_TEST) #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3 if (ap_find_linked_module("mod_remoteip.c") != NULL) { @@ -739,6 +849,7 @@ static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value1 = ap_get_remote_host(msr->r->connection, msr->r->per_dir_config, REMOTE_NAME, NULL); return var_simple_generate(var, vartab, mptmp, value1); @@ -749,6 +860,7 @@ static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%u", msr->remote_port); return var_simple_generate(var, vartab, mptmp, value); } @@ -758,6 +870,7 @@ static int var_remote_port_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->remote_user); } @@ -766,6 +879,10 @@ static int var_remote_user_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -792,10 +909,18 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TX: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; rvar->name = apr_psprintf(mptmp, "TX:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + if (!rvar->name) { + msr_log(msr, 1, "TX: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -810,6 +935,10 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -863,6 +992,10 @@ static int var_highest_severity_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -911,6 +1044,8 @@ static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->matched_var != NULL); return var_simple_generate_ex(var, vartab, mptmp, apr_pmemdup(mptmp, msr->matched_var->value, @@ -923,6 +1058,8 @@ static int var_matched_var_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->matched_var != NULL); return var_simple_generate_ex(var, vartab, mptmp, apr_pmemdup(mptmp, msr->matched_var->name, @@ -935,6 +1072,10 @@ static int var_matched_var_name_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -965,6 +1106,10 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "SESSION: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; @@ -983,6 +1128,10 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1013,10 +1162,18 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "USER: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; rvar->name = apr_psprintf(mptmp, "USER:%s", log_escape_nq_ex(mptmp, str->name, str->name_len)); + if (!rvar->name) { + msr_log(msr, 1, "USER: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -1031,6 +1188,10 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1079,6 +1240,10 @@ static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1109,6 +1274,10 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESOURCE: Memory allocation error"); + return -1; + } rvar->value = str->value; rvar->value_len = str->value_len; @@ -1127,6 +1296,10 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1224,6 +1397,10 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1269,6 +1446,10 @@ static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1314,6 +1495,10 @@ static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1359,6 +1544,10 @@ static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, count = 0; @@ -1368,6 +1557,10 @@ static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *r for(i = 0; i < msr->mpd->parts->nelts; i++) { if (parts[i]->type == MULTIPART_FILE) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "FILES_NAMES: Memory allocation error"); + return count; + } rvar->value = parts[i]->name; rvar->value_len = strlen(rvar->value); @@ -1387,6 +1580,9 @@ static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; msre_var *rvar = NULL; unsigned int combined_size = 0; @@ -1402,6 +1598,10 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre } rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "FILES_NAMES: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%u", combined_size); rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1414,6 +1614,10 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); multipart_part **parts = NULL; int i, j, count = 0; @@ -1470,6 +1674,7 @@ static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_multipart_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->multipart_filename); } @@ -1478,6 +1683,7 @@ static int var_multipart_filename_generate(modsec_rec *msr, msre_var *var, msre_ static int var_multipart_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->multipart_name); } @@ -1486,6 +1692,7 @@ static int var_multipart_name_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_quoted != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1498,6 +1705,7 @@ static int var_multipart_boundary_quoted_generate(modsec_rec *msr, msre_var *var static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_boundary_whitespace != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1510,6 +1718,7 @@ static int var_multipart_boundary_whitespace_generate(modsec_rec *msr, msre_var static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_data_after != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1522,6 +1731,7 @@ static int var_multipart_data_after_generate(modsec_rec *msr, msre_var *var, msr static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_data_before != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1534,6 +1744,7 @@ static int var_multipart_data_before_generate(modsec_rec *msr, msre_var *var, ms static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_header_folding != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1546,6 +1757,7 @@ static int var_multipart_header_folding_generate(modsec_rec *msr, msre_var *var, static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_crlf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1558,6 +1770,7 @@ static int var_multipart_crlf_line_generate(modsec_rec *msr, msre_var *var, msre static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)&&(msr->mpd->flag_crlf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1570,6 +1783,7 @@ static int var_multipart_crlf_lf_lines_generate(modsec_rec *msr, msre_var *var, static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_lf_line != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1582,6 +1796,7 @@ static int var_multipart_lf_line_generate(modsec_rec *msr, msre_var *var, msre_r static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_missing_semicolon != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1594,6 +1809,7 @@ static int var_multipart_missing_semicolon_generate(modsec_rec *msr, msre_var *v static int var_multipart_invalid_part_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_part != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1606,6 +1822,7 @@ static int var_multipart_invalid_part_generate(modsec_rec *msr, msre_var *var, m static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_quoting != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1618,6 +1835,7 @@ static int var_multipart_invalid_quoting_generate(modsec_rec *msr, msre_var *var static int var_multipart_invalid_header_folding_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_invalid_header_folding != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1630,6 +1848,7 @@ static int var_multipart_invalid_header_folding_generate(modsec_rec *msr, msre_v static int var_multipart_file_limit_exceeded_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_file_limit_exceeded != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1642,6 +1861,7 @@ static int var_multipart_file_limit_exceeded_generate(modsec_rec *msr, msre_var static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->mpd != NULL) { /* Respond positive if at least one of the multipart flags is raised. */ if ( (msr->mpd->flag_error) @@ -1669,6 +1889,7 @@ static int var_multipart_strict_error_generate(modsec_rec *msr, msre_var *var, m static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if ((msr->mpd != NULL)&&(msr->mpd->flag_unmatched_boundary != 0)) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1681,6 +1902,7 @@ static int var_multipart_unmatched_boundary_generate(modsec_rec *msr, msre_var * static int var_urlencoded_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->urlencoded_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1693,6 +1915,7 @@ static int var_urlencoded_error_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_inbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->inbound_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1705,6 +1928,7 @@ static int var_inbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_outbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->outbound_error) { return var_simple_generate(var, vartab, mptmp, "1"); } else { @@ -1719,6 +1943,8 @@ static apr_time_t calculate_perf_combined(modsec_rec *msr) { } char *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp) { + assert(msr != NULL); + assert(mp != NULL); return apr_psprintf(mp, "combined=%" APR_TIME_T_FMT ", p1=%" APR_TIME_T_FMT ", p2=%" APR_TIME_T_FMT ", p3=%" APR_TIME_T_FMT ", p4=%" APR_TIME_T_FMT ", p5=%" APR_TIME_T_FMT ", sr=%" APR_TIME_T_FMT ", sw=%" APR_TIME_T_FMT @@ -1731,6 +1957,10 @@ char *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp) { static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp, apr_time_t value) { + assert(msr != NULL); + assert(var != NULL); + assert( vartab!= NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -1747,6 +1977,10 @@ static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_ru static int var_perf_all_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -1771,6 +2005,7 @@ static int var_perf_combined_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_perf_gc_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_gc); } @@ -1779,6 +2014,7 @@ static int var_perf_gc_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_perf_phase1_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase1); } @@ -1787,6 +2023,7 @@ static int var_perf_phase1_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase2_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase2); } @@ -1795,6 +2032,7 @@ static int var_perf_phase2_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase3_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase3); } @@ -1803,6 +2041,7 @@ static int var_perf_phase3_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase4_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase4); } @@ -1811,6 +2050,7 @@ static int var_perf_phase4_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_phase5_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_phase5); } @@ -1819,6 +2059,7 @@ static int var_perf_phase5_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_sread_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_storage_read); } @@ -1827,6 +2068,7 @@ static int var_perf_sread_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_perf_swrite_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_storage_write); } @@ -1835,6 +2077,7 @@ static int var_perf_swrite_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_perf_logging_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return generate_performance_variable(msr, var, rule, vartab, mptmp, msr->time_logging); } @@ -1844,6 +2087,10 @@ static int var_perf_logging_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -1887,9 +2134,16 @@ static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { - msre_var *rvar = NULL; + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); + msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "DURATION: Memory allocation error"); + return -1; + } - rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); rvar->value = apr_psprintf(mptmp, "%" APR_TIME_T_FMT, (apr_time_now() - msr->r->request_time)); rvar->value_len = strlen(rvar->value); @@ -1903,6 +2157,10 @@ static int var_duration_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1910,10 +2168,18 @@ static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19, (tm->tm_year % 100), tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); + if (!rvar->value) { + msr_log(msr, 1, "TIME: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1925,6 +2191,10 @@ static int var_time_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1932,9 +2202,17 @@ static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_YEAR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d%02d", (tm->tm_year / 100) + 19, tm->tm_year % 100); + if (!rvar->value) { + msr_log(msr, 1, "TIME_YEAR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1946,6 +2224,10 @@ static int var_time_year_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1953,7 +2235,15 @@ static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_WDAY: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%d", tm->tm_wday); + if (!rvar->value) { + msr_log(msr, 1, "TIME_WDAY: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1965,6 +2255,10 @@ static int var_time_wday_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1972,7 +2266,15 @@ static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_SEC: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_sec); + if (!rvar->value) { + msr_log(msr, 1, "TIME_SEC: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -1984,6 +2286,10 @@ static int var_time_sec_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -1991,7 +2297,15 @@ static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_MIN: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_min); + if (!rvar->value) { + msr_log(msr, 1, "TIME_MIN: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2002,6 +2316,10 @@ static int var_time_min_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2009,7 +2327,15 @@ static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rul tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_HOUR: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_hour); + if (!rvar->value) { + msr_log(msr, 1, "TIME_HOUR: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2021,6 +2347,10 @@ static int var_time_hour_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2028,7 +2358,21 @@ static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(rule != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); + if (!rvar) { + msr_log(msr, 1, "TIME_MON: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mon + 1); + if (!rvar->value) { + msr_log(msr, 1, "TIME_MON: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2040,6 +2384,11 @@ static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; struct tm *tm; time_t tc; @@ -2047,7 +2396,15 @@ static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tc = time(NULL); tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_DAY: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%02d", tm->tm_mday); + if (!rvar->value) { + msr_log(msr, 1, "TIME_DAY: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2059,12 +2416,24 @@ static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; time_t tc; tc = time(NULL); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "TIME_EPOCH: Memory allocation error"); + return -1; + } rvar->value = apr_psprintf(mptmp, "%ld", (long)tc); + if (!rvar->value) { + msr_log(msr, 1, "TIME_EPOCH: Memory allocation error"); + return -1; + } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); @@ -2076,6 +2445,7 @@ static int var_time_epoch_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->query_string); } @@ -2084,6 +2454,8 @@ static int var_query_string_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = file_basename(mptmp, msr->r->parsed_uri.path); return var_simple_generate(var, vartab, mptmp, value); } @@ -2155,6 +2527,10 @@ static int var_full_request_generate(modsec_rec *msr, msre_var *var, static int var_full_request_length_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; char *value = NULL; int headers_length = 0; @@ -2173,6 +2549,7 @@ static int var_full_request_length_generate(modsec_rec *msr, msre_var *var, msre static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->msc_reqbody_buffer != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->msc_reqbody_buffer, msr->msc_reqbody_length); @@ -2185,6 +2562,7 @@ static int var_request_body_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_body_length_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_length); return var_simple_generate(var, vartab, mptmp, value); } @@ -2194,6 +2572,10 @@ static int var_request_body_length_generate(modsec_rec *msr, msre_var *var, msre static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2259,6 +2641,10 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2324,6 +2710,10 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2348,11 +2738,19 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_COOKIES: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_COOKIES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2367,6 +2765,10 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2391,11 +2793,19 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_COOKIES_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_COOKIES_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_COOKIES_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2410,6 +2820,10 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2434,11 +2848,19 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_HEADERS: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_HEADERS: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2453,6 +2875,10 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2477,11 +2903,19 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "REQUEST_HEADERS_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "REQUEST_HEADERS_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "REQUEST_HEADERS_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2496,6 +2930,7 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path); } @@ -2504,6 +2939,7 @@ static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_line); } @@ -2512,6 +2948,7 @@ static int var_request_line_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_method); } @@ -2520,6 +2957,7 @@ static int var_request_method_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->request_protocol); } @@ -2528,6 +2966,7 @@ static int var_request_protocol_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->local_addr); } @@ -2536,6 +2975,7 @@ static int var_server_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, msr->hostname); } @@ -2544,7 +2984,12 @@ static int var_server_name_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = apr_psprintf(mptmp, "%u", msr->local_port); + if (!value) { + msr_log(msr, 1, "SERVER_PORT: Memory allocation error"); + return -1; + } return var_simple_generate(var, vartab, mptmp, value); } @@ -2553,6 +2998,8 @@ static int var_server_port_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = file_basename(mptmp, msr->r->filename); return var_simple_generate(var, vartab, mptmp, value); } @@ -2562,6 +3009,8 @@ static int var_script_basename_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = msr->r->filename; return var_simple_generate(var, vartab, mptmp, value); } @@ -2571,7 +3020,13 @@ static int var_script_filename_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.group); + if (!value) { + msr_log(msr, 1, "SCRIPT_GID: Memory allocation error"); + return -1; + } return var_simple_generate(var, vartab, mptmp, value); } @@ -2580,6 +3035,9 @@ static int var_script_gid_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = NULL; if (apr_gid_name_get(&value, msr->r->finfo.group, mptmp) == APR_SUCCESS) { return var_simple_generate(var, vartab, mptmp, value); @@ -2592,6 +3050,9 @@ static int var_script_groupname_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = apr_psprintf(mptmp, "%04x", msr->r->finfo.protection); return var_simple_generate(var, vartab, mptmp, value); } @@ -2601,6 +3062,9 @@ static int var_script_mode_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = apr_psprintf(mptmp, "%ld", (long)msr->r->finfo.user); return var_simple_generate(var, vartab, mptmp, value); } @@ -2610,6 +3074,9 @@ static int var_script_uid_generate(modsec_rec *msr, msre_var *var, msre_rule *ru static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); char *value = NULL; if (apr_uid_name_get(&value, msr->r->finfo.user, mptmp) == APR_SUCCESS) { return var_simple_generate(var, vartab, mptmp, value); @@ -2622,6 +3089,7 @@ static int var_script_username_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); char *value = msr->r->ap_auth_type; return var_simple_generate(var, vartab, mptmp, value); } @@ -2631,6 +3099,7 @@ static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->r->path_info; return var_simple_generate(var, vartab, mptmp, value); } @@ -2640,6 +3109,7 @@ static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_stream_output_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->stream_output_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->stream_output_data, msr->stream_output_length); @@ -2653,6 +3123,7 @@ static int var_stream_output_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_stream_input_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->stream_input_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->stream_input_data, msr->stream_input_length); @@ -2666,6 +3137,7 @@ static int var_stream_input_generate(modsec_rec *msr, msre_var *var, msre_rule * static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); if (msr->resbody_data != NULL) { return var_simple_generate_ex(var, vartab, mptmp, msr->resbody_data, msr->resbody_length); @@ -2679,6 +3151,10 @@ static int var_response_body_generate(modsec_rec *msr, msre_var *var, msre_rule static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2705,11 +3181,19 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS: Memory allocation error"); + return -1; + } rvar->value = te[i].val; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar->name) { + msr_log(msr, 1, "RESPONSE_HEADERS: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2724,6 +3208,10 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; int i, count = 0; @@ -2748,11 +3236,19 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m /* If we had a match add this argument to the collection. */ if (match) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS_NAMES: Memory allocation error"); + return -1; + } rvar->value = te[i].key; rvar->value_len = strlen(rvar->value); rvar->name = apr_psprintf(mptmp, "RESPONSE_HEADERS_NAMES:%s", log_escape_nq(mptmp, te[i].key)); + if (!rvar) { + msr_log(msr, 1, "RESPONSE_HEADERS_NAMES: Memory allocation error"); + return -1; + } apr_table_addn(vartab, rvar->name, (void *)rvar); count++; @@ -2767,6 +3263,7 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->status_line; return var_simple_generate(var, vartab, mptmp, value); } @@ -2776,6 +3273,7 @@ static int var_status_line_generate(modsec_rec *msr, msre_var *var, msre_rule *r static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->response_protocol; return var_simple_generate(var, vartab, mptmp, value); } @@ -2785,6 +3283,7 @@ static int var_response_protocol_generate(modsec_rec *msr, msre_var *var, msre_r static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = apr_psprintf(mptmp, "%u", msr->response_status); return var_simple_generate(var, vartab, mptmp, value); } @@ -2794,6 +3293,8 @@ static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rul static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->content_type); } @@ -2802,6 +3303,8 @@ static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule * static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->r != NULL); const char *value = apr_psprintf(mptmp, "%" APR_OFF_T_FMT, msr->r->clength); return var_simple_generate(var, vartab, mptmp, value); } @@ -2811,6 +3314,7 @@ static int var_response_content_length(modsec_rec *msr, msre_var *var, msre_rule static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->userid; return var_simple_generate(var, vartab, mptmp, value); } @@ -2820,6 +3324,7 @@ static int var_userid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); const char *value = msr->sessionid; return var_simple_generate(var, vartab, mptmp, value); } @@ -2829,6 +3334,8 @@ static int var_sessionid_generate(modsec_rec *msr, msre_var *var, msre_rule *rul static int var_webappid_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(msr->txcfg != NULL); const char *value = msr->txcfg->webappid; return var_simple_generate(var, vartab, mptmp, value); } From 462bf7011ae82411b9ba5e69309fae4653578aef Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 21 Feb 2024 17:43:21 +0100 Subject: [PATCH 375/477] Add more test cases --- .github/workflows/ci.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b18bfb78d..e5ca97df84 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,12 +10,19 @@ jobs: strategy: matrix: os: [ubuntu-22.04] - platform: [x64] - compiler: [gcc] + platform: [x32, x64] + compiler: [gcc, clang] configure: - - {label: "with pcre2", opt: "--with-pcre2" } - - {label: "with lua", opt: "--with-lua" } - - {label: "wo lua", opt: "--without-lua" } + - {label: "with pcre, no study, no jit", opt: "--enable-pcre-study=no" } + - {label: "with pcre, with study, no jit", opt: "--enable-pcre-study=yes" } + - {label: "with pcre, no study, with jit", opt: "--enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre, with study, with jit", opt: "--enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with pcre2", opt: "--with-pcre2 --enable-pcre-study=no" } + - {label: "with pcre2, with study, no jit", opt: "--with-pcre2 --enable-pcre-study=yes" } + - {label: "with pcre2, no study, with jit", opt: "--with-pcre2 --enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre2, with study, with jit", opt: "--with-pcre2 --enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with lua", opt: "--with-lua" } + - {label: "wo lua", opt: "--without-lua" } steps: - name: Setup Dependencies run: | From b7a4a4428c4cac2459499add764c5f7b7b46218e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sun, 25 Feb 2024 20:28:12 +0100 Subject: [PATCH 376/477] Replace obsolote macros --- build/compile | 248 +++++++++++++++++++++++++++++++++++++++---- build/find_apr.m4 | 2 +- build/find_apu.m4 | 2 +- build/find_curl.m4 | 2 +- build/find_lua.m4 | 2 +- build/find_pcre.m4 | 2 +- build/find_pcre2.m4 | 2 +- build/find_ssdeep.m4 | 2 +- build/find_yajl.m4 | 2 +- configure.ac | 10 +- 10 files changed, 240 insertions(+), 34 deletions(-) diff --git a/build/compile b/build/compile index 1b1d232169..df363c8fbf 100755 --- a/build/compile +++ b/build/compile @@ -1,9 +1,9 @@ #! /bin/sh -# Wrapper for compilers which do not understand `-c -o'. +# Wrapper for compilers which do not understand '-c -o'. -scriptversion=2005-05-14.22 +scriptversion=2018-03-07.03; # UTC -# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. +# Copyright (C) 1999-2021 Free Software Foundation, Inc. # Written by Tom Tromey <tromey@cygnus.com>. # # This program is free software; you can redistribute it and/or modify @@ -17,8 +17,7 @@ scriptversion=2005-05-14.22 # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# along with this program. If not, see <https://www.gnu.org/licenses/>. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -29,21 +28,224 @@ scriptversion=2005-05-14.22 # bugs to <bug-automake@gnu.org> or send patches to # <automake-patches@gnu.org>. +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN* | MSYS*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/* | msys/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + case $1 in '') - echo "$0: No command. Try \`$0 --help' for more information." 1>&2 + echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] -Wrapper for compilers which do not understand `-c -o'. -Remove `-o dest.o' from ARGS, run PROGRAM with the remaining +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the -right script to run: please start by reading the file `INSTALL'. +right script to run: please start by reading the file 'INSTALL'. Report bugs to <bug-automake@gnu.org>. EOF @@ -53,11 +255,14 @@ EOF echo "compile $scriptversion" exit $? ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; esac ofile= cfile= -eat= for arg do @@ -66,8 +271,8 @@ do else case $1 in -o) - # configure might choose to run compile as `compile cc -o foo foo.c'. - # So we strip `-o arg' only if arg is an object. + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) @@ -94,22 +299,22 @@ do done if test -z "$ofile" || test -z "$cfile"; then - # If no `-o' option was seen then we might have been invoked from a + # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no - # `.c' file was seen then we are probably linking. That is also + # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. -cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. -# Note: use `[/.-]' here to ensure that we don't use the same name +# Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. -lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break @@ -124,9 +329,9 @@ trap "rmdir '$lockdir'; exit 1" 1 2 15 ret=$? if test -f "$cofile"; then - mv "$cofile" "$ofile" + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then - mv "${cofile}bj" "$ofile" + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" @@ -135,8 +340,9 @@ exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" +# time-stamp-time-zone: "UTC0" +# time-stamp-end: "; # UTC" # End: diff --git a/build/find_apr.m4 b/build/find_apr.m4 index 5524b66285..a303696586 100644 --- a/build/find_apr.m4 +++ b/build/find_apr.m4 @@ -18,7 +18,7 @@ AC_DEFUN([CHECK_APR], AC_ARG_WITH( apr, - [AC_HELP_STRING([--with-apr=PATH],[Path to apr prefix or config script])], + [AS_HELP_STRING([--with-apr=PATH],[Path to apr prefix or config script])], [test_paths="${with_apr}"], [test_paths="/usr/local/libapr /usr/local/apr /usr/local /opt/libapr /opt/apr /opt /usr"]) diff --git a/build/find_apu.m4 b/build/find_apu.m4 index 4a5e6e5549..956a159cb7 100644 --- a/build/find_apu.m4 +++ b/build/find_apu.m4 @@ -18,7 +18,7 @@ AC_DEFUN([CHECK_APU], AC_ARG_WITH( apu, - [AC_HELP_STRING([--with-apu=PATH],[Path to apu prefix or config script])], + [AS_HELP_STRING([--with-apu=PATH],[Path to apu prefix or config script])], [test_paths="${with_apu}"], [test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local/apr /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr"]) diff --git a/build/find_curl.m4 b/build/find_curl.m4 index d868a30f03..1cee35bba2 100644 --- a/build/find_curl.m4 +++ b/build/find_curl.m4 @@ -18,7 +18,7 @@ AC_DEFUN([CHECK_CURL], AC_ARG_WITH( curl, - [AC_HELP_STRING([--with-curl=PATH],[Path to curl prefix or config script])], + [AS_HELP_STRING([--with-curl=PATH],[Path to curl prefix or config script])], [test_paths="${with_curl}"], [test_paths="/usr/local/libcurl /usr/local/curl /usr/local /opt/libcurl /opt/curl /opt /usr"]) diff --git a/build/find_lua.m4 b/build/find_lua.m4 index acb903e5fa..664bc3e3fa 100644 --- a/build/find_lua.m4 +++ b/build/find_lua.m4 @@ -21,7 +21,7 @@ LUA_SONAMES="so la sl dll dylib a" AC_ARG_WITH( lua, - [AC_HELP_STRING([--with-lua=PATH],[Path to lua prefix or config script])] + [AS_HELP_STRING([--with-lua=PATH],[Path to lua prefix or config script])] ,, with_lua=yes) AS_CASE(["${with_lua}"], diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index 2cff8f3ccb..bf297f67fc 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -17,7 +17,7 @@ AC_DEFUN([CHECK_PCRE], AC_ARG_WITH( pcre, - [AC_HELP_STRING([--with-pcre=PATH],[Path to pcre prefix or config script])], + [AS_HELP_STRING([--with-pcre=PATH],[Path to pcre prefix or config script])], [test_paths="${with_pcre}"], [test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr"]) diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 index 18c2e25807..f8786ce9f7 100644 --- a/build/find_pcre2.m4 +++ b/build/find_pcre2.m4 @@ -17,7 +17,7 @@ AC_DEFUN([CHECK_PCRE2], AC_ARG_WITH( pcre2, - [AC_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])], + [AS_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])], , with_pcre2=no) AS_CASE(["${with_pcre2}"], diff --git a/build/find_ssdeep.m4 b/build/find_ssdeep.m4 index 4b0c9aa970..08d3ef959b 100644 --- a/build/find_ssdeep.m4 +++ b/build/find_ssdeep.m4 @@ -13,7 +13,7 @@ SSDEEP_LDADD="" AC_ARG_WITH( ssdeep, - [AC_HELP_STRING([--with-ssdeep=PATH],[Path to ssdeep prefix])] + [AS_HELP_STRING([--with-ssdeep=PATH],[Path to ssdeep prefix])] ,, with_ssdeep=yes) AS_CASE(["${with_ssdeep}"], diff --git a/build/find_yajl.m4 b/build/find_yajl.m4 index 132a8a8a90..c3d4dcde7e 100644 --- a/build/find_yajl.m4 +++ b/build/find_yajl.m4 @@ -23,7 +23,7 @@ YAJL_SONAMES="so la sl dll dylib" AC_ARG_WITH( yajl, - [AC_HELP_STRING([--with-yajl=PATH],[Path to yajl prefix or config script])] + [AS_HELP_STRING([--with-yajl=PATH],[Path to yajl prefix or config script])] ,, with_yajl=yes) AS_CASE(["${with_yajl}"], diff --git a/configure.ac b/configure.ac index 7c11873c77..f1c39754ce 100644 --- a/configure.ac +++ b/configure.ac @@ -33,7 +33,7 @@ AC_PATH_PROGS(ENV_CMD, [env printenv], ) PKG_PROG_PKG_CONFIG # Checks for header files. -AC_HEADER_STDC +#AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) # Checks for typedefs, structures, and compiler characteristics. @@ -889,13 +889,13 @@ ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" ORIG_CPPFLAGS="$CPPFLAGS" CFLAGS="$CFLAGS $APR_CFLAGS" CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" -AC_TRY_COMPILE( - [#include <apr_crypto.h>], - [ +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <apr_crypto.h> ]], + [[ #if APU_HAVE_CRYPTO == 0 #error APR util was not compiled with crypto support. #endif - ], + ]])], [ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support]) MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO" ], From 1401ad9131b14ca042795758cb5522e3961442b7 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sun, 25 Feb 2024 20:34:50 +0100 Subject: [PATCH 377/477] Remove commented line --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index f1c39754ce..aac9d52dbc 100644 --- a/configure.ac +++ b/configure.ac @@ -33,7 +33,6 @@ AC_PATH_PROGS(ENV_CMD, [env printenv], ) PKG_PROG_PKG_CONFIG # Checks for header files. -#AC_HEADER_STDC AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) # Checks for typedefs, structures, and compiler characteristics. From 4f33f5b6560033bb0b3c275bc9602e6e60dd4d05 Mon Sep 17 00:00:00 2001 From: Thomas Wouters <twouters@users.noreply.github.com> Date: Fri, 1 Mar 2024 10:57:03 +0100 Subject: [PATCH 378/477] Fix possible segfault in collection_unpack When var->value_len somehow becomes 0, we risk wrapping around to 4294967295 due to it being an unsigned int. Fixes #3082 --- apache2/persist_dbm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index e4f8036f6f..79f99dcc44 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -59,7 +59,7 @@ static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob } blob_offset += 2; - if (blob_offset + var->name_len > blob_size) return NULL; + if (var->name_len < 1 || blob_offset + var->name_len > blob_size) return NULL; var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); blob_offset += var->name_len; var->name_len--; @@ -67,7 +67,7 @@ static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; blob_offset += 2; - if (blob_offset + var->value_len > blob_size) return NULL; + if (var->value_len < 1 || blob_offset + var->value_len > blob_size) return NULL; var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); blob_offset += var->value_len; var->value_len--; From 31bf935f743fb2617549a47f79349fa85dd67aa6 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Sun, 3 Mar 2024 16:20:07 +0100 Subject: [PATCH 379/477] Update CHANGES --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 517e76b74c..eb1b846c06 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Fix possible segfault in collection_unpack + [Issue #3072 - @twouters] * Set the minimum security protocol version for SecRemoteRules [Issue security/code-scanning/2 - @airween] * Allow lua version 5.4 From 538ffa6baa655c2c846d605889f695904d44f47e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 4 Apr 2024 15:45:55 +0200 Subject: [PATCH 380/477] Added some null pointer checks. Added a design doc. --- apache2/mod_security2.c | 11 ++--------- apache2/msc_json.c | 9 +++++++++ apache2/msc_multipart.c | 3 --- apache2/re.c | 6 +++--- design.md | 29 +++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 design.md diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 091aa0e040..0ee72865fc 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -867,10 +867,7 @@ static int hook_request_early(request_rec *r) { * create the initial configuration. */ msr = create_tx_context(r); - if (msr == NULL) { - msr_log(msr, 9, "Failed to create context after request failure."); - return DECLINED; - } + if (msr == NULL) return DECLINED; if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Context created after request failure."); } @@ -1165,11 +1162,7 @@ static void hook_error_log(const char *file, int line, int level, apr_status_t s #else msr = create_tx_context((request_rec*)r); #endif - if (msr == NULL) { - msr_log(msr, 9, "Failed to create context after request failure."); - return; - } - if (msr->txcfg->debuglog_level >= 9) { + if (msr && msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Context created after request failure."); } } diff --git a/apache2/msc_json.c b/apache2/msc_json.c index b42aa96a80..db0f9f025e 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -87,6 +87,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) static int yajl_map_key(void *ctx, const unsigned char *key, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *safe_key = (unsigned char *) NULL; /** @@ -118,6 +119,7 @@ static int yajl_map_key(void *ctx, const unsigned char *key, size_t length) static int yajl_null(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, "", 0); } @@ -128,6 +130,7 @@ static int yajl_null(void *ctx) static int yajl_boolean(void *ctx, int value) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); if (value) { return json_add_argument(msr, "true", strlen("true")); @@ -143,6 +146,7 @@ static int yajl_boolean(void *ctx, int value) static int yajl_string(void *ctx, const unsigned char *value, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, value, length); } @@ -155,12 +159,14 @@ static int yajl_string(void *ctx, const unsigned char *value, size_t length) static int yajl_number(void *ctx, const char *value, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); return json_add_argument(msr, value, length); } static int yajl_start_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); if (!msr->json->current_key && !msr->json->prefix) { msr->json->prefix = apr_pstrdup(msr->mp, "array"); @@ -190,6 +196,7 @@ static int yajl_start_array(void *ctx) { static int yajl_end_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *separator = (unsigned char *) NULL; /** @@ -226,6 +233,7 @@ static int yajl_end_array(void *ctx) { static int yajl_start_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); /** * If we do not have a current_key, this is a top-level hash, so we do not @@ -264,6 +272,7 @@ static int yajl_start_map(void *ctx) static int yajl_end_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; + assert(msr != NULL); unsigned char *separator = (unsigned char *) NULL; /** diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index e40136b4fd..7d56dd64e0 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -24,9 +24,6 @@ void validate_quotes(modsec_rec *msr, char *data, char quote) { assert(msr != NULL); int i, len; - if(msr == NULL) - return; - if(msr->mpd == NULL) return; diff --git a/apache2/re.c b/apache2/re.c index 77ea8ead16..816b911d18 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -215,11 +215,9 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; - if (mode == 0) { /* Looking for next rule. */ if (msre_ruleset_rule_matches_exception(rule, re)) { - - err = update_rule_target_ex(NULL, ruleset, rule, p2, p3); + err = update_rule_target_ex(msr, ruleset, rule, p2, p3); if (err) return err; if (rule->actionset->is_chained) mode = 2; /* Match all rules in this chain. */ } else { @@ -3141,6 +3139,8 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { /* Perform transformations. */ tarr = apr_table_elts(normtab); + /* if no transformation, multi_match makes no sense and breaks the logic */ + if (tarr->nelts == 0) multi_match = 0; /* Execute transformations in a loop. */ diff --git a/design.md b/design.md new file mode 100644 index 0000000000..a8e56e128e --- /dev/null +++ b/design.md @@ -0,0 +1,29 @@ +Design notes for source code +== +This file give some explanations and guidelines regarding ModSecurity v2 source code. +The goal is to discuss topics that are not related to a specific location in the code, so that cannot be best explained by comments. +The goal is not to replace comments where it is probably better. +It's quite short for the moment, but the goal is to extend it from time to time. + +## Null pointer check +The default behaviour is to check for null pointer dereference everywhere it may be needed. +In case a pointer cannot be null, it has to be explained with a comment at the beginning of the function of when dereferencing the pointer. +On top of that, an explicit check should be done when compiling in debug mode with the following code: +``` + assert(mypointer); +``` +In case a pointer that cannot be null is used at several locations (say more than 3 times), +the explanation could be given globally in this file. + +### Pointers never null +The following pointers can never be null: + +#### msr + +msr is assigned at the following places: +- mod_security2.c (14 x): initialization +In all the above calls, and all calling functions, it immediately returns (with an error code) in case msr is null, up to a place where no mod_security2 processing at all occurs. +In subsequent calls, there's thus no possibility to have msr null. +- apache2_io.c (2 x): assign a previously initialized msr +- msc_json (9 x): assign a previously initialized msr +- msc_lua.c (4 x): assign a previously initialized msr From 518b8ba6abc5011e5a4f56c8ae666d7fa7bc80d0 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 4 Apr 2024 16:01:51 +0200 Subject: [PATCH 381/477] more null pointer checks --- apache2/re.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 816b911d18..5999eb826b 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -48,6 +48,13 @@ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr); /* -- Actions, variables, functions and operator functions ----------------- */ +// Returns the rule id if existing, otherwise the file name & line number +static const char* id_log(msre_rule* rule) { + const char* id = rule->actionset->id; + if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + return id; +} + /** * \brief Remove rule targets to be processed * @@ -94,7 +101,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va if(targets != NULL) { if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, rule->actionset->id); + msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, id_log(rule)); } target = apr_strtok((char *)targets, ",", &savedptr); @@ -139,7 +146,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va } } else { if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", rule->actionset->id); + msr_log(msr, 9, "fetch_target_exception: No exception target found for rule id %s.", id_log(rule)); } } @@ -1583,7 +1590,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re saw_starter = 0; if (msr->txcfg->debuglog_level >= 9) { - msr_log(msr, 9, "Current rule is id=\"%s\" [chained %d] is trying to find the SecMarker=\"%s\" [stater %d]",rule->actionset->id,last_rule->actionset->is_chained,skip_after,saw_starter); + msr_log(msr, 9, "Current rule is id=\"%s\" [chained %d] is trying to find the SecMarker=\"%s\" [stater %d]", id_log(rule),last_rule->actionset->is_chained,skip_after,saw_starter); } } @@ -1740,7 +1747,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re msr_log(msr, 5, "Not processing %srule id=\"%s\": " "removed by ctl action", rule->actionset->is_chained ? "chained " : "", - rule->actionset->id); + id_log(rule)); } /* Skip the whole chain, if this is a chained rule */ @@ -1910,15 +1917,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else if (rc < 0) { - const char *id = ""; const char *msg = ""; - if (rule->actionset->id) { - id = rule->actionset->id; - } if (rule->actionset->msg) { msg = rule->actionset->msg; } - msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id, msg); + msr_log(msr, 1, "Rule processing failed (id=%s, msg=%s).", id_log(rule), msg); if (msr->txcfg->reqintercept_oe == 1) { apr_table_clear(msr->matched_vars); @@ -1948,15 +1951,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } else { - const char *id = ""; const char *msg = ""; - if (rule->actionset->id) { - id = rule->actionset->id; - } if (rule->actionset->msg) { msg = rule->actionset->msg; } - msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id, msg); + msr_log(msr, 1, "Rule processing failed with unknown return code: %d (id=%s, msg=%s).", rc, id_log(rule), msg); apr_table_clear(msr->matched_vars); return -1; } From 1014e479b7769cc2ee7a5606f705f6a2f9205519 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 5 Apr 2024 18:17:25 +0200 Subject: [PATCH 382/477] Added missing prototype --- apache2/msc_util.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apache2/msc_util.h b/apache2/msc_util.h index 373e23e214..1925a155f1 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -165,6 +165,8 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg); #endif +char DSOLOCAL *get_username(apr_pool_t* mp); + int read_line(char *buff, int size, FILE *fp); size_t msc_curl_write_memory_cb(void *contents, size_t size, From c8e1904da80600c08880a3180d4439e36f455aa7 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 5 Apr 2024 18:21:02 +0200 Subject: [PATCH 383/477] Missing function --- apache2/msc_util.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index c4d498417d..fd318a087a 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2850,3 +2850,14 @@ char* strtok_r( } #endif +// we cannot log an error message as this happens much too often +char* get_username(apr_pool_t* mp) { + char* username; + apr_uid_t uid; + apr_gid_t gid; + int rc = apr_uid_current(&uid, &gid, mp); + if (rc != APR_SUCCESS) return "apache"; + rc = apr_uid_name_get(&username, uid, mp); + if (rc != APR_SUCCESS) return "apache"; + return username; +} From 5f938536a0aa541eb3089877bdd4cfc2c84e4b5e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Mon, 8 Apr 2024 11:01:29 +0200 Subject: [PATCH 384/477] fixed a NULL check --- apache2/re.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache2/re.c b/apache2/re.c index 4b44f0f371..a7451f8fba 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -873,6 +873,7 @@ static msre_action_metadata *msre_resolve_action(msre_engine *engine, const char msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param, modsec_rec *msr, char **error_msg) { + // msr can be NULL const char *varparam = param; msre_var *var = apr_pcalloc(pool, sizeof(msre_var)); if (var == NULL) return NULL; @@ -953,7 +954,7 @@ msre_var *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char * static msre_var *msre_create_var(msre_ruleset *ruleset, const char *name, const char *param, modsec_rec *msr, char **error_msg) { - assert(msr != NULL); + // msr can be NULL assert(ruleset != NULL); assert(error_msg != NULL); msre_var *var = msre_create_var_ex(ruleset->mp, ruleset->engine, name, param, msr, error_msg); From a01b9b527e0e8b4a15f13798d224624e2bf1f684 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 10 Apr 2024 14:04:34 +0200 Subject: [PATCH 385/477] minor fixes --- apache2/apache2_config.c | 5 +++-- apache2/re.c | 8 ++++---- apache2/re.h | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 615d0c38e4..17f529ce20 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -32,8 +32,9 @@ // Returns the rule id if existing, otherwise the file name & line number static const char* id_log(msre_rule* rule) { - const char* id = rule->actionset->id; - if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + char* id = rule->actionset->id; + if (id == NOT_SET_P || !id || !*id) + id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; } diff --git a/apache2/re.c b/apache2/re.c index a7451f8fba..e775d546b6 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -168,7 +168,6 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va * \param p3 Pointer to configuration option REPLACED_TARGET */ char *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re, const char *p2, const char *p3) { - assert(msr != NULL); char *err; if(ruleset == NULL) @@ -210,7 +209,6 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, apr_array_header_t *phase_arr, const char *p2, const char *p3) { - assert(msr != NULL); assert(ruleset != NULL); msre_rule **rules; int i, j, mode; @@ -245,7 +243,6 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2, const char *p3) { - assert(msr != NULL); assert(ruleset != NULL); msre_var **targets = NULL; @@ -646,7 +643,10 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) { /** * Generate an action string from an actionset. */ -static char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { +#ifndef DEBUG_CONF +static +#endif +char *msre_actionset_generate_action_string(apr_pool_t *pool, const msre_actionset *actionset) { const apr_array_header_t *tarr = NULL; const apr_table_entry_t *telts = NULL; char *actions = NULL; diff --git a/apache2/re.h b/apache2/re.h index c0c5433965..db6c190455 100644 --- a/apache2/re.h +++ b/apache2/re.h @@ -75,6 +75,10 @@ int DSOLOCAL rule_id_in_range(int ruleid, const char *range); msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); +#ifdef DEBUG_CONF +char DSOLOCAL* msre_actionset_generate_action_string(apr_pool_t* pool, const msre_actionset* actionset); +#endif + #if defined(WITH_LUA) apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr, msre_rule *rule, apr_pool_t *mptmp); From bd435277a96af5436f5ccad57b97af1e3e3ec025 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Wed, 10 Apr 2024 17:10:03 +0200 Subject: [PATCH 386/477] Added --enable-assertions configure flag --- configure.ac | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index aac9d52dbc..1058d2623a 100644 --- a/configure.ac +++ b/configure.ac @@ -304,7 +304,20 @@ if test "$build_docs" -eq 1; then AC_CONFIG_FILES([doc/Makefile]) fi - +AC_ARG_ENABLE(assertions, + AS_HELP_STRING([--enable-assertions], + [Turn on assertions checks (undefine NDEBUG])), +[ + if test "${enableval}" = "yes"; then + assertions=-UNDEBUG + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" + else + assertions= + fi +]], +[ + assertions= +]) # Add PCRE Studying AC_ARG_ENABLE(pcre-study, @@ -827,7 +840,8 @@ else EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" fi fi - +EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" + MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" APXS_WRAPPER=build/apxs-wrapper @@ -905,7 +919,7 @@ AC_LINK_IFELSE( CFLAGS="$ORIG_CFLAGS" CPPFLAGS="$ORIG_CPPFLAGS" -# Current our unique download backend is curl, furhter we can support more. +# Currently our unique download backend is curl, further we can support more. if test ! -z "${CURL_VERSION}"; then AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" From 931c081ba6cba6fbdebafa9ffd055155b4832d98 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Thu, 11 Apr 2024 13:42:37 +0200 Subject: [PATCH 387/477] Enforcing -DNDEBUG (default normally) --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 1058d2623a..0b86132c45 100644 --- a/configure.ac +++ b/configure.ac @@ -312,11 +312,11 @@ AC_ARG_ENABLE(assertions, assertions=-UNDEBUG MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" else - assertions= + assertions=-DNDEBUG fi ]], [ - assertions= + assertions=-DNDEBUG ]) # Add PCRE Studying From 38d4b5c898cc1aea39a8bed74e225178378212a2 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 12 Apr 2024 16:28:45 +0200 Subject: [PATCH 388/477] typo --- configure.ac | 1930 +++++++++++++++++++++++++------------------------- 1 file changed, 965 insertions(+), 965 deletions(-) diff --git a/configure.ac b/configure.ac index 0b86132c45..3de3a53764 100644 --- a/configure.ac +++ b/configure.ac @@ -1,965 +1,965 @@ -dnl -dnl Autoconf configuration for ModSecurity -dnl -dnl Use ./autogen.sh to produce a configure script -dnl - -AC_PREREQ(2.63) - -AC_INIT([modsecurity], [2.9], [support@modsecurity.org]) - -AC_CONFIG_MACRO_DIR([build]) -AC_CONFIG_SRCDIR([LICENSE]) -AC_CONFIG_HEADERS([apache2/modsecurity_config_auto.h]) -AC_CONFIG_AUX_DIR([build]) -AC_PREFIX_DEFAULT([/usr/local/modsecurity]) - -AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) -m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) - -LT_PREREQ([2.2]) -LT_INIT([dlopen]) - -# Checks for programs. -AC_PROG_AWK -AC_PROG_CC -AC_PROG_CPP -AC_PROG_INSTALL -AC_PROG_LN_S -AC_PROG_MAKE_SET -AC_PROG_GREP -AC_PATH_PROGS(PERL, [perl perl5], ) -AC_PATH_PROGS(ENV_CMD, [env printenv], ) -PKG_PROG_PKG_CONFIG - -# Checks for header files. -AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_C_RESTRICT -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_STRUCT_TM -AC_TYPE_UINT8_T - -# Checks for library functions. -AC_FUNC_MALLOC -AC_FUNC_MEMCMP -AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol fchmod strcasestr]) - -# Some directories -MSC_BASE_DIR=`pwd` -MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." -MSC_TEST_DIR="$MSC_BASE_DIR/tests" -MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" -MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" -MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" -MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" -MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" - -AC_SUBST(MSC_BASE_DIR) -AC_SUBST(MSC_PKGBASE_DIR) -AC_SUBST(MSC_TEST_DIR) -AC_SUBST(MSC_REGRESSION_DIR) -AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR) -AC_SUBST(MSC_REGRESSION_CONF_DIR) -AC_SUBST(MSC_REGRESSION_LOGS_DIR) -AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) - -### Configure Options - -# Verbose output -AC_ARG_ENABLE(verbose-output, - AS_HELP_STRING([--enable-verbose-output], - [Enable more verbose configure output.]), -[ - if test "$enableval" != "no"; then - verbose_output=1 - else - verbose_output=0 - fi -], -[ - verbose_output=0 -]) - - -#OS type - -AC_CANONICAL_HOST -CANONICAL_HOST=$host - -AH_TEMPLATE([AIX], [Define if the operating system is AIX]) -AH_TEMPLATE([LINUX], [Define if the operating system is LINUX]) -AH_TEMPLATE([OPENBSD], [Define if the operating system is OpenBSD]) -AH_TEMPLATE([SOLARIS], [Define if the operating system is SOLARIS]) -AH_TEMPLATE([HPUX], [Define if the operating system is HPUX]) -AH_TEMPLATE([MACOSX], [Define if the operating system is Macintosh OSX]) -AH_TEMPLATE([FREEBSD], [Define if the operating system is FREEBSD]) -AH_TEMPLATE([NETBSD], [Define if the operating system is NetBSD]) - - -case $host in - *-*-aix*) - echo "Checking platform... Identified as AIX" - aixos=true - ;; - *-*-hpux*) - echo "Checking platform... Identified as HPUX" - hpuxos=true - ;; - *-*-darwin*) - echo "Checking platform... Identified as Macintosh OS X" - macos=true - ;; - *-*-linux*) - echo "Checking platform... Identified as Linux" - linuxos=true - case "${host_cpu}" in - s390x) - cpu_type="-DLINUX_S390" - ;; - esac - ;; - *-*-solaris*) - echo "Checking platform... Identified as Solaris" - solarisos=true - ;; - *-*-freebsd*) - echo "Checking platform... Identified as FreeBSD" - freebsdos=true - ;; - *-*-netbsd*) - echo "Checking platform... Identified as NetBSD" - netbsdos=true - ;; - *-*-openbsd*) - echo "Checking platform... Identified as OpenBSD" - openbsdos=true - ;; - *-*-kfreebsd*) - echo "Checking platform... Identified as kFreeBSD, treating as linux" - linuxos=true - ;; - *-*-gnu*.*) - echo "Checking platform... Identified as HURD, treating as linux" - linuxos=true - ;; - *) - echo "Unknown CANONICAL_HOST $host" - exit - ;; -esac - -AM_CONDITIONAL([AIX], [test x$aixos = xtrue]) -AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue]) -AM_CONDITIONAL([MACOSX], [test x$macos = xtrue]) -AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue]) -AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue]) -AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue]) -AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue]) -AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue]) -AM_CONDITIONAL([NETBSD], [test x$netbsdos = xtrue]) - -#Subdirs -TOPLEVEL_SUBDIRS="tools" - -# Apache2 Module -AC_ARG_ENABLE(apache2-module, - AS_HELP_STRING([--disable-apache2-module], - [Disable building Apache2 module.]), -[ - if test "$enableval" != "no"; then - build_apache2_module=1 - else - build_apache2_module=0 - fi -], -[ - build_apache2_module=1 -]) -AM_CONDITIONAL([BUILD_APACHE2_MODULE], [test "$build_apache2_module" -eq 1]) -if test "$build_apache2_module" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS apache2" -fi - - -# Standalone Module -AC_ARG_ENABLE(standalone-module, - AS_HELP_STRING([--enable-standalone-module], - [Enable building standalone module.]), -[ - if test "$enableval" != "no"; then - build_standalone_module=1 - else - build_standalone_module=0 - fi -], -[ - build_standalone_module=0 -]) -AM_CONDITIONAL([BUILD_STANDALONE_MODULE], [test "$build_standalone_module" -eq 1]) -if test "$build_standalone_module" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS standalone" -fi - - -# Extensions -AC_ARG_ENABLE(extentions, - AS_HELP_STRING([--enable-extentions], - [Enable building extension.]), -[ - if test "$enableval" != "no"; then - build_extentions=1 - else - build_extentions=0 - fi -], -[ - build_extentions=0 -]) -AM_CONDITIONAL([BUILD_extentions], [test "$build_extentions" -eq 1]) -if test "$build_extentions" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS ext" -fi - - -# Mlogc -AC_ARG_ENABLE(mlogc, - AS_HELP_STRING([--disable-mlogc], - [Disable building mlogc.]), -[ - if test "$enableval" != "no"; then - build_mlogc=1 - else - build_mlogc=0 - fi -], -[ - build_mlogc=1 -]) - -CHECK_CURL() - -if test -z "${CURL_VERSION}"; then - AC_MSG_NOTICE([NOTE: mlogc compilation was disabled.]) - build_mlogc=0 -fi - -AM_CONDITIONAL([BUILD_MLOGC], [test "$build_mlogc" -eq 1]) -if test "$build_mlogc" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS mlogc" -fi - -# Audit Log Parser v2 (ALP2) -AC_ARG_ENABLE(alp2, - AS_HELP_STRING([--enable-alp2], - [Enable building audit log parser lib.]), -[ - if test "$enableval" != "no"; then - build_alp2=1 - else - build_alp2=0 - fi -], -[ - build_alp2=0 -]) -AM_CONDITIONAL([BUILD_ALP2], [test "$build_alp2" -eq 1]) -if test "$build_alp2" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS alp2" -fi - -# Documentation -AC_ARG_ENABLE(docs, - AS_HELP_STRING([--enable-docs], - [Enable building documentation.]), -[ - if test "$enableval" != "no"; then - build_docs=1 - else - build_docs=0 - fi -], -[ - build_docs=0 -]) -AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1]) -if test "$build_docs" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS doc" - AC_CHECK_PROGS([DOXYGEN], [doxygen]) - if test -z "$DOXYGEN"; then - AC_MSG_WARN([Doxygen not found - continue without Doxygen support]) - fi - if test "$build_apache2_module" -eq 1; then - AC_CONFIG_FILES([doc/doxygen-apache]) - fi - if test "$build_standalone_module" -eq 1; then - AC_CONFIG_FILES([doc/doxygen-nginx]) - AC_CONFIG_FILES([doc/doxygen-iis]) - AC_CONFIG_FILES([doc/doxygen-standalone]) - fi - AC_CONFIG_FILES([doc/Makefile]) -fi - -AC_ARG_ENABLE(assertions, - AS_HELP_STRING([--enable-assertions], - [Turn on assertions checks (undefine NDEBUG])), -[ - if test "${enableval}" = "yes"; then - assertions=-UNDEBUG - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" - else - assertions=-DNDEBUG - fi -]], -[ - assertions=-DNDEBUG -]) -# Add PCRE Studying - -AC_ARG_ENABLE(pcre-study, - AS_HELP_STRING([--enable-pcre-study], - [Enable PCRE regex studying during configure.]), -[ - if test "$enableval" != "no"; then - pcre_study='-DWITH_PCRE_STUDY' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_study" - else - pcre_study='' - fi -], -[ - pcre_study='-DWITH_PCRE_STUDY' -]) - -# Add PCRE JIT - -AC_ARG_ENABLE(pcre-jit, - AS_HELP_STRING([--enable-pcre-jit], - [Enable PCRE regex jit support during configure.]), -[ - if test "$enableval" != "no"; then - pcre_jit='-DWITH_PCRE_JIT' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_jit" - else - pcre_jit='' - fi -], -[ - pcre_jit='' -]) - - -# Limit PCRE matching -AC_ARG_ENABLE(pcre-match-limit, - AS_HELP_STRING([--enable-pcre-match-limit], - [Enable PCRE regex match limit during configure.]), -[ - if test "$enableval" = "yes"; then - AC_MSG_ERROR([PCRE match limits require a numeric value]) - elif test "$enableval" = "no"; then - pcre_match_limit='' - else - pcre_match_limit="-DMODSEC_PCRE_MATCH_LIMIT=$enableval" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit" - fi -], -[ - pcre_match_limit='-DMODSEC_PCRE_MATCH_LIMIT=1500' -]) - -# Limit PCRE matching recursion -AC_ARG_ENABLE(pcre-match-limit-recursion, - AS_HELP_STRING([--enable-pcre-match-limit-recursion], - [Enable PCRE regex match limit recursion during configure.]), -[ - if test "$enableval" = "yes"; then - AC_MSG_ERROR([PCRE match limits require a numeric value]) - elif test "$enableval" = "no"; then - pcre_match_limit_recursion='' - else - pcre_match_limit_recursion="-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=$enableval" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit_recursion" - fi -], -[ - pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500' -]) - -# Enable Lua per transaction cache -AC_ARG_ENABLE(lua-cache, - AS_HELP_STRING([--enable-lua-cache], - [Enable Lua per transaction cache.]), -[ - if test "$enableval" != "no"; then - lua_cache="-DCACHE_LUA" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache" - else - lua_cache= - fi -], -[ - lua_cache= -]) - -# Enable phase-1 in post_read_request -AC_ARG_ENABLE(htaccess-config, - AS_HELP_STRING([--enable-htaccess-config], - [Enable some mod_security directives into htaccess files.]), -[ - if test "$enableval" != "no"; then - htaccess_config="-DHTACCESS_CONFIG" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $htaccess_config" - else - htaccess_config= - fi -], -[ - htaccess_config= -]) - -# Enable phase-1 in post_read_request -AC_ARG_ENABLE(request-early, - AS_HELP_STRING([--enable-request-early], - [Place phase1 into post_read_request hook. default is hook_request_early]), -[ - if test "$enableval" != "no"; then - request_early="-DREQUEST_EARLY" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early" - else - request_early= - fi -], -[ - request_early='-DREQUEST_EARLY' -]) - -# Enable duplicate rules id -AC_ARG_ENABLE(rule-id-validation, - AS_HELP_STRING([--enable-rule-id-validation], - [Forbid duplicate rule ids and missing ones. This is the default]), -[ - if test "$enableval" != "no"; then - unique_id= - else - unique_id="-DALLOW_ID_NOT_UNIQUE" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $unique_id" - fi -], -[ - unique_id='' -]) - -# Disable logging of filename -AC_ARG_ENABLE(filename-logging, - AS_HELP_STRING([--enable-filename-logging], - [Enable logging of filename in audit log. This is the default]), -[ - if test "$enableval" != "no"; then - log_filename= - else - log_filename="-DLOG_NO_FILENAME" - fi -], -[ - log_filename='' -]) - -# Disable logging of "Server" -AC_ARG_ENABLE(server-logging, - AS_HELP_STRING([--enable-server-logging], - [Enable logging of "Server" in audit log when log level < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_server= - else - log_server="-DLOG_NO_SERVER" - fi -], -[ - log_server='' -]) - -# Disable logging of problem when deleting collection -AC_ARG_ENABLE(collection-delete-problem-logging, - AS_HELP_STRING([--enable-collection-delete-problem-logging], - [Enable logging of collection delete problem even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_collection_delete_problem= - else - log_collection_delete_problem="-DLOG_NO_COLL_DELET_PB" - fi -], -[ - log_collection_delete_problem='' -]) - -# Disable logging of Apache handler -AC_ARG_ENABLE(handler-logging, - AS_HELP_STRING([--enable-handler-logging], - [Enable logging of Apache handler in audit log even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_handler= - else - log_handler="-DLOG_NO_HANDLER" - fi -], -[ - log_handler='' -]) - -# Disable logging of dechunking -AC_ARG_ENABLE(dechunk-logging, - AS_HELP_STRING([--enable-dechunk-logging], - [Enable logging of dechunking even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_dechunk= - else - log_dechunk="-DLOG_NO_DECHUNK" - fi -], -[ - log_dechunk='' -]) - -# Disable logging of stopwatches -AC_ARG_ENABLE(stopwatch-logging, - AS_HELP_STRING([--enable-stopwatch-logging], - [Enable logging of stopwatches even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_stopwatch= - else - log_stopwatch="-DLOG_NO_STOPWATCH" - fi -], -[ - log_stopwatch='' -]) - -# Disable logging of server context -AC_ARG_ENABLE(server-context-logging, - AS_HELP_STRING([--enable-server-context-logging], - [Enable logging of server info (log producer, sanitized objects, ...) in audit log even when log level < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_server_context= - else - log_server_context="-DLOG_NO_SERVER_CONTEXT" - fi -], -[ - log_server_context='' -]) - - -# Enable collection's global lock -AC_ARG_ENABLE(collection-global-lock, - AS_HELP_STRING([--enable-collection-global-lock], - [Enable collection correctness by using a global lock. May reduce performance significatively. This is disabled by default]), -[ - if test "$enableval" != "yes"; then - collection_global_lock="" - else - collection_global_lock="-DGLOBAL_COLLECTION_LOCK" - fi -], -[ - collection_global_lock='' -]) - - -# Ignore configure errors -AC_ARG_ENABLE(errors, - AS_HELP_STRING([--disable-errors], - [Disable errors during configure.]), -[ - if test "$enableval" != "no"; then - report_errors=1 - else - report_errors=0 - fi -], -[ - report_errors=1 -]) - - -# Strict Compile -AC_ARG_ENABLE(strict-compile, - AS_HELP_STRING([--enable-strict-compile], - [Enable strict compilation (warnings are errors).]), -[ - if test "$enableval" != "no"; then - strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $strict_compile" - else - strict_compile= - fi -], -[ - strict_compile= -]) - -# DEBUG_CONF -AC_ARG_ENABLE(debug-conf, - AS_HELP_STRING([--enable-debug-conf], - [Enable debug during configuration.]), -[ - if test "$enableval" != "no"; then - debug_conf="-DDEBUG_CONF" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_conf" - else - debug_conf= - fi -], -[ - debug_conf= -]) - -# CACHE_DEBUG -AC_ARG_ENABLE(debug-cache, - AS_HELP_STRING([--enable-debug-cache], - [Enable debug for transformation caching.]), -[ - if test "$enableval" != "no"; then - debug_cache="-DCACHE_DEBUG" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_cache" - else - debug_cache= - fi -], -[ - debug_cache= -]) - -# DEBUG_ACMP -AC_ARG_ENABLE(debug-acmp, - AS_HELP_STRING([--enable-debug-acmp], - [Enable debugging acmp code.]), -[ - if test "$enableval" != "no"; then - debug_acmp="-DDEBUG_ACMP" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_acmp" - else - debug_acmp= - fi -], -[ - debug_acmp= -]) - -# DEBUG_MEM -AC_ARG_ENABLE(debug-mem, - AS_HELP_STRING([--enable-debug-mem], - [Enable debug during configuration.]), -[ - if test "$enableval" != "no"; then - debug_mem="-DDEBUG_MEM" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_mem" - else - debug_mem= - fi -], -[ - debug_mem= -]) - -# PERFORMANCE_MEASUREMENT -AC_ARG_ENABLE(performance-measurement, - AS_HELP_STRING([--enable-performance-measurement], - [Enable performance-measurement stats.]), -[ - if test "$enableval" != "no"; then - perf_meas="-DPERFORMANCE_MEASUREMENT" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $perf_meas" - else - perf_meas= - fi -], -[ - perf_meas= -]) - -# NO_MODSEC_API -AC_ARG_ENABLE(modsec-api, - AS_HELP_STRING([--disable-modsec-api], - [Disable the API; compiling against some older Apache versions require this.]), -[ - if test "$enableval" != "yes"; then - modsec_api="-DNO_MODSEC_API" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $modsec_api" - else - modsec_api= - fi -], -[ - modsec_api= -]) - -# MSC_LARGE_STREAM_INPUT -AC_ARG_ENABLE(large-stream-input, - AS_HELP_STRING([--enable-large-stream-input], - [Enable optimization for large stream input]), -[ - if test "$enableval" = "yes"; then - large_stream_input="-DMSC_LARGE_STREAM_INPUT" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" - else - large_stream_input= - fi -], -[ - large_stream_input= -]) - -# Find apxs -AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) -AC_ARG_WITH(apxs, - [AS_HELP_STRING([[--with-apxs=FILE]], - [FILE is the path to apxs; defaults to "apxs".])], -[ - if test "$withval" = "yes"; then - APXS=apxs - else - APXS="$withval" - fi -]) - -if test -z "$APXS"; then - for i in /usr/local/apache22/bin \ - /usr/local/apache2/bin \ - /usr/local/apache/bin \ - /usr/local/sbin \ - /usr/local/bin \ - /usr/sbin \ - /usr/bin; - do - if test -f "$i/apxs2"; then - APXS="$i/apxs2" - break - elif test -f "$i/apxs"; then - APXS="$i/apxs" - break - fi - done -fi - -# arbitrarily picking the same version subversion looks for, don't know how -# accurate this really is, but at least it'll force us to have apache2... -HTTPD_WANTED_MMN=20020903 - -if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then - APXS_INCLUDE="`$APXS -q INCLUDEDIR`" - if test -r $APXS_INCLUDE/httpd.h; then - AC_MSG_NOTICE(found apxs at $APXS) - AC_MSG_NOTICE(checking httpd version) - AC_EGREP_CPP(VERSION_OK, - [ -#include "$APXS_INCLUDE/ap_mmn.h" -#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) -VERSION_OK -#endif], - [AC_MSG_NOTICE(httpd is recent enough)], - [ - if test "$report_errors" -eq 1; then - AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) - else - AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) - fi - ]) - fi - APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi - # Make sure the include dir is used - if test -n "$APXS_INCLUDEDIR"; then - APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" - else - APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi - APXS_CFLAGS=-I`$APXS -q INCLUDEDIR` - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi - APXS_LDFLAGS= - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi - APXS_LIBDIR="`$APXS -q LIBDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi - # Make sure the lib dir is used - if test -n "$APXS_LIBDIR"; then - APXS_LIBS="-L${APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" - else - APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi - APXS_LIBTOOL="`$APXS -q LIBTOOL`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi - APXS_CC="`$APXS -q CC`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi - APXS_BINDIR="`$APXS -q BINDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi - APXS_SBINDIR="`$APXS -q SBINDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi - APXS_PROGNAME="`$APXS -q PROGNAME`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi - APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" - if test "xx$APXS_LIBEXECDIR" = "xx"; then APXS_LIBEXECDIR="`$APXS -q LIBDIR`/modules"; fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi - APXS_MODULES=$APXS_LIBEXECDIR - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs MODULES: $APXS_MODULES); fi - if test "$APXS_SBINDIR" = "/"; then - APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" - else - APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi -else - if test "$report_errors" -eq 1; then - AC_MSG_ERROR(couldn't find APXS) - else - AC_MSG_NOTICE(couldn't find APXS) - fi -fi - -### Build *EXTRA_CFLAGS vars - -# Allow overriding EXTRA_CFLAGS -if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then - if test -z "$debug_mem"; then - EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" - fi -else - if test -n "$debug_mem"; then - EXTRA_CFLAGS="-O0 -g -Wall" - else - EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" - fi -fi -EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" - -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" - -APXS_WRAPPER=build/apxs-wrapper -APXS_EXTRA_CFLAGS="" -for f in $EXTRA_CFLAGS; do - APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" -done; -MODSEC_APXS_EXTRA_CFLAGS="" -for f in $MODSEC_EXTRA_CFLAGS; do - MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" -done; - -### Substitute the vars - -AC_SUBST(TOPLEVEL_SUBDIRS) -AC_SUBST(EXTRA_CFLAGS) -AC_SUBST(MODSEC_EXTRA_CFLAGS) -AC_SUBST(APXS) -AC_SUBST(APXS_WRAPPER) -AC_SUBST(APXS_INCLUDEDIR) -AC_SUBST(APXS_INCLUDES) -AC_SUBST(APXS_EXTRA_CFLAGS) -AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS) -AC_SUBST(APXS_LDFLAGS) -AC_SUBST(APXS_LIBS) -AC_SUBST(APXS_CFLAGS) -AC_SUBST(APXS_LIBTOOL) -AC_SUBST(APXS_CC) -AC_SUBST(APXS_LIBDIR) -AC_SUBST(APXS_BINDIR) -AC_SUBST(APXS_SBINDIR) -AC_SUBST(APXS_PROGNAME) -AC_SUBST(APXS_LIBEXECDIR) -AC_SUBST(APXS_MODULES) -AC_SUBST(APXS_HTTPD) - -CHECK_PCRE() -CHECK_PCRE2() -if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then -CHECK_APR() -CHECK_APU() -fi -CHECK_LIBXML2() -CHECK_LUA() -#if test "$build_mlogc" -ne 0; then -#CHECK_CURL() -#fi - -# Check for YAJL libs (for JSON body processor) -CHECK_YAJL() -#AC_SEARCH_LIBS([yajl_alloc], [yajl]) -CHECK_SSDEEP() -#AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy]) - -# Temporarily set cflags for apr_crypto check, then restore -# since it's already used correctly to compile modsecurity module. -ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" -ORIG_CPPFLAGS="$CPPFLAGS" -CFLAGS="$CFLAGS $APR_CFLAGS" -CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ #include <apr_crypto.h> ]], - [[ - #if APU_HAVE_CRYPTO == 0 - #error APR util was not compiled with crypto support. - #endif - ]])], - [ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support]) - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO" - ], - [ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ] -) -# Restore env vars so that we don't clutter with duplicates that -# are eventually appended later on -CFLAGS="$ORIG_CFLAGS" -CPPFLAGS="$ORIG_CPPFLAGS" - -# Currently our unique download backend is curl, further we can support more. -if test ! -z "${CURL_VERSION}"; then - AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" -fi - -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES([tools/Makefile]) -if test "$build_alp2" -ne 0; then -AC_CONFIG_FILES([alp2/Makefile]) -fi -if test "$build_apache2_module" -ne 0; then -AC_CONFIG_FILES([apache2/Makefile]) -fi -if test "$build_standalone_module" -ne 0; then -AC_CONFIG_FILES([standalone/Makefile]) -AC_CONFIG_FILES([nginx/modsecurity/config]) -fi -if test "$build_extentions" -ne 0; then -AC_CONFIG_FILES([ext/Makefile]) -fi -AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper]) -if test -e "$PERL"; then - if test "$build_mlogc" -ne 0; then - AC_CONFIG_FILES([mlogc/mlogc-batch-load.pl], [chmod +x mlogc/mlogc-batch-load.pl]) - AC_CONFIG_FILES([tests/regression/misc/40-secRemoteRules.t]) - AC_CONFIG_FILES([tests/regression/misc/50-ipmatchfromfile-external.t]) - AC_CONFIG_FILES([tests/regression/misc/60-pmfromfile-external.t]) - fi - AC_CONFIG_FILES([tests/run-unit-tests.pl], [chmod +x tests/run-unit-tests.pl]) - AC_CONFIG_FILES([tests/run-regression-tests.pl], [chmod +x tests/run-regression-tests.pl]) - AC_CONFIG_FILES([tests/gen_rx-pm.pl], [chmod +x tests/gen_rx-pm.pl]) - AC_CONFIG_FILES([tests/csv_rx-pm.pl], [chmod +x tests/csv_rx-pm.pl]) - AC_CONFIG_FILES([tests/regression/server_root/conf/httpd.conf]) - - # Perl based tools - AC_CONFIG_FILES([tools/rules-updater.pl], [chmod +x tools/rules-updater.pl]) -fi -if test "$build_mlogc" -ne 0; then - AC_CONFIG_FILES([mlogc/Makefile]) -fi -AC_CONFIG_FILES([tests/Makefile]) - -AC_OUTPUT +dnl +dnl Autoconf configuration for ModSecurity +dnl +dnl Use ./autogen.sh to produce a configure script +dnl + +AC_PREREQ(2.63) + +AC_INIT([modsecurity], [2.9], [support@modsecurity.org]) + +AC_CONFIG_MACRO_DIR([build]) +AC_CONFIG_SRCDIR([LICENSE]) +AC_CONFIG_HEADERS([apache2/modsecurity_config_auto.h]) +AC_CONFIG_AUX_DIR([build]) +AC_PREFIX_DEFAULT([/usr/local/modsecurity]) + +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +LT_PREREQ([2.2]) +LT_INIT([dlopen]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_GREP +AC_PATH_PROGS(PERL, [perl perl5], ) +AC_PATH_PROGS(ENV_CMD, [env printenv], ) +PKG_PROG_PKG_CONFIG + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_C_RESTRICT +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_TM +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol fchmod strcasestr]) + +# Some directories +MSC_BASE_DIR=`pwd` +MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." +MSC_TEST_DIR="$MSC_BASE_DIR/tests" +MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" +MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" +MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" +MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" +MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" + +AC_SUBST(MSC_BASE_DIR) +AC_SUBST(MSC_PKGBASE_DIR) +AC_SUBST(MSC_TEST_DIR) +AC_SUBST(MSC_REGRESSION_DIR) +AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR) +AC_SUBST(MSC_REGRESSION_CONF_DIR) +AC_SUBST(MSC_REGRESSION_LOGS_DIR) +AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) + +### Configure Options + +# Verbose output +AC_ARG_ENABLE(verbose-output, + AS_HELP_STRING([--enable-verbose-output], + [Enable more verbose configure output.]), +[ + if test "$enableval" != "no"; then + verbose_output=1 + else + verbose_output=0 + fi +], +[ + verbose_output=0 +]) + + +#OS type + +AC_CANONICAL_HOST +CANONICAL_HOST=$host + +AH_TEMPLATE([AIX], [Define if the operating system is AIX]) +AH_TEMPLATE([LINUX], [Define if the operating system is LINUX]) +AH_TEMPLATE([OPENBSD], [Define if the operating system is OpenBSD]) +AH_TEMPLATE([SOLARIS], [Define if the operating system is SOLARIS]) +AH_TEMPLATE([HPUX], [Define if the operating system is HPUX]) +AH_TEMPLATE([MACOSX], [Define if the operating system is Macintosh OSX]) +AH_TEMPLATE([FREEBSD], [Define if the operating system is FREEBSD]) +AH_TEMPLATE([NETBSD], [Define if the operating system is NetBSD]) + + +case $host in + *-*-aix*) + echo "Checking platform... Identified as AIX" + aixos=true + ;; + *-*-hpux*) + echo "Checking platform... Identified as HPUX" + hpuxos=true + ;; + *-*-darwin*) + echo "Checking platform... Identified as Macintosh OS X" + macos=true + ;; + *-*-linux*) + echo "Checking platform... Identified as Linux" + linuxos=true + case "${host_cpu}" in + s390x) + cpu_type="-DLINUX_S390" + ;; + esac + ;; + *-*-solaris*) + echo "Checking platform... Identified as Solaris" + solarisos=true + ;; + *-*-freebsd*) + echo "Checking platform... Identified as FreeBSD" + freebsdos=true + ;; + *-*-netbsd*) + echo "Checking platform... Identified as NetBSD" + netbsdos=true + ;; + *-*-openbsd*) + echo "Checking platform... Identified as OpenBSD" + openbsdos=true + ;; + *-*-kfreebsd*) + echo "Checking platform... Identified as kFreeBSD, treating as linux" + linuxos=true + ;; + *-*-gnu*.*) + echo "Checking platform... Identified as HURD, treating as linux" + linuxos=true + ;; + *) + echo "Unknown CANONICAL_HOST $host" + exit + ;; +esac + +AM_CONDITIONAL([AIX], [test x$aixos = xtrue]) +AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue]) +AM_CONDITIONAL([MACOSX], [test x$macos = xtrue]) +AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue]) +AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue]) +AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue]) +AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue]) +AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue]) +AM_CONDITIONAL([NETBSD], [test x$netbsdos = xtrue]) + +#Subdirs +TOPLEVEL_SUBDIRS="tools" + +# Apache2 Module +AC_ARG_ENABLE(apache2-module, + AS_HELP_STRING([--disable-apache2-module], + [Disable building Apache2 module.]), +[ + if test "$enableval" != "no"; then + build_apache2_module=1 + else + build_apache2_module=0 + fi +], +[ + build_apache2_module=1 +]) +AM_CONDITIONAL([BUILD_APACHE2_MODULE], [test "$build_apache2_module" -eq 1]) +if test "$build_apache2_module" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS apache2" +fi + + +# Standalone Module +AC_ARG_ENABLE(standalone-module, + AS_HELP_STRING([--enable-standalone-module], + [Enable building standalone module.]), +[ + if test "$enableval" != "no"; then + build_standalone_module=1 + else + build_standalone_module=0 + fi +], +[ + build_standalone_module=0 +]) +AM_CONDITIONAL([BUILD_STANDALONE_MODULE], [test "$build_standalone_module" -eq 1]) +if test "$build_standalone_module" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS standalone" +fi + + +# Extensions +AC_ARG_ENABLE(extentions, + AS_HELP_STRING([--enable-extentions], + [Enable building extension.]), +[ + if test "$enableval" != "no"; then + build_extentions=1 + else + build_extentions=0 + fi +], +[ + build_extentions=0 +]) +AM_CONDITIONAL([BUILD_extentions], [test "$build_extentions" -eq 1]) +if test "$build_extentions" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS ext" +fi + + +# Mlogc +AC_ARG_ENABLE(mlogc, + AS_HELP_STRING([--disable-mlogc], + [Disable building mlogc.]), +[ + if test "$enableval" != "no"; then + build_mlogc=1 + else + build_mlogc=0 + fi +], +[ + build_mlogc=1 +]) + +CHECK_CURL() + +if test -z "${CURL_VERSION}"; then + AC_MSG_NOTICE([NOTE: mlogc compilation was disabled.]) + build_mlogc=0 +fi + +AM_CONDITIONAL([BUILD_MLOGC], [test "$build_mlogc" -eq 1]) +if test "$build_mlogc" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS mlogc" +fi + +# Audit Log Parser v2 (ALP2) +AC_ARG_ENABLE(alp2, + AS_HELP_STRING([--enable-alp2], + [Enable building audit log parser lib.]), +[ + if test "$enableval" != "no"; then + build_alp2=1 + else + build_alp2=0 + fi +], +[ + build_alp2=0 +]) +AM_CONDITIONAL([BUILD_ALP2], [test "$build_alp2" -eq 1]) +if test "$build_alp2" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS alp2" +fi + +# Documentation +AC_ARG_ENABLE(docs, + AS_HELP_STRING([--enable-docs], + [Enable building documentation.]), +[ + if test "$enableval" != "no"; then + build_docs=1 + else + build_docs=0 + fi +], +[ + build_docs=0 +]) +AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1]) +if test "$build_docs" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS doc" + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + if test -z "$DOXYGEN"; then + AC_MSG_WARN([Doxygen not found - continue without Doxygen support]) + fi + if test "$build_apache2_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-apache]) + fi + if test "$build_standalone_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-nginx]) + AC_CONFIG_FILES([doc/doxygen-iis]) + AC_CONFIG_FILES([doc/doxygen-standalone]) + fi + AC_CONFIG_FILES([doc/Makefile]) +fi + +AC_ARG_ENABLE(assertions, + AS_HELP_STRING([--enable-assertions], + [Turn on assertions checks (undefine NDEBUG)]), +[ + if test "${enableval}" = "yes"; then + assertions=-UNDEBUG + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" + else + assertions=-DNDEBUG + fi +], +[ + assertions=-DNDEBUG +]) +# Add PCRE Studying + +AC_ARG_ENABLE(pcre-study, + AS_HELP_STRING([--enable-pcre-study], + [Enable PCRE regex studying during configure.]), +[ + if test "$enableval" != "no"; then + pcre_study='-DWITH_PCRE_STUDY' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_study" + else + pcre_study='' + fi +], +[ + pcre_study='-DWITH_PCRE_STUDY' +]) + +# Add PCRE JIT + +AC_ARG_ENABLE(pcre-jit, + AS_HELP_STRING([--enable-pcre-jit], + [Enable PCRE regex jit support during configure.]), +[ + if test "$enableval" != "no"; then + pcre_jit='-DWITH_PCRE_JIT' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_jit" + else + pcre_jit='' + fi +], +[ + pcre_jit='' +]) + + +# Limit PCRE matching +AC_ARG_ENABLE(pcre-match-limit, + AS_HELP_STRING([--enable-pcre-match-limit], + [Enable PCRE regex match limit during configure.]), +[ + if test "$enableval" = "yes"; then + AC_MSG_ERROR([PCRE match limits require a numeric value]) + elif test "$enableval" = "no"; then + pcre_match_limit='' + else + pcre_match_limit="-DMODSEC_PCRE_MATCH_LIMIT=$enableval" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit" + fi +], +[ + pcre_match_limit='-DMODSEC_PCRE_MATCH_LIMIT=1500' +]) + +# Limit PCRE matching recursion +AC_ARG_ENABLE(pcre-match-limit-recursion, + AS_HELP_STRING([--enable-pcre-match-limit-recursion], + [Enable PCRE regex match limit recursion during configure.]), +[ + if test "$enableval" = "yes"; then + AC_MSG_ERROR([PCRE match limits require a numeric value]) + elif test "$enableval" = "no"; then + pcre_match_limit_recursion='' + else + pcre_match_limit_recursion="-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=$enableval" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit_recursion" + fi +], +[ + pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500' +]) + +# Enable Lua per transaction cache +AC_ARG_ENABLE(lua-cache, + AS_HELP_STRING([--enable-lua-cache], + [Enable Lua per transaction cache.]), +[ + if test "$enableval" != "no"; then + lua_cache="-DCACHE_LUA" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache" + else + lua_cache= + fi +], +[ + lua_cache= +]) + +# Enable phase-1 in post_read_request +AC_ARG_ENABLE(htaccess-config, + AS_HELP_STRING([--enable-htaccess-config], + [Enable some mod_security directives into htaccess files.]), +[ + if test "$enableval" != "no"; then + htaccess_config="-DHTACCESS_CONFIG" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $htaccess_config" + else + htaccess_config= + fi +], +[ + htaccess_config= +]) + +# Enable phase-1 in post_read_request +AC_ARG_ENABLE(request-early, + AS_HELP_STRING([--enable-request-early], + [Place phase1 into post_read_request hook. default is hook_request_early]), +[ + if test "$enableval" != "no"; then + request_early="-DREQUEST_EARLY" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early" + else + request_early= + fi +], +[ + request_early='-DREQUEST_EARLY' +]) + +# Enable duplicate rules id +AC_ARG_ENABLE(rule-id-validation, + AS_HELP_STRING([--enable-rule-id-validation], + [Forbid duplicate rule ids and missing ones. This is the default]), +[ + if test "$enableval" != "no"; then + unique_id= + else + unique_id="-DALLOW_ID_NOT_UNIQUE" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $unique_id" + fi +], +[ + unique_id='' +]) + +# Disable logging of filename +AC_ARG_ENABLE(filename-logging, + AS_HELP_STRING([--enable-filename-logging], + [Enable logging of filename in audit log. This is the default]), +[ + if test "$enableval" != "no"; then + log_filename= + else + log_filename="-DLOG_NO_FILENAME" + fi +], +[ + log_filename='' +]) + +# Disable logging of "Server" +AC_ARG_ENABLE(server-logging, + AS_HELP_STRING([--enable-server-logging], + [Enable logging of "Server" in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server= + else + log_server="-DLOG_NO_SERVER" + fi +], +[ + log_server='' +]) + +# Disable logging of problem when deleting collection +AC_ARG_ENABLE(collection-delete-problem-logging, + AS_HELP_STRING([--enable-collection-delete-problem-logging], + [Enable logging of collection delete problem even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_collection_delete_problem= + else + log_collection_delete_problem="-DLOG_NO_COLL_DELET_PB" + fi +], +[ + log_collection_delete_problem='' +]) + +# Disable logging of Apache handler +AC_ARG_ENABLE(handler-logging, + AS_HELP_STRING([--enable-handler-logging], + [Enable logging of Apache handler in audit log even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_handler= + else + log_handler="-DLOG_NO_HANDLER" + fi +], +[ + log_handler='' +]) + +# Disable logging of dechunking +AC_ARG_ENABLE(dechunk-logging, + AS_HELP_STRING([--enable-dechunk-logging], + [Enable logging of dechunking even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_dechunk= + else + log_dechunk="-DLOG_NO_DECHUNK" + fi +], +[ + log_dechunk='' +]) + +# Disable logging of stopwatches +AC_ARG_ENABLE(stopwatch-logging, + AS_HELP_STRING([--enable-stopwatch-logging], + [Enable logging of stopwatches even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_stopwatch= + else + log_stopwatch="-DLOG_NO_STOPWATCH" + fi +], +[ + log_stopwatch='' +]) + +# Disable logging of server context +AC_ARG_ENABLE(server-context-logging, + AS_HELP_STRING([--enable-server-context-logging], + [Enable logging of server info (log producer, sanitized objects, ...) in audit log even when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server_context= + else + log_server_context="-DLOG_NO_SERVER_CONTEXT" + fi +], +[ + log_server_context='' +]) + + +# Enable collection's global lock +AC_ARG_ENABLE(collection-global-lock, + AS_HELP_STRING([--enable-collection-global-lock], + [Enable collection correctness by using a global lock. May reduce performance significatively. This is disabled by default]), +[ + if test "$enableval" != "yes"; then + collection_global_lock="" + else + collection_global_lock="-DGLOBAL_COLLECTION_LOCK" + fi +], +[ + collection_global_lock='' +]) + + +# Ignore configure errors +AC_ARG_ENABLE(errors, + AS_HELP_STRING([--disable-errors], + [Disable errors during configure.]), +[ + if test "$enableval" != "no"; then + report_errors=1 + else + report_errors=0 + fi +], +[ + report_errors=1 +]) + + +# Strict Compile +AC_ARG_ENABLE(strict-compile, + AS_HELP_STRING([--enable-strict-compile], + [Enable strict compilation (warnings are errors).]), +[ + if test "$enableval" != "no"; then + strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $strict_compile" + else + strict_compile= + fi +], +[ + strict_compile= +]) + +# DEBUG_CONF +AC_ARG_ENABLE(debug-conf, + AS_HELP_STRING([--enable-debug-conf], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_conf="-DDEBUG_CONF" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_conf" + else + debug_conf= + fi +], +[ + debug_conf= +]) + +# CACHE_DEBUG +AC_ARG_ENABLE(debug-cache, + AS_HELP_STRING([--enable-debug-cache], + [Enable debug for transformation caching.]), +[ + if test "$enableval" != "no"; then + debug_cache="-DCACHE_DEBUG" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_cache" + else + debug_cache= + fi +], +[ + debug_cache= +]) + +# DEBUG_ACMP +AC_ARG_ENABLE(debug-acmp, + AS_HELP_STRING([--enable-debug-acmp], + [Enable debugging acmp code.]), +[ + if test "$enableval" != "no"; then + debug_acmp="-DDEBUG_ACMP" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_acmp" + else + debug_acmp= + fi +], +[ + debug_acmp= +]) + +# DEBUG_MEM +AC_ARG_ENABLE(debug-mem, + AS_HELP_STRING([--enable-debug-mem], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_mem="-DDEBUG_MEM" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_mem" + else + debug_mem= + fi +], +[ + debug_mem= +]) + +# PERFORMANCE_MEASUREMENT +AC_ARG_ENABLE(performance-measurement, + AS_HELP_STRING([--enable-performance-measurement], + [Enable performance-measurement stats.]), +[ + if test "$enableval" != "no"; then + perf_meas="-DPERFORMANCE_MEASUREMENT" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $perf_meas" + else + perf_meas= + fi +], +[ + perf_meas= +]) + +# NO_MODSEC_API +AC_ARG_ENABLE(modsec-api, + AS_HELP_STRING([--disable-modsec-api], + [Disable the API; compiling against some older Apache versions require this.]), +[ + if test "$enableval" != "yes"; then + modsec_api="-DNO_MODSEC_API" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $modsec_api" + else + modsec_api= + fi +], +[ + modsec_api= +]) + +# MSC_LARGE_STREAM_INPUT +AC_ARG_ENABLE(large-stream-input, + AS_HELP_STRING([--enable-large-stream-input], + [Enable optimization for large stream input]), +[ + if test "$enableval" = "yes"; then + large_stream_input="-DMSC_LARGE_STREAM_INPUT" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" + else + large_stream_input= + fi +], +[ + large_stream_input= +]) + +# Find apxs +AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) +AC_ARG_WITH(apxs, + [AS_HELP_STRING([[--with-apxs=FILE]], + [FILE is the path to apxs; defaults to "apxs".])], +[ + if test "$withval" = "yes"; then + APXS=apxs + else + APXS="$withval" + fi +]) + +if test -z "$APXS"; then + for i in /usr/local/apache22/bin \ + /usr/local/apache2/bin \ + /usr/local/apache/bin \ + /usr/local/sbin \ + /usr/local/bin \ + /usr/sbin \ + /usr/bin; + do + if test -f "$i/apxs2"; then + APXS="$i/apxs2" + break + elif test -f "$i/apxs"; then + APXS="$i/apxs" + break + fi + done +fi + +# arbitrarily picking the same version subversion looks for, don't know how +# accurate this really is, but at least it'll force us to have apache2... +HTTPD_WANTED_MMN=20020903 + +if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then + APXS_INCLUDE="`$APXS -q INCLUDEDIR`" + if test -r $APXS_INCLUDE/httpd.h; then + AC_MSG_NOTICE(found apxs at $APXS) + AC_MSG_NOTICE(checking httpd version) + AC_EGREP_CPP(VERSION_OK, + [ +#include "$APXS_INCLUDE/ap_mmn.h" +#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) +VERSION_OK +#endif], + [AC_MSG_NOTICE(httpd is recent enough)], + [ + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + else + AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + fi + ]) +ÿ�fi + APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi + # Make sure the include dir is used + if test -n "$APXS_INCLUDEDIR"; then + APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + else + APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi + APXS_CFLAGS=-I`$APXS -q INCLUDEDIR` + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi + APXS_LDFLAGS= + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi + APXS_LIBDIR="`$APXS -q LIBDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi + # Make sure the lib dir is used + if test -n "$APXS_LIBDIR"; then + APXS_LIBS="-L${APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + else + APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi + APXS_LIBTOOL="`$APXS -q LIBTOOL`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi + APXS_CC="`$APXS -q CC`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi + APXS_BINDIR="`$APXS -q BINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi + APXS_SBINDIR="`$APXS -q SBINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi + APXS_PROGNAME="`$APXS -q PROGNAME`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi + APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" + if test "xx$APXS_LIBEXECDIR" = "xx"; then APXS_LIBEXECDIR="`$APXS -q LIBDIR`/modules"; fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi + APXS_MODULES=$APXS_LIBEXECDIR + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs MODULES: $APXS_MODULES); fi + if test "$APXS_SBINDIR" = "/"; then + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + else + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi +else + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(couldn't find APXS) + else + AC_MSG_NOTICE(couldn't find APXS) + fi +fi + +### Build *EXTRA_CFLAGS vars + +# Allow overriding EXTRA_CFLAGS +if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then + if test -z "$debug_mem"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" + fi +else + if test -n "$debug_mem"; then + EXTRA_CFLAGS="-O0 -g -Wall" + else + EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" + fi +fi +EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" + +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" + +APXS_WRAPPER=build/apxs-wrapper +APXS_EXTRA_CFLAGS="" +for f in $EXTRA_CFLAGS; do + APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" +done; +MODSEC_APXS_EXTRA_CFLAGS="" +for f in $MODSEC_EXTRA_CFLAGS; do + MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" +done; + +### Substitute the vars + +AC_SUBST(TOPLEVEL_SUBDIRS) +AC_SUBST(EXTRA_CFLAGS) +AC_SUBST(MODSEC_EXTRA_CFLAGS) +AC_SUBST(APXS) +AC_SUBST(APXS_WRAPPER) +AC_SUBST(APXS_INCLUDEDIR) +AC_SUBST(APXS_INCLUDES) +AC_SUBST(APXS_EXTRA_CFLAGS) +AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS) +AC_SUBST(APXS_LDFLAGS) +AC_SUBST(APXS_LIBS) +AC_SUBST(APXS_CFLAGS) +AC_SUBST(APXS_LIBTOOL) +AC_SUBST(APXS_CC) +AC_SUBST(APXS_LIBDIR) +AC_SUBST(APXS_BINDIR) +AC_SUBST(APXS_SBINDIR) +AC_SUBST(APXS_PROGNAME) +AC_SUBST(APXS_LIBEXECDIR) +AC_SUBST(APXS_MODULES) +AC_SUBST(APXS_HTTPD) + +CHECK_PCRE() +CHECK_PCRE2() +if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then +CHECK_APR() +CHECK_APU() +fi +CHECK_LIBXML2() +CHECK_LUA() +#if test "$build_mlogc" -ne 0; then +#CHECK_CURL() +#fi + +# Check for YAJL libs (for JSON body processor) +CHECK_YAJL() +#AC_SEARCH_LIBS([yajl_alloc], [yajl]) +CHECK_SSDEEP() +#AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy]) + +# Temporarily set cflags for apr_crypto check, then restore +# since it's already used correctly to compile modsecurity module. +ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" +ORIG_CPPFLAGS="$CPPFLAGS" +CFLAGS="$CFLAGS $APR_CFLAGS" +CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <apr_crypto.h> ]], + [[ + #if APU_HAVE_CRYPTO == 0 + #error APR util was not compiled with crypto support. + #endif + ]])], + [ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support]) + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO" + ], + [ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ] +) +# Restore env vars so that we don't clutter with duplicates that +# are eventually appended later on +CFLAGS="$ORIG_CFLAGS" +CPPFLAGS="$ORIG_CPPFLAGS" + +# Currently our unique download backend is curl, further we can support more. +if test ! -z "${CURL_VERSION}"; then + AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" +fi + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([tools/Makefile]) +if test "$build_alp2" -ne 0; then +AC_CONFIG_FILES([alp2/Makefile]) +fi +if test "$build_apache2_module" -ne 0; then +AC_CONFIG_FILES([apache2/Makefile]) +fi +if test "$build_standalone_module" -ne 0; then +AC_CONFIG_FILES([standalone/Makefile]) +AC_CONFIG_FILES([nginx/modsecurity/config]) +fi +if test "$build_extentions" -ne 0; then +AC_CONFIG_FILES([ext/Makefile]) +fi +AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper]) +if test -e "$PERL"; then + if test "$build_mlogc" -ne 0; then + AC_CONFIG_FILES([mlogc/mlogc-batch-load.pl], [chmod +x mlogc/mlogc-batch-load.pl]) + AC_CONFIG_FILES([tests/regression/misc/40-secRemoteRules.t]) + AC_CONFIG_FILES([tests/regression/misc/50-ipmatchfromfile-external.t]) + AC_CONFIG_FILES([tests/regression/misc/60-pmfromfile-external.t]) + fi + AC_CONFIG_FILES([tests/run-unit-tests.pl], [chmod +x tests/run-unit-tests.pl]) + AC_CONFIG_FILES([tests/run-regression-tests.pl], [chmod +x tests/run-regression-tests.pl]) + AC_CONFIG_FILES([tests/gen_rx-pm.pl], [chmod +x tests/gen_rx-pm.pl]) + AC_CONFIG_FILES([tests/csv_rx-pm.pl], [chmod +x tests/csv_rx-pm.pl]) + AC_CONFIG_FILES([tests/regression/server_root/conf/httpd.conf]) + + # Perl based tools + AC_CONFIG_FILES([tools/rules-updater.pl], [chmod +x tools/rules-updater.pl]) +fi +if test "$build_mlogc" -ne 0; then + AC_CONFIG_FILES([mlogc/Makefile]) +fi +AC_CONFIG_FILES([tests/Makefile]) + +AC_OUTPUT From 556835c6fe04c8691f90de7564da3573480fe7b2 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 12 Apr 2024 18:04:16 +0200 Subject: [PATCH 389/477] Fixed corrupted character --- configure.ac | 1934 +++++++++++++++++++++++++------------------------- 1 file changed, 969 insertions(+), 965 deletions(-) diff --git a/configure.ac b/configure.ac index 3de3a53764..24a3dba7ef 100644 --- a/configure.ac +++ b/configure.ac @@ -1,965 +1,969 @@ -dnl -dnl Autoconf configuration for ModSecurity -dnl -dnl Use ./autogen.sh to produce a configure script -dnl - -AC_PREREQ(2.63) - -AC_INIT([modsecurity], [2.9], [support@modsecurity.org]) - -AC_CONFIG_MACRO_DIR([build]) -AC_CONFIG_SRCDIR([LICENSE]) -AC_CONFIG_HEADERS([apache2/modsecurity_config_auto.h]) -AC_CONFIG_AUX_DIR([build]) -AC_PREFIX_DEFAULT([/usr/local/modsecurity]) - -AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) -m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) - -LT_PREREQ([2.2]) -LT_INIT([dlopen]) - -# Checks for programs. -AC_PROG_AWK -AC_PROG_CC -AC_PROG_CPP -AC_PROG_INSTALL -AC_PROG_LN_S -AC_PROG_MAKE_SET -AC_PROG_GREP -AC_PATH_PROGS(PERL, [perl perl5], ) -AC_PATH_PROGS(ENV_CMD, [env printenv], ) -PKG_PROG_PKG_CONFIG - -# Checks for header files. -AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_C_RESTRICT -AC_TYPE_PID_T -AC_TYPE_SIZE_T -AC_STRUCT_TM -AC_TYPE_UINT8_T - -# Checks for library functions. -AC_FUNC_MALLOC -AC_FUNC_MEMCMP -AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol fchmod strcasestr]) - -# Some directories -MSC_BASE_DIR=`pwd` -MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." -MSC_TEST_DIR="$MSC_BASE_DIR/tests" -MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" -MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" -MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" -MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" -MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" - -AC_SUBST(MSC_BASE_DIR) -AC_SUBST(MSC_PKGBASE_DIR) -AC_SUBST(MSC_TEST_DIR) -AC_SUBST(MSC_REGRESSION_DIR) -AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR) -AC_SUBST(MSC_REGRESSION_CONF_DIR) -AC_SUBST(MSC_REGRESSION_LOGS_DIR) -AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) - -### Configure Options - -# Verbose output -AC_ARG_ENABLE(verbose-output, - AS_HELP_STRING([--enable-verbose-output], - [Enable more verbose configure output.]), -[ - if test "$enableval" != "no"; then - verbose_output=1 - else - verbose_output=0 - fi -], -[ - verbose_output=0 -]) - - -#OS type - -AC_CANONICAL_HOST -CANONICAL_HOST=$host - -AH_TEMPLATE([AIX], [Define if the operating system is AIX]) -AH_TEMPLATE([LINUX], [Define if the operating system is LINUX]) -AH_TEMPLATE([OPENBSD], [Define if the operating system is OpenBSD]) -AH_TEMPLATE([SOLARIS], [Define if the operating system is SOLARIS]) -AH_TEMPLATE([HPUX], [Define if the operating system is HPUX]) -AH_TEMPLATE([MACOSX], [Define if the operating system is Macintosh OSX]) -AH_TEMPLATE([FREEBSD], [Define if the operating system is FREEBSD]) -AH_TEMPLATE([NETBSD], [Define if the operating system is NetBSD]) - - -case $host in - *-*-aix*) - echo "Checking platform... Identified as AIX" - aixos=true - ;; - *-*-hpux*) - echo "Checking platform... Identified as HPUX" - hpuxos=true - ;; - *-*-darwin*) - echo "Checking platform... Identified as Macintosh OS X" - macos=true - ;; - *-*-linux*) - echo "Checking platform... Identified as Linux" - linuxos=true - case "${host_cpu}" in - s390x) - cpu_type="-DLINUX_S390" - ;; - esac - ;; - *-*-solaris*) - echo "Checking platform... Identified as Solaris" - solarisos=true - ;; - *-*-freebsd*) - echo "Checking platform... Identified as FreeBSD" - freebsdos=true - ;; - *-*-netbsd*) - echo "Checking platform... Identified as NetBSD" - netbsdos=true - ;; - *-*-openbsd*) - echo "Checking platform... Identified as OpenBSD" - openbsdos=true - ;; - *-*-kfreebsd*) - echo "Checking platform... Identified as kFreeBSD, treating as linux" - linuxos=true - ;; - *-*-gnu*.*) - echo "Checking platform... Identified as HURD, treating as linux" - linuxos=true - ;; - *) - echo "Unknown CANONICAL_HOST $host" - exit - ;; -esac - -AM_CONDITIONAL([AIX], [test x$aixos = xtrue]) -AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue]) -AM_CONDITIONAL([MACOSX], [test x$macos = xtrue]) -AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue]) -AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue]) -AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue]) -AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue]) -AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue]) -AM_CONDITIONAL([NETBSD], [test x$netbsdos = xtrue]) - -#Subdirs -TOPLEVEL_SUBDIRS="tools" - -# Apache2 Module -AC_ARG_ENABLE(apache2-module, - AS_HELP_STRING([--disable-apache2-module], - [Disable building Apache2 module.]), -[ - if test "$enableval" != "no"; then - build_apache2_module=1 - else - build_apache2_module=0 - fi -], -[ - build_apache2_module=1 -]) -AM_CONDITIONAL([BUILD_APACHE2_MODULE], [test "$build_apache2_module" -eq 1]) -if test "$build_apache2_module" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS apache2" -fi - - -# Standalone Module -AC_ARG_ENABLE(standalone-module, - AS_HELP_STRING([--enable-standalone-module], - [Enable building standalone module.]), -[ - if test "$enableval" != "no"; then - build_standalone_module=1 - else - build_standalone_module=0 - fi -], -[ - build_standalone_module=0 -]) -AM_CONDITIONAL([BUILD_STANDALONE_MODULE], [test "$build_standalone_module" -eq 1]) -if test "$build_standalone_module" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS standalone" -fi - - -# Extensions -AC_ARG_ENABLE(extentions, - AS_HELP_STRING([--enable-extentions], - [Enable building extension.]), -[ - if test "$enableval" != "no"; then - build_extentions=1 - else - build_extentions=0 - fi -], -[ - build_extentions=0 -]) -AM_CONDITIONAL([BUILD_extentions], [test "$build_extentions" -eq 1]) -if test "$build_extentions" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS ext" -fi - - -# Mlogc -AC_ARG_ENABLE(mlogc, - AS_HELP_STRING([--disable-mlogc], - [Disable building mlogc.]), -[ - if test "$enableval" != "no"; then - build_mlogc=1 - else - build_mlogc=0 - fi -], -[ - build_mlogc=1 -]) - -CHECK_CURL() - -if test -z "${CURL_VERSION}"; then - AC_MSG_NOTICE([NOTE: mlogc compilation was disabled.]) - build_mlogc=0 -fi - -AM_CONDITIONAL([BUILD_MLOGC], [test "$build_mlogc" -eq 1]) -if test "$build_mlogc" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS mlogc" -fi - -# Audit Log Parser v2 (ALP2) -AC_ARG_ENABLE(alp2, - AS_HELP_STRING([--enable-alp2], - [Enable building audit log parser lib.]), -[ - if test "$enableval" != "no"; then - build_alp2=1 - else - build_alp2=0 - fi -], -[ - build_alp2=0 -]) -AM_CONDITIONAL([BUILD_ALP2], [test "$build_alp2" -eq 1]) -if test "$build_alp2" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS alp2" -fi - -# Documentation -AC_ARG_ENABLE(docs, - AS_HELP_STRING([--enable-docs], - [Enable building documentation.]), -[ - if test "$enableval" != "no"; then - build_docs=1 - else - build_docs=0 - fi -], -[ - build_docs=0 -]) -AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1]) -if test "$build_docs" -eq 1; then - TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS doc" - AC_CHECK_PROGS([DOXYGEN], [doxygen]) - if test -z "$DOXYGEN"; then - AC_MSG_WARN([Doxygen not found - continue without Doxygen support]) - fi - if test "$build_apache2_module" -eq 1; then - AC_CONFIG_FILES([doc/doxygen-apache]) - fi - if test "$build_standalone_module" -eq 1; then - AC_CONFIG_FILES([doc/doxygen-nginx]) - AC_CONFIG_FILES([doc/doxygen-iis]) - AC_CONFIG_FILES([doc/doxygen-standalone]) - fi - AC_CONFIG_FILES([doc/Makefile]) -fi - -AC_ARG_ENABLE(assertions, - AS_HELP_STRING([--enable-assertions], - [Turn on assertions checks (undefine NDEBUG)]), -[ - if test "${enableval}" = "yes"; then - assertions=-UNDEBUG - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" - else - assertions=-DNDEBUG - fi -], -[ - assertions=-DNDEBUG -]) -# Add PCRE Studying - -AC_ARG_ENABLE(pcre-study, - AS_HELP_STRING([--enable-pcre-study], - [Enable PCRE regex studying during configure.]), -[ - if test "$enableval" != "no"; then - pcre_study='-DWITH_PCRE_STUDY' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_study" - else - pcre_study='' - fi -], -[ - pcre_study='-DWITH_PCRE_STUDY' -]) - -# Add PCRE JIT - -AC_ARG_ENABLE(pcre-jit, - AS_HELP_STRING([--enable-pcre-jit], - [Enable PCRE regex jit support during configure.]), -[ - if test "$enableval" != "no"; then - pcre_jit='-DWITH_PCRE_JIT' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_jit" - else - pcre_jit='' - fi -], -[ - pcre_jit='' -]) - - -# Limit PCRE matching -AC_ARG_ENABLE(pcre-match-limit, - AS_HELP_STRING([--enable-pcre-match-limit], - [Enable PCRE regex match limit during configure.]), -[ - if test "$enableval" = "yes"; then - AC_MSG_ERROR([PCRE match limits require a numeric value]) - elif test "$enableval" = "no"; then - pcre_match_limit='' - else - pcre_match_limit="-DMODSEC_PCRE_MATCH_LIMIT=$enableval" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit" - fi -], -[ - pcre_match_limit='-DMODSEC_PCRE_MATCH_LIMIT=1500' -]) - -# Limit PCRE matching recursion -AC_ARG_ENABLE(pcre-match-limit-recursion, - AS_HELP_STRING([--enable-pcre-match-limit-recursion], - [Enable PCRE regex match limit recursion during configure.]), -[ - if test "$enableval" = "yes"; then - AC_MSG_ERROR([PCRE match limits require a numeric value]) - elif test "$enableval" = "no"; then - pcre_match_limit_recursion='' - else - pcre_match_limit_recursion="-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=$enableval" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit_recursion" - fi -], -[ - pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500' -]) - -# Enable Lua per transaction cache -AC_ARG_ENABLE(lua-cache, - AS_HELP_STRING([--enable-lua-cache], - [Enable Lua per transaction cache.]), -[ - if test "$enableval" != "no"; then - lua_cache="-DCACHE_LUA" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache" - else - lua_cache= - fi -], -[ - lua_cache= -]) - -# Enable phase-1 in post_read_request -AC_ARG_ENABLE(htaccess-config, - AS_HELP_STRING([--enable-htaccess-config], - [Enable some mod_security directives into htaccess files.]), -[ - if test "$enableval" != "no"; then - htaccess_config="-DHTACCESS_CONFIG" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $htaccess_config" - else - htaccess_config= - fi -], -[ - htaccess_config= -]) - -# Enable phase-1 in post_read_request -AC_ARG_ENABLE(request-early, - AS_HELP_STRING([--enable-request-early], - [Place phase1 into post_read_request hook. default is hook_request_early]), -[ - if test "$enableval" != "no"; then - request_early="-DREQUEST_EARLY" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early" - else - request_early= - fi -], -[ - request_early='-DREQUEST_EARLY' -]) - -# Enable duplicate rules id -AC_ARG_ENABLE(rule-id-validation, - AS_HELP_STRING([--enable-rule-id-validation], - [Forbid duplicate rule ids and missing ones. This is the default]), -[ - if test "$enableval" != "no"; then - unique_id= - else - unique_id="-DALLOW_ID_NOT_UNIQUE" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $unique_id" - fi -], -[ - unique_id='' -]) - -# Disable logging of filename -AC_ARG_ENABLE(filename-logging, - AS_HELP_STRING([--enable-filename-logging], - [Enable logging of filename in audit log. This is the default]), -[ - if test "$enableval" != "no"; then - log_filename= - else - log_filename="-DLOG_NO_FILENAME" - fi -], -[ - log_filename='' -]) - -# Disable logging of "Server" -AC_ARG_ENABLE(server-logging, - AS_HELP_STRING([--enable-server-logging], - [Enable logging of "Server" in audit log when log level < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_server= - else - log_server="-DLOG_NO_SERVER" - fi -], -[ - log_server='' -]) - -# Disable logging of problem when deleting collection -AC_ARG_ENABLE(collection-delete-problem-logging, - AS_HELP_STRING([--enable-collection-delete-problem-logging], - [Enable logging of collection delete problem even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_collection_delete_problem= - else - log_collection_delete_problem="-DLOG_NO_COLL_DELET_PB" - fi -], -[ - log_collection_delete_problem='' -]) - -# Disable logging of Apache handler -AC_ARG_ENABLE(handler-logging, - AS_HELP_STRING([--enable-handler-logging], - [Enable logging of Apache handler in audit log even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_handler= - else - log_handler="-DLOG_NO_HANDLER" - fi -], -[ - log_handler='' -]) - -# Disable logging of dechunking -AC_ARG_ENABLE(dechunk-logging, - AS_HELP_STRING([--enable-dechunk-logging], - [Enable logging of dechunking even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_dechunk= - else - log_dechunk="-DLOG_NO_DECHUNK" - fi -], -[ - log_dechunk='' -]) - -# Disable logging of stopwatches -AC_ARG_ENABLE(stopwatch-logging, - AS_HELP_STRING([--enable-stopwatch-logging], - [Enable logging of stopwatches even when log level is < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_stopwatch= - else - log_stopwatch="-DLOG_NO_STOPWATCH" - fi -], -[ - log_stopwatch='' -]) - -# Disable logging of server context -AC_ARG_ENABLE(server-context-logging, - AS_HELP_STRING([--enable-server-context-logging], - [Enable logging of server info (log producer, sanitized objects, ...) in audit log even when log level < 9. This is the default]), -[ - if test "$enableval" != "no"; then - log_server_context= - else - log_server_context="-DLOG_NO_SERVER_CONTEXT" - fi -], -[ - log_server_context='' -]) - - -# Enable collection's global lock -AC_ARG_ENABLE(collection-global-lock, - AS_HELP_STRING([--enable-collection-global-lock], - [Enable collection correctness by using a global lock. May reduce performance significatively. This is disabled by default]), -[ - if test "$enableval" != "yes"; then - collection_global_lock="" - else - collection_global_lock="-DGLOBAL_COLLECTION_LOCK" - fi -], -[ - collection_global_lock='' -]) - - -# Ignore configure errors -AC_ARG_ENABLE(errors, - AS_HELP_STRING([--disable-errors], - [Disable errors during configure.]), -[ - if test "$enableval" != "no"; then - report_errors=1 - else - report_errors=0 - fi -], -[ - report_errors=1 -]) - - -# Strict Compile -AC_ARG_ENABLE(strict-compile, - AS_HELP_STRING([--enable-strict-compile], - [Enable strict compilation (warnings are errors).]), -[ - if test "$enableval" != "no"; then - strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $strict_compile" - else - strict_compile= - fi -], -[ - strict_compile= -]) - -# DEBUG_CONF -AC_ARG_ENABLE(debug-conf, - AS_HELP_STRING([--enable-debug-conf], - [Enable debug during configuration.]), -[ - if test "$enableval" != "no"; then - debug_conf="-DDEBUG_CONF" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_conf" - else - debug_conf= - fi -], -[ - debug_conf= -]) - -# CACHE_DEBUG -AC_ARG_ENABLE(debug-cache, - AS_HELP_STRING([--enable-debug-cache], - [Enable debug for transformation caching.]), -[ - if test "$enableval" != "no"; then - debug_cache="-DCACHE_DEBUG" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_cache" - else - debug_cache= - fi -], -[ - debug_cache= -]) - -# DEBUG_ACMP -AC_ARG_ENABLE(debug-acmp, - AS_HELP_STRING([--enable-debug-acmp], - [Enable debugging acmp code.]), -[ - if test "$enableval" != "no"; then - debug_acmp="-DDEBUG_ACMP" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_acmp" - else - debug_acmp= - fi -], -[ - debug_acmp= -]) - -# DEBUG_MEM -AC_ARG_ENABLE(debug-mem, - AS_HELP_STRING([--enable-debug-mem], - [Enable debug during configuration.]), -[ - if test "$enableval" != "no"; then - debug_mem="-DDEBUG_MEM" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_mem" - else - debug_mem= - fi -], -[ - debug_mem= -]) - -# PERFORMANCE_MEASUREMENT -AC_ARG_ENABLE(performance-measurement, - AS_HELP_STRING([--enable-performance-measurement], - [Enable performance-measurement stats.]), -[ - if test "$enableval" != "no"; then - perf_meas="-DPERFORMANCE_MEASUREMENT" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $perf_meas" - else - perf_meas= - fi -], -[ - perf_meas= -]) - -# NO_MODSEC_API -AC_ARG_ENABLE(modsec-api, - AS_HELP_STRING([--disable-modsec-api], - [Disable the API; compiling against some older Apache versions require this.]), -[ - if test "$enableval" != "yes"; then - modsec_api="-DNO_MODSEC_API" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $modsec_api" - else - modsec_api= - fi -], -[ - modsec_api= -]) - -# MSC_LARGE_STREAM_INPUT -AC_ARG_ENABLE(large-stream-input, - AS_HELP_STRING([--enable-large-stream-input], - [Enable optimization for large stream input]), -[ - if test "$enableval" = "yes"; then - large_stream_input="-DMSC_LARGE_STREAM_INPUT" - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" - else - large_stream_input= - fi -], -[ - large_stream_input= -]) - -# Find apxs -AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) -AC_ARG_WITH(apxs, - [AS_HELP_STRING([[--with-apxs=FILE]], - [FILE is the path to apxs; defaults to "apxs".])], -[ - if test "$withval" = "yes"; then - APXS=apxs - else - APXS="$withval" - fi -]) - -if test -z "$APXS"; then - for i in /usr/local/apache22/bin \ - /usr/local/apache2/bin \ - /usr/local/apache/bin \ - /usr/local/sbin \ - /usr/local/bin \ - /usr/sbin \ - /usr/bin; - do - if test -f "$i/apxs2"; then - APXS="$i/apxs2" - break - elif test -f "$i/apxs"; then - APXS="$i/apxs" - break - fi - done -fi - -# arbitrarily picking the same version subversion looks for, don't know how -# accurate this really is, but at least it'll force us to have apache2... -HTTPD_WANTED_MMN=20020903 - -if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then - APXS_INCLUDE="`$APXS -q INCLUDEDIR`" - if test -r $APXS_INCLUDE/httpd.h; then - AC_MSG_NOTICE(found apxs at $APXS) - AC_MSG_NOTICE(checking httpd version) - AC_EGREP_CPP(VERSION_OK, - [ -#include "$APXS_INCLUDE/ap_mmn.h" -#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) -VERSION_OK -#endif], - [AC_MSG_NOTICE(httpd is recent enough)], - [ - if test "$report_errors" -eq 1; then - AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) - else - AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) - fi - ]) -ÿ�fi - APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi - # Make sure the include dir is used - if test -n "$APXS_INCLUDEDIR"; then - APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" - else - APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi - APXS_CFLAGS=-I`$APXS -q INCLUDEDIR` - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi - APXS_LDFLAGS= - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi - APXS_LIBDIR="`$APXS -q LIBDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi - # Make sure the lib dir is used - if test -n "$APXS_LIBDIR"; then - APXS_LIBS="-L${APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" - else - APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi - APXS_LIBTOOL="`$APXS -q LIBTOOL`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi - APXS_CC="`$APXS -q CC`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi - APXS_BINDIR="`$APXS -q BINDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi - APXS_SBINDIR="`$APXS -q SBINDIR`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi - APXS_PROGNAME="`$APXS -q PROGNAME`" - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi - APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" - if test "xx$APXS_LIBEXECDIR" = "xx"; then APXS_LIBEXECDIR="`$APXS -q LIBDIR`/modules"; fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi - APXS_MODULES=$APXS_LIBEXECDIR - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs MODULES: $APXS_MODULES); fi - if test "$APXS_SBINDIR" = "/"; then - APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" - else - APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" - fi - if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi -else - if test "$report_errors" -eq 1; then - AC_MSG_ERROR(couldn't find APXS) - else - AC_MSG_NOTICE(couldn't find APXS) - fi -fi - -### Build *EXTRA_CFLAGS vars - -# Allow overriding EXTRA_CFLAGS -if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then - if test -z "$debug_mem"; then - EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" - fi -else - if test -n "$debug_mem"; then - EXTRA_CFLAGS="-O0 -g -Wall" - else - EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" - fi -fi -EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" - -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" - -APXS_WRAPPER=build/apxs-wrapper -APXS_EXTRA_CFLAGS="" -for f in $EXTRA_CFLAGS; do - APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" -done; -MODSEC_APXS_EXTRA_CFLAGS="" -for f in $MODSEC_EXTRA_CFLAGS; do - MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" -done; - -### Substitute the vars - -AC_SUBST(TOPLEVEL_SUBDIRS) -AC_SUBST(EXTRA_CFLAGS) -AC_SUBST(MODSEC_EXTRA_CFLAGS) -AC_SUBST(APXS) -AC_SUBST(APXS_WRAPPER) -AC_SUBST(APXS_INCLUDEDIR) -AC_SUBST(APXS_INCLUDES) -AC_SUBST(APXS_EXTRA_CFLAGS) -AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS) -AC_SUBST(APXS_LDFLAGS) -AC_SUBST(APXS_LIBS) -AC_SUBST(APXS_CFLAGS) -AC_SUBST(APXS_LIBTOOL) -AC_SUBST(APXS_CC) -AC_SUBST(APXS_LIBDIR) -AC_SUBST(APXS_BINDIR) -AC_SUBST(APXS_SBINDIR) -AC_SUBST(APXS_PROGNAME) -AC_SUBST(APXS_LIBEXECDIR) -AC_SUBST(APXS_MODULES) -AC_SUBST(APXS_HTTPD) - -CHECK_PCRE() -CHECK_PCRE2() -if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then -CHECK_APR() -CHECK_APU() -fi -CHECK_LIBXML2() -CHECK_LUA() -#if test "$build_mlogc" -ne 0; then -#CHECK_CURL() -#fi - -# Check for YAJL libs (for JSON body processor) -CHECK_YAJL() -#AC_SEARCH_LIBS([yajl_alloc], [yajl]) -CHECK_SSDEEP() -#AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy]) - -# Temporarily set cflags for apr_crypto check, then restore -# since it's already used correctly to compile modsecurity module. -ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" -ORIG_CPPFLAGS="$CPPFLAGS" -CFLAGS="$CFLAGS $APR_CFLAGS" -CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" -AC_LINK_IFELSE( - [AC_LANG_PROGRAM([[ #include <apr_crypto.h> ]], - [[ - #if APU_HAVE_CRYPTO == 0 - #error APR util was not compiled with crypto support. - #endif - ]])], - [ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support]) - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO" - ], - [ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ] -) -# Restore env vars so that we don't clutter with duplicates that -# are eventually appended later on -CFLAGS="$ORIG_CFLAGS" -CPPFLAGS="$ORIG_CPPFLAGS" - -# Currently our unique download backend is curl, further we can support more. -if test ! -z "${CURL_VERSION}"; then - AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" -fi - -AC_CONFIG_FILES([Makefile]) -AC_CONFIG_FILES([tools/Makefile]) -if test "$build_alp2" -ne 0; then -AC_CONFIG_FILES([alp2/Makefile]) -fi -if test "$build_apache2_module" -ne 0; then -AC_CONFIG_FILES([apache2/Makefile]) -fi -if test "$build_standalone_module" -ne 0; then -AC_CONFIG_FILES([standalone/Makefile]) -AC_CONFIG_FILES([nginx/modsecurity/config]) -fi -if test "$build_extentions" -ne 0; then -AC_CONFIG_FILES([ext/Makefile]) -fi -AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper]) -if test -e "$PERL"; then - if test "$build_mlogc" -ne 0; then - AC_CONFIG_FILES([mlogc/mlogc-batch-load.pl], [chmod +x mlogc/mlogc-batch-load.pl]) - AC_CONFIG_FILES([tests/regression/misc/40-secRemoteRules.t]) - AC_CONFIG_FILES([tests/regression/misc/50-ipmatchfromfile-external.t]) - AC_CONFIG_FILES([tests/regression/misc/60-pmfromfile-external.t]) - fi - AC_CONFIG_FILES([tests/run-unit-tests.pl], [chmod +x tests/run-unit-tests.pl]) - AC_CONFIG_FILES([tests/run-regression-tests.pl], [chmod +x tests/run-regression-tests.pl]) - AC_CONFIG_FILES([tests/gen_rx-pm.pl], [chmod +x tests/gen_rx-pm.pl]) - AC_CONFIG_FILES([tests/csv_rx-pm.pl], [chmod +x tests/csv_rx-pm.pl]) - AC_CONFIG_FILES([tests/regression/server_root/conf/httpd.conf]) - - # Perl based tools - AC_CONFIG_FILES([tools/rules-updater.pl], [chmod +x tools/rules-updater.pl]) -fi -if test "$build_mlogc" -ne 0; then - AC_CONFIG_FILES([mlogc/Makefile]) -fi -AC_CONFIG_FILES([tests/Makefile]) - -AC_OUTPUT +dnl +dnl Autoconf configuration for ModSecurity +dnl +dnl Use ./autogen.sh to produce a configure script +dnl + +AC_PREREQ(2.63) + +AC_INIT([modsecurity], [2.9], [support@modsecurity.org]) + +AC_CONFIG_MACRO_DIR([build]) +AC_CONFIG_SRCDIR([LICENSE]) +AC_CONFIG_HEADERS([apache2/modsecurity_config_auto.h]) +AC_CONFIG_AUX_DIR([build]) +AC_PREFIX_DEFAULT([/usr/local/modsecurity]) + +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) +m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) + +LT_PREREQ([2.2]) +LT_INIT([dlopen]) + +# Checks for programs. +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_GREP +AC_PATH_PROGS(PERL, [perl perl5], ) +AC_PATH_PROGS(ENV_CMD, [env printenv], ) +PKG_PROG_PKG_CONFIG + +# Checks for header files. +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_C_RESTRICT +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_STRUCT_TM +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_MEMCMP +AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol fchmod strcasestr]) + +# Some directories +MSC_BASE_DIR=`pwd` +MSC_PKGBASE_DIR="$MSC_BASE_DIR/.." +MSC_TEST_DIR="$MSC_BASE_DIR/tests" +MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression" +MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root" +MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf" +MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs" +MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs" + +AC_SUBST(MSC_BASE_DIR) +AC_SUBST(MSC_PKGBASE_DIR) +AC_SUBST(MSC_TEST_DIR) +AC_SUBST(MSC_REGRESSION_DIR) +AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR) +AC_SUBST(MSC_REGRESSION_CONF_DIR) +AC_SUBST(MSC_REGRESSION_LOGS_DIR) +AC_SUBST(MSC_REGRESSION_DOCROOT_DIR) + +### Configure Options + +# Verbose output +AC_ARG_ENABLE(verbose-output, + AS_HELP_STRING([--enable-verbose-output], + [Enable more verbose configure output.]), +[ + if test "$enableval" != "no"; then + verbose_output=1 + else + verbose_output=0 + fi +], +[ + verbose_output=0 +]) + + +#OS type + +AC_CANONICAL_HOST +CANONICAL_HOST=$host + +AH_TEMPLATE([AIX], [Define if the operating system is AIX]) +AH_TEMPLATE([LINUX], [Define if the operating system is LINUX]) +AH_TEMPLATE([OPENBSD], [Define if the operating system is OpenBSD]) +AH_TEMPLATE([SOLARIS], [Define if the operating system is SOLARIS]) +AH_TEMPLATE([HPUX], [Define if the operating system is HPUX]) +AH_TEMPLATE([MACOSX], [Define if the operating system is Macintosh OSX]) +AH_TEMPLATE([FREEBSD], [Define if the operating system is FREEBSD]) +AH_TEMPLATE([NETBSD], [Define if the operating system is NetBSD]) + + +case $host in + *-*-aix*) + echo "Checking platform... Identified as AIX" + aixos=true + ;; + *-*-hpux*) + echo "Checking platform... Identified as HPUX" + hpuxos=true + ;; + *-*-darwin*) + echo "Checking platform... Identified as Macintosh OS X" + macos=true + ;; + *-*-linux*) + echo "Checking platform... Identified as Linux" + linuxos=true + case "${host_cpu}" in + s390x) + cpu_type="-DLINUX_S390" + ;; + esac + ;; + *-*-solaris*) + echo "Checking platform... Identified as Solaris" + solarisos=true + ;; + *-*-freebsd*) + echo "Checking platform... Identified as FreeBSD" + freebsdos=true + ;; + *-*-netbsd*) + echo "Checking platform... Identified as NetBSD" + netbsdos=true + ;; + *-*-openbsd*) + echo "Checking platform... Identified as OpenBSD" + openbsdos=true + ;; + *-*-kfreebsd*) + echo "Checking platform... Identified as kFreeBSD, treating as linux" + linuxos=true + ;; + *-*-gnu*.*) + echo "Checking platform... Identified as HURD, treating as linux" + linuxos=true + ;; + *) + echo "Unknown CANONICAL_HOST $host" + exit + ;; +esac + +AM_CONDITIONAL([AIX], [test x$aixos = xtrue]) +AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue]) +AM_CONDITIONAL([MACOSX], [test x$macos = xtrue]) +AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue]) +AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue]) +AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue]) +AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue]) +AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue]) +AM_CONDITIONAL([NETBSD], [test x$netbsdos = xtrue]) + +#Subdirs +TOPLEVEL_SUBDIRS="tools" + +# Apache2 Module +AC_ARG_ENABLE(apache2-module, + AS_HELP_STRING([--disable-apache2-module], + [Disable building Apache2 module.]), +[ + if test "$enableval" != "no"; then + build_apache2_module=1 + else + build_apache2_module=0 + fi +], +[ + build_apache2_module=1 +]) +AM_CONDITIONAL([BUILD_APACHE2_MODULE], [test "$build_apache2_module" -eq 1]) +if test "$build_apache2_module" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS apache2" +fi + + +# Standalone Module +AC_ARG_ENABLE(standalone-module, + AS_HELP_STRING([--enable-standalone-module], + [Enable building standalone module.]), +[ + if test "$enableval" != "no"; then + build_standalone_module=1 + else + build_standalone_module=0 + fi +], +[ + build_standalone_module=0 +]) +AM_CONDITIONAL([BUILD_STANDALONE_MODULE], [test "$build_standalone_module" -eq 1]) +if test "$build_standalone_module" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS standalone" +fi + + +# Extensions +AC_ARG_ENABLE(extentions, + AS_HELP_STRING([--enable-extentions], + [Enable building extension.]), +[ + if test "$enableval" != "no"; then + build_extentions=1 + else + build_extentions=0 + fi +], +[ + build_extentions=0 +]) +AM_CONDITIONAL([BUILD_extentions], [test "$build_extentions" -eq 1]) +if test "$build_extentions" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS ext" +fi + + +# Mlogc +AC_ARG_ENABLE(mlogc, + AS_HELP_STRING([--disable-mlogc], + [Disable building mlogc.]), +[ + if test "$enableval" != "no"; then + build_mlogc=1 + else + build_mlogc=0 + fi +], +[ + build_mlogc=1 +]) + +CHECK_CURL() + +if test -z "${CURL_VERSION}"; then + AC_MSG_NOTICE([NOTE: mlogc compilation was disabled.]) + build_mlogc=0 +fi + +AM_CONDITIONAL([BUILD_MLOGC], [test "$build_mlogc" -eq 1]) +if test "$build_mlogc" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS mlogc" +fi + +# Audit Log Parser v2 (ALP2) +AC_ARG_ENABLE(alp2, + AS_HELP_STRING([--enable-alp2], + [Enable building audit log parser lib.]), +[ + if test "$enableval" != "no"; then + build_alp2=1 + else + build_alp2=0 + fi +], +[ + build_alp2=0 +]) +AM_CONDITIONAL([BUILD_ALP2], [test "$build_alp2" -eq 1]) +if test "$build_alp2" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS alp2" +fi + +# Documentation +AC_ARG_ENABLE(docs, + AS_HELP_STRING([--enable-docs], + [Enable building documentation.]), +[ + if test "$enableval" != "no"; then + build_docs=1 + else + build_docs=0 + fi +], +[ + build_docs=0 +]) +AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1]) +if test "$build_docs" -eq 1; then + TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS doc" + AC_CHECK_PROGS([DOXYGEN], [doxygen]) + if test -z "$DOXYGEN"; then + AC_MSG_WARN([Doxygen not found - continue without Doxygen support]) + fi + if test "$build_apache2_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-apache]) + fi + if test "$build_standalone_module" -eq 1; then + AC_CONFIG_FILES([doc/doxygen-nginx]) + AC_CONFIG_FILES([doc/doxygen-iis]) + AC_CONFIG_FILES([doc/doxygen-standalone]) + fi + AC_CONFIG_FILES([doc/Makefile]) +fi + + +# Add assert() usage + +AC_ARG_ENABLE(assertions, + AS_HELP_STRING([--enable-assertions], + [Turn on assertions checks (undefine NDEBUG)]), +[ + if test "${enableval}" = "yes"; then + assertions='-UNDEBUG' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" + else + assertions='-DNDEBUG' + fi +], +[ + assertions='-DNDEBUG' +]) + +# Add PCRE Studying + +AC_ARG_ENABLE(pcre-study, + AS_HELP_STRING([--enable-pcre-study], + [Enable PCRE regex studying during configure.]), +[ + if test "$enableval" != "no"; then + pcre_study='-DWITH_PCRE_STUDY' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_study" + else + pcre_study='' + fi +], +[ + pcre_study='-DWITH_PCRE_STUDY' +]) + +# Add PCRE JIT + +AC_ARG_ENABLE(pcre-jit, + AS_HELP_STRING([--enable-pcre-jit], + [Enable PCRE regex jit support during configure.]), +[ + if test "$enableval" != "no"; then + pcre_jit='-DWITH_PCRE_JIT' + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_jit" + else + pcre_jit='' + fi +], +[ + pcre_jit='' +]) + + +# Limit PCRE matching +AC_ARG_ENABLE(pcre-match-limit, + AS_HELP_STRING([--enable-pcre-match-limit], + [Enable PCRE regex match limit during configure.]), +[ + if test "$enableval" = "yes"; then + AC_MSG_ERROR([PCRE match limits require a numeric value]) + elif test "$enableval" = "no"; then + pcre_match_limit='' + else + pcre_match_limit="-DMODSEC_PCRE_MATCH_LIMIT=$enableval" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit" + fi +], +[ + pcre_match_limit='-DMODSEC_PCRE_MATCH_LIMIT=1500' +]) + +# Limit PCRE matching recursion +AC_ARG_ENABLE(pcre-match-limit-recursion, + AS_HELP_STRING([--enable-pcre-match-limit-recursion], + [Enable PCRE regex match limit recursion during configure.]), +[ + if test "$enableval" = "yes"; then + AC_MSG_ERROR([PCRE match limits require a numeric value]) + elif test "$enableval" = "no"; then + pcre_match_limit_recursion='' + else + pcre_match_limit_recursion="-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=$enableval" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit_recursion" + fi +], +[ + pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500' +]) + +# Enable Lua per transaction cache +AC_ARG_ENABLE(lua-cache, + AS_HELP_STRING([--enable-lua-cache], + [Enable Lua per transaction cache.]), +[ + if test "$enableval" != "no"; then + lua_cache="-DCACHE_LUA" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache" + else + lua_cache= + fi +], +[ + lua_cache= +]) + +# Enable phase-1 in post_read_request +AC_ARG_ENABLE(htaccess-config, + AS_HELP_STRING([--enable-htaccess-config], + [Enable some mod_security directives into htaccess files.]), +[ + if test "$enableval" != "no"; then + htaccess_config="-DHTACCESS_CONFIG" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $htaccess_config" + else + htaccess_config= + fi +], +[ + htaccess_config= +]) + +# Enable phase-1 in post_read_request +AC_ARG_ENABLE(request-early, + AS_HELP_STRING([--enable-request-early], + [Place phase1 into post_read_request hook. default is hook_request_early]), +[ + if test "$enableval" != "no"; then + request_early="-DREQUEST_EARLY" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early" + else + request_early= + fi +], +[ + request_early='-DREQUEST_EARLY' +]) + +# Enable duplicate rules id +AC_ARG_ENABLE(rule-id-validation, + AS_HELP_STRING([--enable-rule-id-validation], + [Forbid duplicate rule ids and missing ones. This is the default]), +[ + if test "$enableval" != "no"; then + unique_id= + else + unique_id="-DALLOW_ID_NOT_UNIQUE" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $unique_id" + fi +], +[ + unique_id='' +]) + +# Disable logging of filename +AC_ARG_ENABLE(filename-logging, + AS_HELP_STRING([--enable-filename-logging], + [Enable logging of filename in audit log. This is the default]), +[ + if test "$enableval" != "no"; then + log_filename= + else + log_filename="-DLOG_NO_FILENAME" + fi +], +[ + log_filename='' +]) + +# Disable logging of "Server" +AC_ARG_ENABLE(server-logging, + AS_HELP_STRING([--enable-server-logging], + [Enable logging of "Server" in audit log when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server= + else + log_server="-DLOG_NO_SERVER" + fi +], +[ + log_server='' +]) + +# Disable logging of problem when deleting collection +AC_ARG_ENABLE(collection-delete-problem-logging, + AS_HELP_STRING([--enable-collection-delete-problem-logging], + [Enable logging of collection delete problem even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_collection_delete_problem= + else + log_collection_delete_problem="-DLOG_NO_COLL_DELET_PB" + fi +], +[ + log_collection_delete_problem='' +]) + +# Disable logging of Apache handler +AC_ARG_ENABLE(handler-logging, + AS_HELP_STRING([--enable-handler-logging], + [Enable logging of Apache handler in audit log even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_handler= + else + log_handler="-DLOG_NO_HANDLER" + fi +], +[ + log_handler='' +]) + +# Disable logging of dechunking +AC_ARG_ENABLE(dechunk-logging, + AS_HELP_STRING([--enable-dechunk-logging], + [Enable logging of dechunking even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_dechunk= + else + log_dechunk="-DLOG_NO_DECHUNK" + fi +], +[ + log_dechunk='' +]) + +# Disable logging of stopwatches +AC_ARG_ENABLE(stopwatch-logging, + AS_HELP_STRING([--enable-stopwatch-logging], + [Enable logging of stopwatches even when log level is < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_stopwatch= + else + log_stopwatch="-DLOG_NO_STOPWATCH" + fi +], +[ + log_stopwatch='' +]) + +# Disable logging of server context +AC_ARG_ENABLE(server-context-logging, + AS_HELP_STRING([--enable-server-context-logging], + [Enable logging of server info (log producer, sanitized objects, ...) in audit log even when log level < 9. This is the default]), +[ + if test "$enableval" != "no"; then + log_server_context= + else + log_server_context="-DLOG_NO_SERVER_CONTEXT" + fi +], +[ + log_server_context='' +]) + + +# Enable collection's global lock +AC_ARG_ENABLE(collection-global-lock, + AS_HELP_STRING([--enable-collection-global-lock], + [Enable collection correctness by using a global lock. May reduce performance significatively. This is disabled by default]), +[ + if test "$enableval" != "yes"; then + collection_global_lock="" + else + collection_global_lock="-DGLOBAL_COLLECTION_LOCK" + fi +], +[ + collection_global_lock='' +]) + + +# Ignore configure errors +AC_ARG_ENABLE(errors, + AS_HELP_STRING([--disable-errors], + [Disable errors during configure.]), +[ + if test "$enableval" != "no"; then + report_errors=1 + else + report_errors=0 + fi +], +[ + report_errors=1 +]) + + +# Strict Compile +AC_ARG_ENABLE(strict-compile, + AS_HELP_STRING([--enable-strict-compile], + [Enable strict compilation (warnings are errors).]), +[ + if test "$enableval" != "no"; then + strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $strict_compile" + else + strict_compile= + fi +], +[ + strict_compile= +]) + +# DEBUG_CONF +AC_ARG_ENABLE(debug-conf, + AS_HELP_STRING([--enable-debug-conf], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_conf="-DDEBUG_CONF" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_conf" + else + debug_conf= + fi +], +[ + debug_conf= +]) + +# CACHE_DEBUG +AC_ARG_ENABLE(debug-cache, + AS_HELP_STRING([--enable-debug-cache], + [Enable debug for transformation caching.]), +[ + if test "$enableval" != "no"; then + debug_cache="-DCACHE_DEBUG" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_cache" + else + debug_cache= + fi +], +[ + debug_cache= +]) + +# DEBUG_ACMP +AC_ARG_ENABLE(debug-acmp, + AS_HELP_STRING([--enable-debug-acmp], + [Enable debugging acmp code.]), +[ + if test "$enableval" != "no"; then + debug_acmp="-DDEBUG_ACMP" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_acmp" + else + debug_acmp= + fi +], +[ + debug_acmp= +]) + +# DEBUG_MEM +AC_ARG_ENABLE(debug-mem, + AS_HELP_STRING([--enable-debug-mem], + [Enable debug during configuration.]), +[ + if test "$enableval" != "no"; then + debug_mem="-DDEBUG_MEM" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_mem" + else + debug_mem= + fi +], +[ + debug_mem= +]) + +# PERFORMANCE_MEASUREMENT +AC_ARG_ENABLE(performance-measurement, + AS_HELP_STRING([--enable-performance-measurement], + [Enable performance-measurement stats.]), +[ + if test "$enableval" != "no"; then + perf_meas="-DPERFORMANCE_MEASUREMENT" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $perf_meas" + else + perf_meas= + fi +], +[ + perf_meas= +]) + +# NO_MODSEC_API +AC_ARG_ENABLE(modsec-api, + AS_HELP_STRING([--disable-modsec-api], + [Disable the API; compiling against some older Apache versions require this.]), +[ + if test "$enableval" != "yes"; then + modsec_api="-DNO_MODSEC_API" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $modsec_api" + else + modsec_api= + fi +], +[ + modsec_api= +]) + +# MSC_LARGE_STREAM_INPUT +AC_ARG_ENABLE(large-stream-input, + AS_HELP_STRING([--enable-large-stream-input], + [Enable optimization for large stream input]), +[ + if test "$enableval" = "yes"; then + large_stream_input="-DMSC_LARGE_STREAM_INPUT" + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $large_stream_input" + else + large_stream_input= + fi +], +[ + large_stream_input= +]) + +# Find apxs +AC_MSG_NOTICE(looking for Apache module support via DSO through APXS) +AC_ARG_WITH(apxs, + [AS_HELP_STRING([[--with-apxs=FILE]], + [FILE is the path to apxs; defaults to "apxs".])], +[ + if test "$withval" = "yes"; then + APXS=apxs + else + APXS="$withval" + fi +]) + +if test -z "$APXS"; then + for i in /usr/local/apache22/bin \ + /usr/local/apache2/bin \ + /usr/local/apache/bin \ + /usr/local/sbin \ + /usr/local/bin \ + /usr/sbin \ + /usr/bin; + do + if test -f "$i/apxs2"; then + APXS="$i/apxs2" + break + elif test -f "$i/apxs"; then + APXS="$i/apxs" + break + fi + done +fi + +# arbitrarily picking the same version subversion looks for, don't know how +# accurate this really is, but at least it'll force us to have apache2... +HTTPD_WANTED_MMN=20020903 + +if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then + APXS_INCLUDE="`$APXS -q INCLUDEDIR`" + if test -r $APXS_INCLUDE/httpd.h; then + AC_MSG_NOTICE(found apxs at $APXS) + AC_MSG_NOTICE(checking httpd version) + AC_EGREP_CPP(VERSION_OK, + [ +#include "$APXS_INCLUDE/ap_mmn.h" +#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0) +VERSION_OK +#endif], + [AC_MSG_NOTICE(httpd is recent enough)], + [ + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + else + AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN) + fi + ]) + fi + APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi + # Make sure the include dir is used + if test -n "$APXS_INCLUDEDIR"; then + APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + else + APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi + APXS_CFLAGS=-I`$APXS -q INCLUDEDIR` + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi + APXS_LDFLAGS= + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi + APXS_LIBDIR="`$APXS -q LIBDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi + # Make sure the lib dir is used + if test -n "$APXS_LIBDIR"; then + APXS_LIBS="-L${APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + else + APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi + APXS_LIBTOOL="`$APXS -q LIBTOOL`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi + APXS_CC="`$APXS -q CC`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi + APXS_BINDIR="`$APXS -q BINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi + APXS_SBINDIR="`$APXS -q SBINDIR`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi + APXS_PROGNAME="`$APXS -q PROGNAME`" + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi + APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`" + if test "xx$APXS_LIBEXECDIR" = "xx"; then APXS_LIBEXECDIR="`$APXS -q LIBDIR`/modules"; fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi + APXS_MODULES=$APXS_LIBEXECDIR + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs MODULES: $APXS_MODULES); fi + if test "$APXS_SBINDIR" = "/"; then + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + else + APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME" + fi + if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi +else + if test "$report_errors" -eq 1; then + AC_MSG_ERROR(couldn't find APXS) + else + AC_MSG_NOTICE(couldn't find APXS) + fi +fi + +### Build *EXTRA_CFLAGS vars + +# Allow overriding EXTRA_CFLAGS +if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then + if test -z "$debug_mem"; then + EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile" + fi +else + if test -n "$debug_mem"; then + EXTRA_CFLAGS="-O0 -g -Wall" + else + EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" + fi +fi +EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" + +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" + +APXS_WRAPPER=build/apxs-wrapper +APXS_EXTRA_CFLAGS="" +for f in $EXTRA_CFLAGS; do + APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f" +done; +MODSEC_APXS_EXTRA_CFLAGS="" +for f in $MODSEC_EXTRA_CFLAGS; do + MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f" +done; + +### Substitute the vars + +AC_SUBST(TOPLEVEL_SUBDIRS) +AC_SUBST(EXTRA_CFLAGS) +AC_SUBST(MODSEC_EXTRA_CFLAGS) +AC_SUBST(APXS) +AC_SUBST(APXS_WRAPPER) +AC_SUBST(APXS_INCLUDEDIR) +AC_SUBST(APXS_INCLUDES) +AC_SUBST(APXS_EXTRA_CFLAGS) +AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS) +AC_SUBST(APXS_LDFLAGS) +AC_SUBST(APXS_LIBS) +AC_SUBST(APXS_CFLAGS) +AC_SUBST(APXS_LIBTOOL) +AC_SUBST(APXS_CC) +AC_SUBST(APXS_LIBDIR) +AC_SUBST(APXS_BINDIR) +AC_SUBST(APXS_SBINDIR) +AC_SUBST(APXS_PROGNAME) +AC_SUBST(APXS_LIBEXECDIR) +AC_SUBST(APXS_MODULES) +AC_SUBST(APXS_HTTPD) + +CHECK_PCRE() +CHECK_PCRE2() +if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then +CHECK_APR() +CHECK_APU() +fi +CHECK_LIBXML2() +CHECK_LUA() +#if test "$build_mlogc" -ne 0; then +#CHECK_CURL() +#fi + +# Check for YAJL libs (for JSON body processor) +CHECK_YAJL() +#AC_SEARCH_LIBS([yajl_alloc], [yajl]) +CHECK_SSDEEP() +#AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy]) + +# Temporarily set cflags for apr_crypto check, then restore +# since it's already used correctly to compile modsecurity module. +ORIG_CFLAGS="$CFLAGS $APU_CFLAGS" +ORIG_CPPFLAGS="$CPPFLAGS" +CFLAGS="$CFLAGS $APR_CFLAGS" +CPPFLAGS="$CPPFLAGS $APR_CPPFLAGS" +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include <apr_crypto.h> ]], + [[ + #if APU_HAVE_CRYPTO == 0 + #error APR util was not compiled with crypto support. + #endif + ]])], + [ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support]) + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO" + ], + [ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ] +) +# Restore env vars so that we don't clutter with duplicates that +# are eventually appended later on +CFLAGS="$ORIG_CFLAGS" +CPPFLAGS="$ORIG_CPPFLAGS" + +# Currently our unique download backend is curl, further we can support more. +if test ! -z "${CURL_VERSION}"; then + AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support]) + MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES" +fi + +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([tools/Makefile]) +if test "$build_alp2" -ne 0; then +AC_CONFIG_FILES([alp2/Makefile]) +fi +if test "$build_apache2_module" -ne 0; then +AC_CONFIG_FILES([apache2/Makefile]) +fi +if test "$build_standalone_module" -ne 0; then +AC_CONFIG_FILES([standalone/Makefile]) +AC_CONFIG_FILES([nginx/modsecurity/config]) +fi +if test "$build_extentions" -ne 0; then +AC_CONFIG_FILES([ext/Makefile]) +fi +AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper]) +if test -e "$PERL"; then + if test "$build_mlogc" -ne 0; then + AC_CONFIG_FILES([mlogc/mlogc-batch-load.pl], [chmod +x mlogc/mlogc-batch-load.pl]) + AC_CONFIG_FILES([tests/regression/misc/40-secRemoteRules.t]) + AC_CONFIG_FILES([tests/regression/misc/50-ipmatchfromfile-external.t]) + AC_CONFIG_FILES([tests/regression/misc/60-pmfromfile-external.t]) + fi + AC_CONFIG_FILES([tests/run-unit-tests.pl], [chmod +x tests/run-unit-tests.pl]) + AC_CONFIG_FILES([tests/run-regression-tests.pl], [chmod +x tests/run-regression-tests.pl]) + AC_CONFIG_FILES([tests/gen_rx-pm.pl], [chmod +x tests/gen_rx-pm.pl]) + AC_CONFIG_FILES([tests/csv_rx-pm.pl], [chmod +x tests/csv_rx-pm.pl]) + AC_CONFIG_FILES([tests/regression/server_root/conf/httpd.conf]) + + # Perl based tools + AC_CONFIG_FILES([tools/rules-updater.pl], [chmod +x tools/rules-updater.pl]) +fi +if test "$build_mlogc" -ne 0; then + AC_CONFIG_FILES([mlogc/Makefile]) +fi +AC_CONFIG_FILES([tests/Makefile]) + +AC_OUTPUT From 5122f890057285d6d9d6eda16ca5702e6e969984 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 16 Apr 2024 13:28:37 +0200 Subject: [PATCH 390/477] defined id_log() only once --- apache2/apache2_config.c | 5 ++--- apache2/msc_util.h | 1 + apache2/re.c | 7 ------- configure.ac | 5 ++--- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 17f529ce20..18208c821f 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -31,10 +31,9 @@ #endif // Returns the rule id if existing, otherwise the file name & line number -static const char* id_log(msre_rule* rule) { +const char* id_log(msre_rule* rule) { char* id = rule->actionset->id; - if (id == NOT_SET_P || !id || !*id) - id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; } diff --git a/apache2/msc_util.h b/apache2/msc_util.h index 1925a155f1..afff3e7f64 100644 --- a/apache2/msc_util.h +++ b/apache2/msc_util.h @@ -166,6 +166,7 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, #endif char DSOLOCAL *get_username(apr_pool_t* mp); +const char* id_log(msre_rule* rule); int read_line(char *buff, int size, FILE *fp); diff --git a/apache2/re.c b/apache2/re.c index e775d546b6..8e69f5bafa 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -48,13 +48,6 @@ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr); /* -- Actions, variables, functions and operator functions ----------------- */ -// Returns the rule id if existing, otherwise the file name & line number -static const char* id_log(msre_rule* rule) { - const char* id = rule->actionset->id; - if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); - return id; -} - /** * \brief Remove rule targets to be processed * diff --git a/configure.ac b/configure.ac index 24a3dba7ef..a9025c717f 100644 --- a/configure.ac +++ b/configure.ac @@ -313,7 +313,6 @@ AC_ARG_ENABLE(assertions, [ if test "${enableval}" = "yes"; then assertions='-UNDEBUG' - MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $assertions" else assertions='-DNDEBUG' fi @@ -844,9 +843,9 @@ else EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" fi fi -EXTRA_CFLAGS="$EXTRA_CFLAGS $assertions" +EXTRA_CFLAGS="$EXTRA_CFLAGS" -MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input" +MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input $assertions" APXS_WRAPPER=build/apxs-wrapper APXS_EXTRA_CFLAGS="" From 62302c2474a9d4651930e6f411e18937ebc34d10 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Tue, 16 Apr 2024 17:59:43 +0200 Subject: [PATCH 391/477] Update apache2/apache2_io.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Felipe ZipitrÃa <3012076+fzipi@users.noreply.github.com> --- apache2/apache2_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index b8117d91ce..5d2ef85bd9 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -180,7 +180,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, */ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { assert(msr != NULL); - assert( error_msg!= NULL); + assert(error_msg!= NULL); request_rec *r = msr->r; unsigned int finished_reading; apr_bucket_brigade *bb_in; From d35018ef3f6de8fecef9949762da7c9b8b91a48b Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 16 Apr 2024 18:02:06 +0200 Subject: [PATCH 392/477] another null check --- apache2/apache2_config.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 18208c821f..f5c3fea7e2 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -32,7 +32,9 @@ // Returns the rule id if existing, otherwise the file name & line number const char* id_log(msre_rule* rule) { - char* id = rule->actionset->id; + assert(rule != NULL); + assert(rule->actionset != NULL); + char* id = rule->actionset->id; if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; } From 4961f46a6f1772c53a1951dfa2b80c4429846986 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Tue, 16 Apr 2024 18:09:00 +0200 Subject: [PATCH 393/477] (re)fixed const type --- apache2/apache2_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index f5c3fea7e2..c0464f50eb 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -34,7 +34,7 @@ const char* id_log(msre_rule* rule) { assert(rule != NULL); assert(rule->actionset != NULL); - char* id = rule->actionset->id; + const char* id = rule->actionset->id; if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; } From dd400f7fa31da8174a930806e9c46bc99062db06 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach.be> Date: Fri, 26 Apr 2024 17:22:16 +0200 Subject: [PATCH 394/477] Added --enable-assertions in CI Removed useless line --- .github/workflows/ci.yml | 2 +- configure.ac | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5ca97df84..d931133834 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: autogen.sh run: ./autogen.sh - name: configure ${{ matrix.configure.label }} - run: ./configure ${{ matrix.configure.opt }} + run: ./configure --enable-assertions ${{ matrix.configure.opt }} - uses: ammaraskar/gcc-problem-matcher@master - name: make run: make -j `nproc` diff --git a/configure.ac b/configure.ac index a9025c717f..c75335c14d 100644 --- a/configure.ac +++ b/configure.ac @@ -843,7 +843,6 @@ else EXTRA_CFLAGS="-O2 -g -Wall $strict_compile" fi fi -EXTRA_CFLAGS="$EXTRA_CFLAGS" MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type $unique_id $log_filename $log_server $log_collection_delete_problem $log_dechunk $log_stopwatch $log_handler $log_server_context $collection_global_lock $large_stream_input $assertions" From a61820fe2cae58ca8ed3336d07147d0e76d61638 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 10 May 2024 17:26:23 +0200 Subject: [PATCH 395/477] Enhanced logging [Issue #3107] --- CHANGES | 2 ++ apache2/msc_json.c | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index eb1b846c06..80d8520c47 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.x (to be released) ------------------- + * Enhance logging + [Issue #3107 - @marcstern] * Fix possible segfault in collection_unpack [Issue #3072 - @twouters] * Set the minimum security protocol version for SecRemoteRules diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 4cbeebf59c..f57d780200 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -65,6 +65,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) log_escape_ex(msr->mp, arg->value, arg->value_len)); } msr->msc_reqbody_error = 1; + msr->json->yajl_error = apr_psprintf(msr->mp, "More than %ld JSON keys", msr->txcfg->arguments_limit); return 0; } @@ -374,9 +375,12 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char if (msr->json->depth_limit_exceeded) { *error_msg = "JSON depth limit exceeded"; } else { - char *yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); - *error_msg = apr_pstrdup(msr->mp, yajl_err); - yajl_free_error(msr->json->handle, yajl_err); + if (msr->json->yajl_error) *error_msg = msr->json->yajl_error; + else { + char* yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); + *error_msg = apr_pstrdup(msr->mp, yajl_err); + yajl_free_error(msr->json->handle, yajl_err); + } } return -1; } From 746f57f96312ce2f564f708bf9ac116f9a92be96 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 16 May 2024 15:52:31 +0200 Subject: [PATCH 396/477] Changed indentation --- apache2/msc_json.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/msc_json.c b/apache2/msc_json.c index f57d780200..136e8ad9cb 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -377,9 +377,9 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char } else { if (msr->json->yajl_error) *error_msg = msr->json->yajl_error; else { - char* yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); - *error_msg = apr_pstrdup(msr->mp, yajl_err); - yajl_free_error(msr->json->handle, yajl_err); + char* yajl_err = yajl_get_error(msr->json->handle, 0, buf, size); + *error_msg = apr_pstrdup(msr->mp, yajl_err); + yajl_free_error(msr->json->handle, yajl_err); } } return -1; From d45c4baa83355a729129d1662c4c7c6fd6cd97d1 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 16 May 2024 16:55:31 +0200 Subject: [PATCH 397/477] spaces --- apache2/re_operators.c | 2223 ++++++++++++++++++++-------------------- 1 file changed, 1088 insertions(+), 1135 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index a5bc05224f..5f31933dee 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -41,24 +41,24 @@ /** * */ -void msre_engine_op_register(msre_engine* engine, const char* name, +void msre_engine_op_register(msre_engine *engine, const char *name, fn_op_param_init_t fn1, fn_op_execute_t fn2) { - msre_op_metadata* metadata = (msre_op_metadata*)apr_pcalloc(engine->mp, + msre_op_metadata *metadata = (msre_op_metadata *)apr_pcalloc(engine->mp, sizeof(msre_op_metadata)); if (metadata == NULL) return; metadata->name = name; metadata->param_init = fn1; metadata->execute = fn2; - apr_table_setn(engine->operators, name, (void*)metadata); + apr_table_setn(engine->operators, name, (void *)metadata); } /** * */ -msre_op_metadata* msre_engine_op_resolve(msre_engine* engine, const char* name) { - return (msre_op_metadata*)apr_table_get(engine->operators, name); +msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) { + return (msre_op_metadata *)apr_table_get(engine->operators, name); } @@ -67,8 +67,8 @@ msre_op_metadata* msre_engine_op_resolve(msre_engine* engine, const char* name) /* unconditionalMatch */ -static int msre_op_unconditionalmatch_execute(modsec_rec* msr, msre_rule* rule, - msre_var* var, char** error_msg) +static int msre_op_unconditionalmatch_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) { assert(error_msg != NULL); *error_msg = "Unconditional match in SecAction."; @@ -79,8 +79,8 @@ static int msre_op_unconditionalmatch_execute(modsec_rec* msr, msre_rule* rule, /* noMatch */ -static int msre_op_nomatch_execute(modsec_rec* msr, msre_rule* rule, - msre_var* var, char** error_msg) +static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) { assert(error_msg != NULL); *error_msg = "No match."; @@ -100,8 +100,8 @@ static int msre_op_nomatch_execute(modsec_rec* msr, msre_rule* rule, * \retval 1 On Success * \retval 0 On Fail */ -static int msre_op_ipmatch_param_init(msre_rule* rule, char** error_msg) { - char* param = NULL; +static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { + char *param = NULL; int res = 0; if (error_msg == NULL) @@ -132,11 +132,11 @@ static int msre_op_ipmatch_param_init(msre_rule* rule, char** error_msg) { * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_ipmatch_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, char** error_msg) { +static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(var != NULL); assert(error_msg != NULL); - TreeRoot* rtree = NULL; + TreeRoot *rtree = NULL; int res = 0; *error_msg = NULL; @@ -154,7 +154,7 @@ static int msre_op_ipmatch_execute(modsec_rec* msr, msre_rule* rule, msre_var* v msr_log(msr, 1, "%s", *error_msg); *error_msg = NULL; } - + if (res > 0) { *error_msg = apr_psprintf(msr->mp, "IPmatch: \"%s\" matched at %s.", var->value, var->name); } @@ -172,13 +172,13 @@ static int msre_op_ipmatch_execute(modsec_rec* msr, msre_rule* rule, msre_var* v * \retval 1 On Success * \retval 0 On Fail */ -static int msre_op_ipmatchFromFile_param_init(msre_rule* rule, char** error_msg) { - const char* rootpath = NULL; - const char* filepath = NULL; - const char* ipfile_path = NULL; - char* fn = NULL; +static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg) { + const char *rootpath = NULL; + const char *filepath = NULL; + const char *ipfile_path = NULL; + char *fn = NULL; int res = 0; - TreeRoot* rtree = NULL; + TreeRoot *rtree = NULL; if ((rule->op_param == NULL) || (strlen(rule->op_param) == 0)) { @@ -200,14 +200,14 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule* rule, char** error_msg) filepath = fn; if (strlen(fn) > strlen("http://") && - strncmp(fn, "http://", strlen("http://")) == 0) + strncmp(fn, "http://", strlen("http://")) == 0) { *error_msg = apr_psprintf(rule->ruleset->mp, "HTTPS address or file " \ "path are expected for operator ipmatchFromFile \"%s\"", fn); return 0; } else if (strlen(fn) > strlen("https://") && - strncmp(fn, "https://", strlen("https://")) == 0) + strncmp(fn, "https://", strlen("https://")) == 0) { #ifdef WITH_CURL res = ip_tree_from_uri(&rtree, fn, rule->ruleset->mp, error_msg); @@ -221,7 +221,7 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule* rule, char** error_msg) return 0; } #else - * error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ + *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ "compiled with Curl support, it cannot load: \"%s\"", fn); return 0; #endif @@ -258,13 +258,13 @@ static int msre_op_ipmatchFromFile_param_init(msre_rule* rule, char** error_msg) * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_ipmatchFromFile_execute(modsec_rec* msr, msre_rule* rule, - msre_var* var, char** error_msg) { +static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - TreeRoot* rtree = (TreeRoot*)rule->op_param_data; + TreeRoot *rtree = (TreeRoot *)rule->op_param_data; int res = 0; *error_msg = NULL; @@ -280,7 +280,7 @@ static int msre_op_ipmatchFromFile_execute(modsec_rec* msr, msre_rule* rule, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "IPmatchFromFile: Total tree entries: %d, ipv4 %d " \ - "ipv6 %d", rtree->ipv4_tree->count + rtree->ipv6_tree->count, + "ipv6 %d", rtree->ipv4_tree->count+rtree->ipv6_tree->count, rtree->ipv4_tree->count, rtree->ipv6_tree->count); } @@ -292,28 +292,26 @@ static int msre_op_ipmatchFromFile_execute(modsec_rec* msr, msre_rule* rule, if (res > 0) *error_msg = apr_psprintf(msr->mp, "IPmatchFromFile: \"%s\" matched at " \ - "%s.", var->value, var->name); + "%s.", var->value, var->name); return res; } /* rsub */ -static char* param_remove_escape(msre_rule* rule, char* str, int len) { - char* parm = apr_pcalloc(rule->ruleset->mp, len); - char* ret = parm; +static char *param_remove_escape(msre_rule *rule, char *str, int len) { + char *parm = apr_pcalloc(rule->ruleset->mp, len); + char *ret = parm; - for (; *str != '\0'; str++) { - if (*str != '\\') { + for(;*str!='\0';str++) { + if(*str != '\\') { *parm++ = *str; - } - else { + } else { str++; - if (*str != '/') { + if(*str != '/') { str--; *parm++ = *str; - } - else { + } else { *parm++ = *str; } } @@ -333,20 +331,20 @@ static char* param_remove_escape(msre_rule* rule, char* str, int len) { * \retval 0 On Fail */ #if !defined(MSC_TEST) -static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { +static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 - ap_regex_t* regex; + ap_regex_t *regex; #else - regex_t* regex; + regex_t *regex; #endif - const char* pattern = NULL; - const char* line = NULL; - char* reg_pattern = NULL; - char* replace = NULL; - char* e_pattern = NULL; - char* parsed_replace = NULL; - char* flags = NULL; - char* data = NULL; + const char *pattern = NULL; + const char *line = NULL; + char *reg_pattern = NULL; + char *replace = NULL; + char *e_pattern = NULL; + char *parsed_replace = NULL; + char *flags = NULL; + char *data = NULL; char delim; int ignore_case = 0; unsigned short int op_len = 0; @@ -368,10 +366,10 @@ static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { if (reg_pattern) { if (*data != delim) { - for (; *data != '\0'; data++) { - if (*data == delim) { + for(;*data != '\0' ;data++) { + if(*data == delim) { data--; - if (*data == '\\') { + if(*data == '\\') { data++; continue; } @@ -391,10 +389,10 @@ static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { if (replace) { if (*data != delim) { - for (; *data != '\0'; data++) { - if (*data == delim) { + for(;*data != '\0' ;data++) { + if(*data == delim) { data--; - if (*data == '\\') { + if(*data == '\\') { data++; continue; } @@ -419,7 +417,7 @@ static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { parsed_replace = apr_pstrdup(rule->ruleset->mp, parse_pm_content(param_remove_escape(rule, replace, strlen(replace)), op_len, rule, error_msg)); - if (!parsed_replace) { + if(!parsed_replace) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error rsub operator parsing input data"); return -1; } @@ -442,17 +440,16 @@ static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { e_pattern = param_remove_escape(rule, reg_pattern, strlen(reg_pattern)); pattern = apr_pstrndup(rule->ruleset->mp, e_pattern, strlen(e_pattern)); - if (strstr(pattern, "%{") == NULL) { + if(strstr(pattern,"%{") == NULL) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 regex = ap_pregcomp(rule->ruleset->mp, pattern, AP_REG_EXTENDED | - (ignore_case ? AP_REG_ICASE : 0)); + (ignore_case ? AP_REG_ICASE : 0)); #else regex = ap_pregcomp(rule->ruleset->mp, pattern, REG_EXTENDED | - (ignore_case ? REG_ICASE : 0)); + (ignore_case ? REG_ICASE : 0)); #endif rule->sub_regex = regex; - } - else { + } else { rule->re_precomp = 1; rule->re_str = apr_pstrndup(rule->ruleset->mp, pattern, strlen(pattern)); rule->sub_regex = NULL; @@ -473,26 +470,26 @@ static int msre_op_rsub_param_init(msre_rule* rule, char** error_msg) { * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, char** error_msg) { +static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!str) { msr_log(msr, 1, "rsub: Memory allocation error"); return -1; } - msc_string* re_pattern = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!re_pattern) { msr_log(msr, 1, "rsub: Memory allocation error"); return -1; } - char* offset = NULL; - char* data = NULL, * pattern = NULL; - char* data_out = NULL; + char *offset = NULL; + char *data = NULL, *pattern = NULL; + char *data_out = NULL; unsigned int size = 0; - unsigned int maxsize = 0; + unsigned int maxsize=0; int output_body = 0, input_body = 0, sl; #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 ap_regmatch_t pmatch[AP_MAX_REG_MATCH]; @@ -500,51 +497,47 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, regmatch_t pmatch[AP_MAX_REG_MATCH]; #endif - * error_msg = NULL; + *error_msg = NULL; - if (strcmp(var->name, "STREAM_OUTPUT_BODY") == 0) { + if(strcmp(var->name,"STREAM_OUTPUT_BODY") == 0 ) { output_body = 1; - } - else if (strcmp(var->name, "STREAM_INPUT_BODY") == 0) { + } else if(strcmp(var->name,"STREAM_INPUT_BODY") == 0 ) { input_body = 1; - } - else { - msr_log(msr, 9, "Operator rsub only works with STREAM_* variables"); + } else { + msr_log(msr,9,"Operator rsub only works with STREAM_* variables"); return -1; } - if (rule->re_precomp == 1) { + if(rule->re_precomp == 1) { re_pattern->value = apr_pstrndup(msr->mp, rule->re_str, strlen(rule->re_str)); re_pattern->value_len = strlen(re_pattern->value); expand_macros(msr, re_pattern, rule, msr->mp); - if (strlen(re_pattern->value) > 0) { - if (rule->escape_re == 1) { + if(strlen(re_pattern->value) > 0) { + if(rule->escape_re == 1) { pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - msr_log(msr, 6, "Escaping pattern [%s]", pattern); + msr_log(msr, 6, "Escaping pattern [%s]",pattern); } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 rule->sub_regex = ap_pregcomp(msr->mp, pattern, AP_REG_EXTENDED); #else rule->sub_regex = ap_pregcomp(msr->mp, pattern, REG_EXTENDED); #endif - } - else { + } else { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 rule->sub_regex = ap_pregcomp(msr->mp, re_pattern->value, AP_REG_EXTENDED); #else rule->sub_regex = ap_pregcomp(msr->mp, re_pattern->value, REG_EXTENDED); #endif } - } - else { + } else { rule->sub_regex = NULL; } } - if (rule->sub_regex == NULL) { + if(rule->sub_regex == NULL) { *error_msg = "Internal Error: regex data is null."; return -1; } @@ -552,94 +545,93 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, str->value = apr_pstrndup(msr->mp, rule->sub_str, strlen(rule->sub_str)); str->value_len = strlen(str->value); - if (strstr(rule->sub_str, "%{") != NULL) + if(strstr(rule->sub_str,"%{") != NULL) expand_macros(msr, str, rule, msr->mp); - maxsize = var->value_len + (AP_MAX_REG_MATCH * 1024) + 1; + maxsize=var->value_len+(AP_MAX_REG_MATCH*1024)+1; nextround: - data = apr_pcalloc(msr->mp, maxsize + 1); + data = apr_pcalloc(msr->mp, maxsize+1); - if (data == NULL) { + if(data == NULL) { *error_msg = "Internal Error: cannot allocate memory"; return -1; } - data_out = data; - size = 0; - for (offset = (char*)var->value; !ap_regexec(rule->sub_regex, offset, AP_MAX_REG_MATCH, pmatch, 0); ) { + data_out=data; + size=0; + for (offset = (char*)var->value; !ap_regexec(rule->sub_regex, offset, AP_MAX_REG_MATCH, pmatch, 0); ) { //Copy of data before the regex match int i; - int s = pmatch[0].rm_so; - int p_len = pmatch[0].rm_eo - pmatch[0].rm_so; - if (size + s > maxsize) { - maxsize *= 2; + int s = pmatch [0].rm_so; + int p_len=pmatch [0].rm_eo - pmatch [0].rm_so; + if (size+s>maxsize) { + maxsize*=2; goto nextround; } - memcpy(data_out, offset, s); - data_out += s; - size += s; + memcpy(data_out,offset,s); + data_out+=s; + size+=s; //Copy of regex match with replacing data \1..\9 - for (i = 0; i < str->value_len;) { - char* x = str->value + i; + for(i=0;i<str->value_len;) { + char *x = str->value+i; if (*x == '\\' && *(x + 1) > '0' && *(x + 1) <= '9') { - int capture = *(x + 1) - 48; - int capture_len = pmatch[capture].rm_eo - pmatch[capture].rm_so; + int capture=*(x + 1) - 48; + int capture_len=pmatch[capture].rm_eo-pmatch[capture].rm_so; - if (size + capture_len > maxsize) + if (size+capture_len>maxsize) { - maxsize *= 2; + maxsize*=2; goto nextround; } - memcpy(data_out, offset + pmatch[capture].rm_so, capture_len); - data_out += capture_len; - size += capture_len; - i += 2; - } - else { - - if (size + 1 > maxsize) { - maxsize *= 2; + memcpy(data_out,offset+pmatch[capture].rm_so,capture_len); + data_out+= capture_len; + size+=capture_len; + i+=2; + } else { + + if (size+1>maxsize) { + maxsize*=2; goto nextround; } - *data_out = *(str->value + i); + *data_out=*(str->value+i); data_out++; size++; i++; } } - offset += s; - offset += p_len; + offset+=s; + offset+=p_len; } //Copy of data after the last regex match sl = strlen(offset); - if (size + sl > maxsize) { - maxsize *= 2; + if (size+sl>maxsize) { + maxsize*=2; goto nextround; } - memcpy(data_out, offset, sl); - data_out += sl; - size += sl; - *data_out = 0; + memcpy(data_out,offset,sl); + data_out+=sl; + size+=sl; + *data_out=0; - if (msr->stream_output_data != NULL && output_body == 1) { + if(msr->stream_output_data != NULL && output_body == 1) { memset(msr->stream_output_data, 0x0, msr->stream_output_length); free(msr->stream_output_data); msr->stream_output_data = NULL; msr->stream_output_length = 0; - msr->stream_output_data = (char*)malloc(size + 1); + msr->stream_output_data = (char *)malloc(size+1); - if (msr->stream_output_data == NULL) { + if(msr->stream_output_data == NULL) { return -1; } msr->stream_output_length = size; - memset(msr->stream_output_data, 0x0, size + 1); + memset(msr->stream_output_data, 0x0, size+1); msr->of_stream_changed = 1; @@ -650,20 +642,20 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, var->value = msr->stream_output_data; } - if (msr->stream_input_data != NULL && input_body == 1) { + if(msr->stream_input_data != NULL && input_body == 1) { memset(msr->stream_input_data, 0x0, msr->stream_input_length); free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; #ifdef MSC_LARGE_STREAM_INPUT - msr->stream_input_allocated_length = 0; + msr->stream_input_allocated_length = 0; - msr->stream_input_data = (char*)malloc(size); + msr->stream_input_data = (char *)malloc(size); #else - msr->stream_input_data = (char*)malloc(size + 1); + msr->stream_input_data = (char *)malloc(size+1); #endif - if (msr->stream_input_data == NULL) { + if(msr->stream_input_data == NULL) { return -1; } @@ -672,7 +664,7 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, msr->stream_input_allocated_length = size; memset(msr->stream_input_data, 0x0, size); #else - memset(msr->stream_input_data, 0x0, size + 1); + memset(msr->stream_input_data, 0x0, size+1); #endif msr->if_stream_changed = 1; @@ -685,7 +677,7 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, var->value = msr->stream_input_data; } - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Operator rsub succeeded."); } @@ -702,22 +694,22 @@ static int msre_op_rsub_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, * \retval 1 On success * \retval 0 On fail */ -static int msre_op_validateHash_param_init(msre_rule* rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; - msc_regex_t* regex; - const char* pattern = rule->op_param; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + msc_regex_t *regex; + const char *pattern = rule->op_param; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int rc, jit; -#endif -#endif + #endif + #endif if (error_msg == NULL) return -1; *error_msg = NULL; /* Compile pattern */ - if (strstr(pattern, "%{") == NULL) { + if(strstr(pattern,"%{") == NULL) { #ifdef WITH_PCRE2 int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else @@ -726,33 +718,32 @@ static int msre_op_validateHash_param_init(msre_rule* rule, char** error_msg) { regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(rule->ruleset->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); } -#endif -#endif + #endif + #endif rule->op_param_data = regex; - } - else { + } else { rule->re_precomp = 1; rule->re_str = apr_pstrndup(rule->ruleset->mp, pattern, strlen(pattern)); rule->op_param_data = NULL; @@ -772,44 +763,43 @@ static int msre_op_validateHash_param_init(msre_rule* rule, char** error_msg) { * \retval 1 On success * \retval 0 On fail */ -static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_var* var, char** error_msg) { +static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; - msc_string* re_pattern = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!re_pattern) { msr_log(msr, 1, "validateHash: Memory allocation error"); return -1; } - const char* target; - const char* errptr = NULL; + const char *target; + const char *errptr = NULL; int erroffset; int options = 0; unsigned int target_length; - char* my_error_msg = NULL; + char *my_error_msg = NULL; int ovector[33]; int rc; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int jit; -#endif -#endif + #endif + #endif - * error_msg = NULL; + *error_msg = NULL; if (msr->txcfg->hash_enforcement == HASH_DISABLED || msr->txcfg->hash_is_enabled == HASH_DISABLED) return 0; if (regex == NULL) { - if (rule->re_precomp == 0) { + if(rule->re_precomp == 0) { *error_msg = "Internal Error: regex data is null."; return -1; - } - else { + } else { - if (re_pattern == NULL) { + if(re_pattern == NULL) { *error_msg = "Internal Error: regex variable data is null."; return -1; } @@ -819,9 +809,9 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v expand_macros(msr, re_pattern, rule, msr->mp); - const char* pattern = log_escape_re(msr->mp, re_pattern->value); + const char *pattern = log_escape_re(msr->mp, re_pattern->value); if (msr->txcfg->debuglog_level >= 6) { - msr_log(msr, 6, "Escaping pattern [%s]", pattern); + msr_log(msr, 6, "Escaping pattern [%s]",pattern); } #ifdef WITH_PCRE2 @@ -830,35 +820,35 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; #endif regex = msc_pregcomp_ex(msr->mp, pattern, options, &errptr, - &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); + &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); msr_log(msr, 4, "%s.", *error_msg); } } -#endif -#endif + #endif + #endif } } @@ -869,8 +859,7 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -884,7 +873,7 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { #endif - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); @@ -893,15 +882,15 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; - apr_table_setn(msr->tx_vars, s->name, (void*)s); + apr_table_setn(msr->tx_vars, s->name, (void *)s); *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "PCRE limits exceeded (%d): %s", - rule, ((rule->actionset != NULL) && (rule->actionset->id != NULL)) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc, my_error_msg); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "PCRE limits exceeded (%d): %s", + rule,((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc, my_error_msg); msr_log(msr, 3, "%s.", *error_msg); @@ -909,7 +898,7 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v } else if (rc < -1) { *error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", - rc, my_error_msg); + rc, my_error_msg); return -1; } @@ -919,58 +908,54 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ #endif /* We no longer escape the pattern here as it is done when logging */ - char* pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); - char* hmac = NULL, * valid = NULL; - char* hash_link = NULL, * nlink = NULL; + char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); + char *hmac = NULL, *valid = NULL; + char *hash_link = NULL, *nlink = NULL; if (strlen(pattern) > 252) { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s.", - pattern, var->name); - } - else { + pattern, var->name); + } else { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s.", - pattern, var->name); + pattern, var->name); } valid = strstr(target, msr->txcfg->crypto_param_name); - if (valid == NULL) { + if(valid == NULL) { if (msr->txcfg->debuglog_level >= 9) msr_log(msr, 9, "Request URI without hash parameter [%s]", target); if (strlen(pattern) > 252) { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. No Hash parameter", - pattern, var->name); - } - else { + pattern, var->name); + } else { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. No Hash parameter", - pattern, var->name); + pattern, var->name); } return 1; - } - else { + } else { - if (strlen(valid) < strlen(msr->txcfg->crypto_param_name) + 1) + if(strlen(valid) < strlen(msr->txcfg->crypto_param_name)+1) return 1; - hmac = valid + strlen(msr->txcfg->crypto_param_name) + 1; + hmac = valid+strlen(msr->txcfg->crypto_param_name)+1; nlink = apr_pstrmemdup(msr->mp, target, strlen(target) - strlen(valid) - 1); - msr_log(msr, 9, "Validating URI %s size %zu", nlink, strlen(nlink)); + msr_log(msr, 9, "Validating URI %s size %zu",nlink,strlen(nlink)); - hash_link = do_hash_link(msr, (char*)nlink, HASH_ONLY); + hash_link = do_hash_link(msr, (char *)nlink, HASH_ONLY); - if (strcmp(hmac, hash_link) != 0) { + if(strcmp(hmac, hash_link) != 0) { if (strlen(pattern) > 252) { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%.252s ...\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]", - pattern, var->name, hmac, hash_link); - } - else { + pattern, var->name, hmac, hash_link); + } else { *error_msg = apr_psprintf(msr->mp, "Request URI matched \"%s\" at %s. Hash parameter hash value = [%s] Requested URI hash value = [%s]", - pattern, var->name, hmac, hash_link); + pattern, var->name, hmac, hash_link); } return 1; } @@ -980,26 +965,26 @@ static int msre_op_validateHash_execute(modsec_rec* msr, msre_rule* rule, msre_v } return 0; - } +} /* rx */ -static int msre_op_rx_param_init(msre_rule * rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; - msc_regex_t* regex; - const char* pattern = rule->op_param; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + msc_regex_t *regex; + const char *pattern = rule->op_param; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int rc, jit; -#endif -#endif + #endif + #endif if (error_msg == NULL) return -1; *error_msg = NULL; /* Compile pattern */ - if (strstr(pattern, "%{") == NULL) { + if(strstr(pattern,"%{") == NULL) { #ifdef WITH_PCRE2 int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else @@ -1008,33 +993,32 @@ static int msre_op_rx_param_init(msre_rule * rule, char** error_msg) { regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(rule->ruleset->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); } -#endif -#endif + #endif + #endif rule->op_param_data = regex; - } - else { + } else { rule->re_precomp = 1; rule->re_str = apr_pstrndup(rule->ruleset->mp, pattern, strlen(pattern)); rule->op_param_data = NULL; @@ -1043,52 +1027,51 @@ static int msre_op_rx_param_init(msre_rule * rule, char** error_msg) { return 1; /* OK */ } -static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; if (!regex) { msr_log(msr, 1, "rx: Memory allocation error"); return -1; } - msc_string* re_pattern = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!re_pattern) { msr_log(msr, 1, "rx: Memory allocation error"); return -1; } - const char* target; - const char* errptr = NULL; + const char *target; + const char *errptr = NULL; int erroffset; int options = 0; unsigned int target_length; - char* my_error_msg = NULL; + char *my_error_msg = NULL; int ovector[33]; int capture = 0; int matched_bytes = 0; int matched = 0; int rc; - char* qspos = NULL; - const char* parm = NULL; - msc_parm* mparm = NULL; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + char *qspos = NULL; + const char *parm = NULL; + msc_parm *mparm = NULL; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int jit; -#endif -#endif + #endif + #endif - * error_msg = NULL; + *error_msg = NULL; if (regex == NULL) { - if (rule->re_precomp == 0) { + if(rule->re_precomp == 0) { *error_msg = "Internal Error: regex data is null."; return -1; - } - else { + } else { - if (re_pattern == NULL) { + if(re_pattern == NULL) { *error_msg = "Internal Error: regex variable data is null."; return -1; } @@ -1099,44 +1082,44 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var expand_macros(msr, re_pattern, rule, msr->mp); if (msr->txcfg->debuglog_level >= 6) { - char* pattern = log_escape_re(msr->mp, re_pattern->value); - msr_log(msr, 6, "Expanded-macro pattern [%s]", pattern); + char *pattern = log_escape_re(msr->mp, re_pattern->value); + msr_log(msr, 6, "Expanded-macro pattern [%s]",pattern); } #ifdef WITH_PCRE2 - options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; + options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else - options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; + options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; #endif regex = msc_pregcomp_ex(msr->mp, re_pattern->value, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(msr->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); msr_log(msr, 4, "%s.", *error_msg); } } -#endif -#endif + #endif + #endif } @@ -1149,8 +1132,7 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -1192,7 +1174,7 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { #endif - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); @@ -1201,15 +1183,15 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; - apr_table_setn(msr->tx_vars, s->name, (void*)s); + apr_table_setn(msr->tx_vars, s->name, (void *)s); *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "PCRE limits exceeded (%d): %s", - rule, ((rule->actionset != NULL) && (rule->actionset->id != NULL)) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc, my_error_msg); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "PCRE limits exceeded (%d): %s", + rule,((rule->actionset != NULL)&&(rule->actionset->id != NULL)) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc, my_error_msg); msr_log(msr, 3, "%s.", *error_msg); @@ -1217,7 +1199,7 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var } else if (rc < -1) { *error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", - rc, my_error_msg); + rc, my_error_msg); return -1; } @@ -1238,47 +1220,46 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var apr_table_unset(msr->tx_vars, "9"); /* Use the available captures. */ - for (i = 0; i < rc; i++) { - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + for(i = 0; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_psprintf(msr->mp, "%d", i); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrmemdup(msr->mp, - target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]); + target + ovector[2 * i], ovector[2 * i + 1] - ovector[2 * i]); if (s->value == NULL) return -1; s->value_len = (ovector[2 * i + 1] - ovector[2 * i]); - apr_table_addn(msr->tx_vars, s->name, (void*)s); + apr_table_addn(msr->tx_vars, s->name, (void *)s); - if (((matched == 1) || (matched_bytes == 1)) && (var != NULL) && (var->name != NULL)) { + if(((matched == 1) || (matched_bytes == 1)) && (var != NULL) && (var->name != NULL)) { qspos = apr_psprintf(msr->mp, "%s", var->name); parm = strstr(qspos, ":"); - if (parm != NULL) { + if (parm != NULL) { parm++; mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); mparm->pad_1 = rule->actionset->arg_min; mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void*)mparm); - } - else { + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void*)mparm); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); } } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); + log_escape_nq_ex(msr->mp, s->value, s->value_len)); } } } @@ -1289,16 +1270,15 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ #endif /* We no longer escape the pattern here as it is done when logging */ - char* pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); + char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "<Unknown Match>")); /* This message will be logged. */ if (strlen(pattern) > 252) { *error_msg = apr_psprintf(msr->mp, "Pattern match \"%.252s ...\" at %s.", - pattern, var->name); - } - else { + pattern, var->name); + } else { *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.", - pattern, var->name); + pattern, var->name); } return 1; @@ -1306,17 +1286,17 @@ static int msre_op_rx_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /* No match. */ return 0; - } +} /* pm */ -static int msre_op_pm_param_init(msre_rule * rule, char** error_msg) { - ACMP* p; - const char* phrase; - const char* next; +static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) { + ACMP *p; + const char *phrase; + const char *next; unsigned short int op_len; - if ((rule->op_param == NULL) || (strlen(rule->op_param) == 0)) { + if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'."); return 0; /* ERROR */ } @@ -1328,16 +1308,16 @@ static int msre_op_pm_param_init(msre_rule * rule, char** error_msg) { phrase = apr_pstrdup(rule->ruleset->mp, parse_pm_content(rule->op_param, op_len, rule, error_msg)); - if (phrase == NULL) + if(phrase == NULL) phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param); /* Loop through phrases */ /* ENH: Need to allow quoted phrases w/space */ for (;;) { - while ((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++; + while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++; if (*phrase == '\0') break; next = phrase; - while ((apr_isspace(*next) == 0) && (*next != 0)) next++; + while((apr_isspace(*next) == 0) && (*next != 0)) next++; acmp_add_pattern(p, phrase, NULL, NULL, next - phrase); phrase = next; } @@ -1348,21 +1328,21 @@ static int msre_op_pm_param_init(msre_rule * rule, char** error_msg) { /* pmFromFile */ -static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { +static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { char errstr[1024]; char buf[HUGE_STRING_LEN + 1]; - char* fn = NULL; - char* next = NULL; - char* start = NULL; - char* end = NULL; - const char* rulefile_path; - char* processed = NULL; + char *fn = NULL; + char *next = NULL; + char *start = NULL; + char *end = NULL; + const char *rulefile_path; + char *processed = NULL; unsigned short int op_len; apr_status_t rc; - apr_file_t* fd = NULL; - ACMP* p; + apr_file_t *fd = NULL; + ACMP *p; - if ((rule->op_param == NULL) || (strlen(rule->op_param) == 0)) { + if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pmFromFile'."); return 0; /* ERROR */ } @@ -1375,23 +1355,23 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { /* Get the path of the rule filename to use as a base */ rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename))); -#ifdef DEBUG_CONF + #ifdef DEBUG_CONF fprintf(stderr, "Rulefile path: \"%s\"\n", rulefile_path); -#endif + #endif /* Loop through filenames */ /* ENH: Need to allow quoted filenames w/space */ for (;;) { - const char* rootpath = NULL; - const char* filepath = NULL; + const char *rootpath = NULL; + const char *filepath = NULL; int line = 0; /* Trim whitespace */ - while ((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++; + while((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++; if (*fn == '\0') break; next = fn; - while ((apr_isspace(*next) == 0) && (*next != '\0')) next++; - while ((apr_isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0'; + while((apr_isspace(*next) == 0) && (*next != '\0')) next++; + while((apr_isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0'; /* Add path of the rule filename for a relative phrase filename */ filepath = fn; @@ -1408,13 +1388,13 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { { #ifdef WITH_CURL int res = 0; - char* word = NULL; - char* brkt = NULL; - char* sep = "\n"; + char *word = NULL; + char *brkt = NULL; + char *sep = "\n"; struct msc_curl_memory_buffer_t chunk; res = msc_remote_download_content(rule->ruleset->mp, fn, NULL, - &chunk, error_msg); + &chunk, error_msg); if (res == -2) { /* If download failed but SecRemoteRulesFailAction is set to Warn. */ @@ -1426,8 +1406,8 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { } for (word = strtok_r(chunk.memory, sep, &brkt); - word; - word = strtok_r(NULL, sep, &brkt)) + word; + word = strtok_r(NULL, sep, &brkt)) { /* Ignore empty lines and comments */ if (*word == '#') continue; @@ -1436,7 +1416,7 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { } msc_remote_clean_chunk(&chunk); #else - * error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ + *error_msg = apr_psprintf(rule->ruleset->mp, "ModSecurity was not " \ "compiled with Curl support, it cannot load: \"%s\"", fn); return 0; #endif @@ -1456,12 +1436,12 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { return 0; } -#ifdef DEBUG_CONF + #ifdef DEBUG_CONF fprintf(stderr, "Loading phrase file: \"%s\"\n", fn); -#endif + #endif /* Read one pattern per line skipping empty/commented */ - for (;;) { + for(;;) { line++; rc = apr_file_gets(buf, HUGE_STRING_LEN, fd); if (rc == APR_EOF) break; @@ -1474,13 +1454,13 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { processed = apr_pstrdup(rule->ruleset->mp, parse_pm_content(buf, op_len, rule, error_msg)); /* Trim Whitespace */ - if (processed != NULL) + if(processed != NULL) start = processed; else start = buf; while ((apr_isspace(*start) != 0) && (*start != '\0')) start++; - if (processed != NULL) + if(processed != NULL) end = processed + strlen(processed); else end = buf + strlen(buf); @@ -1507,13 +1487,13 @@ static int msre_op_pmFromFile_param_init(msre_rule * rule, char** error_msg) { return 1; } -static int msre_op_pm_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); assert(var != NULL); assert(error_msg != NULL); - const char* match = NULL; + const char *match = NULL; apr_status_t rc = 0; int capture; ACMPT pt; @@ -1536,27 +1516,26 @@ static int msre_op_pm_execute(modsec_rec * msr, msre_rule * rule, msre_var * var return 0; } - pt.parser = (ACMP*)rule->op_param_data; + pt.parser = (ACMP *)rule->op_param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, var->value, var->value_len); if (rc) { - char* match_escaped = log_escape(msr->mp, match ? match : "<Unknown Match>"); + char *match_escaped = log_escape(msr->mp, match ? match : "<Unknown Match>"); /* This message will be logged. */ if (strlen(match_escaped) > 252) { *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %s.", - match_escaped, var->name); - } - else { + match_escaped, var->name); + } else { *error_msg = apr_psprintf(msr->mp, "Matched phrase \"%s\" at %s.", - match_escaped, var->name); + match_escaped, var->name); } /* Handle capture as tx.0=match */ if (capture) { int i; - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; @@ -1565,15 +1544,15 @@ static int msre_op_pm_execute(modsec_rec * msr, msre_rule * rule, msre_var * var s->value = apr_pstrdup(msr->mp, match); if (s->value == NULL) return -1; s->value_len = strlen(s->value); - apr_table_setn(msr->tx_vars, s->name, (void*)s); + apr_table_setn(msr->tx_vars, s->name, (void *)s); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Added phrase match to TX.0: %s", - log_escape_nq_ex(msr->mp, s->value, s->value_len)); + log_escape_nq_ex(msr->mp, s->value, s->value_len)); } /* Unset the remaining ones (from previous invocations). */ - for (i = rc; i <= 9; i++) { + for(i = rc; i <= 9; i++) { char buf[2]; apr_snprintf(buf, sizeof(buf), "%d", i); apr_table_unset(msr->tx_vars, buf); @@ -1596,30 +1575,30 @@ static int msre_op_pm_execute(modsec_rec * msr, msre_rule * rule, msre_var * var * \retval domain On Failure * \retval url On Success */ -static const char* gsb_replace_tpath(apr_pool_t * pool, const char* domain, int len) { +static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int len) { - char* pos = NULL, * data = NULL; - char* url = NULL; + char *pos = NULL, *data = NULL; + char *url = NULL; int match = 0; url = apr_palloc(pool, len + 1); data = apr_palloc(pool, len + 1); - memset(data, 0, len + 1); - memset(url, 0, len + 1); + memset(data, 0, len+1); + memset(url, 0, len+1); memcpy(url, domain, len); - while ((pos = strstr(url, "/./")) != NULL) { + while(( pos = strstr(url , "/./" )) != NULL) { match = 1; data[0] = '\0'; strncat(data, url, pos - url); - strcat(data, "/"); - strcat(data, pos + strlen("/./")); - strncpy(url, data, len); + strcat(data , "/"); + strcat(data ,pos + strlen("/./")); + strncpy(url , data, len); } - if (match == 0) + if(match == 0) return domain; return url; @@ -1634,44 +1613,44 @@ static const char* gsb_replace_tpath(apr_pool_t * pool, const char* domain, int * \retval domain On Failure * \retval reduced On Success */ -static const char* gsb_reduce_char(apr_pool_t * pool, const char* domain) { +static const char *gsb_reduce_char(apr_pool_t *pool, const char *domain) { - char* ptr = apr_pstrdup(pool, domain); - char* data = NULL; - char* reduced = NULL; + char *ptr = apr_pstrdup(pool, domain); + char *data = NULL; + char *reduced = NULL; int skip = 0; - if (ptr == NULL) + if(ptr == NULL) return domain; data = apr_pcalloc(pool, strlen(ptr)); - if (data == NULL) + if(data == NULL) return domain; reduced = data; - while (*ptr != '\0') { + while(*ptr != '\0') { - switch (*ptr) { - case '.': - ptr++; - if (*ptr == '.') - skip = 1; + switch(*ptr) { + case '.': + ptr++; + if(*ptr == '.') + skip = 1; - ptr--; - break; - case '/': - ptr++; - if (*ptr == '/') - skip = 1; + ptr--; + break; + case '/': + ptr++; + if(*ptr == '/') + skip = 1; - ptr--; - break; + ptr--; + break; } - if (skip == 0) { + if(skip == 0) { *data = *ptr; data++; } @@ -1681,7 +1660,7 @@ static const char* gsb_reduce_char(apr_pool_t * pool, const char* domain) { *data = '\0'; --data; - if (*data == '.') + if(*data == '.') *data = '\0'; else ++data; @@ -1701,15 +1680,15 @@ static const char* gsb_reduce_char(apr_pool_t * pool, const char* domain) { * \retval 1 On Match * \retval 0 On No Match */ -static int verify_gsb(gsb_db * gsb, modsec_rec * msr, const char* match, unsigned int match_length) { +static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned int match_length) { assert(gsb != NULL); assert(msr != NULL); assert(match != NULL); apr_md5_ctx_t ctx; apr_status_t rc; unsigned char digest[APR_MD5_DIGESTSIZE]; - const char* hash = NULL; - const char* search = NULL; + const char *hash = NULL; + const char *search = NULL; memset(digest, 0, sizeof(digest)); @@ -1722,7 +1701,7 @@ static int verify_gsb(gsb_db * gsb, modsec_rec * msr, const char* match, unsigne hash = apr_psprintf(msr->mp, "%s", bytes2hex(msr->mp, digest, 16)); - if ((hash != NULL) && (gsb->gsb_table != NULL)) { + if ((hash != NULL) && (gsb->gsb_table != NULL)) { search = apr_hash_get(gsb->gsb_table, hash, APR_HASH_KEY_STRING); if (search != NULL) @@ -1741,11 +1720,11 @@ static int verify_gsb(gsb_db * gsb, modsec_rec * msr, const char* match, unsigne * \retval 1 On Success * \retval 0 On Fail */ -static int msre_op_gsbLookup_param_init(msre_rule * rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; int options = 0; - msc_regex_t* regex; + msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; @@ -1760,7 +1739,7 @@ static int msre_op_gsbLookup_param_init(msre_rule * rule, char** error_msg) { if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } @@ -1781,26 +1760,26 @@ static int msre_op_gsbLookup_param_init(msre_rule * rule, char** error_msg) { * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; - char* my_error_msg = NULL; + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + char *my_error_msg = NULL; int ovector[33]; unsigned int offset = 0; int options = 0; - gsb_db* gsb = msr->txcfg->gsb; - const char* match = NULL; + gsb_db *gsb = msr->txcfg->gsb; + const char *match = NULL; unsigned int match_length; unsigned int canon_length; int rv, i, ret, count_slash; unsigned int j = 0; unsigned int size = var->value_len; - char* base = NULL, * domain = NULL, * savedptr = NULL; - char* str = NULL, * canon = NULL, * dot = NULL; - char* data = NULL, * ptr = NULL, * url = NULL; + char *base = NULL, *domain = NULL, *savedptr = NULL; + char *str = NULL, *canon = NULL, *dot = NULL; + char *data = NULL, *ptr = NULL, *url = NULL; int capture, domain_len; int d_pos = -1; int s_pos = -1; @@ -1808,26 +1787,26 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va if (error_msg == NULL) return -1; *error_msg = NULL; - if (regex == NULL) { + if(regex == NULL) { *error_msg = "Internal Error: regex is null."; return 0; } - if (gsb == NULL) { + if(gsb == NULL) { msr_log(msr, 1, "GSB lookup failed without a database. Set SecGsbLookupDB."); return 0; } - data = apr_pcalloc(msr->mp, var->value_len + 1); + data = apr_pcalloc(msr->mp, var->value_len+1); - if (data == NULL) { + if(data == NULL) { *error_msg = "Internal Error: cannot allocate memory for data."; return -1; } capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0; - memcpy(data, var->value, var->value_len); + memcpy(data,var->value,var->value_len); #ifdef WITH_PCRE2 options = PCRE2_NOTEMPTY; @@ -1836,11 +1815,11 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va #endif while (offset < size && (rv = msc_regexec_ex(regex, data, size, offset, options, ovector, 30, &my_error_msg)) >= 0) { - for (i = 0; i < rv; ++i) + for(i = 0; i < rv; ++i) { - match = apr_psprintf(msr->mp, "%.*s", ovector[2 * i + 1] - ovector[2 * i], data + ovector[2 * i]); + match = apr_psprintf(msr->mp, "%.*s", ovector[2*i+1] - ovector[2*i], data + ovector[2*i]); - if (match == NULL) { + if (match == NULL) { *error_msg = "Internal Error: cannot allocate memory for match."; return -1; } @@ -1853,9 +1832,9 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va match_length = strlen(match); - strtolower_inplace((unsigned char*)match); + strtolower_inplace((unsigned char *)match); - if ((strstr(match, "http") == NULL) && (match_length > 0) && (strchr(match, '.'))) { + if((strstr(match,"http") == NULL) && (match_length > 0) && (strchr(match,'.'))) { /* full url */ if (msr->txcfg->debuglog_level >= 4) { @@ -1864,42 +1843,42 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va ret = verify_gsb(gsb, msr, match, match_length); - if (ret > 0) { + if(ret > 0) { set_match_to_tx(msr, capture, match, 0); - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, match)); + log_escape_nq(msr->mp, match)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; } /* append / in the end of full url */ - if ((match[match_length - 1] != '/') && (strchr(match, '?') == NULL)) { + if ((match[match_length -1] != '/') && (strchr(match,'?') == NULL)) { canon = apr_psprintf(msr->mp, "%s/", match); - if (canon != NULL) { + if (canon != NULL) { canon_length = strlen(canon); ret = verify_gsb(gsb, msr, canon, canon_length); - if (ret > 0) { + if(ret > 0) { set_match_to_tx(msr, capture, match, 0); - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, canon)); + log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; @@ -1913,54 +1892,54 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va domain_len = strlen(domain); - if (*domain != '/') { + if(*domain != '/') { - if (domain[domain_len - 1] == '.') - domain[domain_len - 1] = '\0'; - if (domain[domain_len - 1] == '/' && domain[domain_len - 2] == '.') { - domain[domain_len - 2] = '/'; - domain[domain_len - 1] = '\0'; + if(domain[domain_len-1] == '.') + domain[domain_len-1] = '\0'; + if(domain[domain_len-1] == '/' && domain[domain_len-2] == '.') { + domain[domain_len-2] = '/'; + domain[domain_len-1] = '\0'; } - dot = strchr(domain, '.'); - if (dot != NULL) { + dot = strchr(domain,'.'); + if(dot != NULL) { canon = apr_pstrdup(msr->mp, domain); ret = verify_gsb(gsb, msr, canon, strlen(canon)); - if (ret > 0) { + if(ret > 0) { set_match_to_tx(msr, capture, canon, 0); - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, canon)); + log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; } - base = apr_strtok(canon, "?", &savedptr); + base = apr_strtok(canon,"?",&savedptr); - if (base != NULL) { + if(base != NULL) { ret = verify_gsb(gsb, msr, base, strlen(base)); - if (ret > 0) { + if(ret > 0) { set_match_to_tx(msr, capture, base, 0); - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, base)); + log_escape_nq(msr->mp, base)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; @@ -1971,27 +1950,27 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va url = apr_palloc(msr->mp, strlen(canon)); count_slash = 0; - while (*canon != '\0') { - switch (*canon) { - case '/': - ptr = apr_psprintf(msr->mp, "%s/", url); - ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); - if (ret > 0) { - set_match_to_tx(msr, capture, ptr, 0); - if (!*error_msg) { - *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, ptr)); - } + while(*canon != '\0') { + switch (*canon) { + case '/': + ptr = apr_psprintf(msr->mp,"%s/",url); + ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); + if(ret > 0) { + set_match_to_tx(msr, capture, ptr, 0); + if (! *error_msg) { + *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", + log_escape_nq(msr->mp, ptr)); + } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) - set_match_to_tx(msr, capture, base, 1); - return 1; - } + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) + set_match_to_tx(msr, capture, base, 1); + return 1; + } - break; + break; } url[count_slash] = *canon; count_slash++; @@ -2002,8 +1981,8 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va /* Do the same for subdomains */ - for (j = 0; j < strlen(match); j++) { - if (match[j] == '/') { + for(j=0; j<strlen(match); j++) { + if(match[j] == '/') { s_pos = j; break; } @@ -2012,100 +1991,100 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va str = apr_pstrdup(msr->mp, match); - while (*str != '\0') { - - switch (*str) { - case '.': - domain++; - domain_len = strlen(domain); + while (*str != '\0') { - d_pos = strchr(domain, '.') - domain; + switch(*str) { + case '.': + domain++; + domain_len = strlen(domain); - if (s_pos >= 0 && d_pos >= 0 && d_pos > s_pos) - break; + d_pos = strchr(domain,'.') - domain; - if (*domain != '/') { - - if (domain[domain_len - 1] == '.') - domain[domain_len - 1] = '\0'; - if (domain[domain_len - 1] == '/' && domain[domain_len - 2] == '.') { - domain[domain_len - 2] = '/'; - domain[domain_len - 1] = '\0'; - } - - dot = strchr(domain, '.'); - if (dot != NULL) { - canon = apr_pstrdup(msr->mp, domain); - - ret = verify_gsb(gsb, msr, canon, strlen(canon)); + if(s_pos >= 0 && d_pos >= 0 && d_pos > s_pos) + break; - if (ret > 0) { - set_match_to_tx(msr, capture, canon, 0); - if (!*error_msg) { - *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, canon)); - } - str = apr_pstrdup(msr->mp, match); + if(*domain != '/') { - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) - set_match_to_tx(msr, capture, base, 1); - return 1; + if(domain[domain_len-1] == '.') + domain[domain_len-1] = '\0'; + if(domain[domain_len-1] == '/' && domain[domain_len-2] == '.') { + domain[domain_len-2] = '/'; + domain[domain_len-1] = '\0'; } + dot = strchr(domain,'.'); + if(dot != NULL) { + canon = apr_pstrdup(msr->mp, domain); - base = apr_strtok(canon, "?", &savedptr); - - if (base != NULL) { - ret = verify_gsb(gsb, msr, base, strlen(base)); + ret = verify_gsb(gsb, msr, canon, strlen(canon)); - if (ret > 0) { - set_match_to_tx(msr, capture, base, 0); - if (!*error_msg) { + if(ret > 0) { + set_match_to_tx(msr, capture, canon, 0); + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, base)); + log_escape_nq(msr->mp, canon)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; } - } - url = apr_palloc(msr->mp, strlen(canon)); - count_slash = 0; - - while (*canon != '\0') { - switch (*canon) { - case '/': - ptr = apr_psprintf(msr->mp, "%s/", url); - ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); - if (ret > 0) { - set_match_to_tx(msr, capture, ptr, 0); - if (!*error_msg) { + base = apr_strtok(canon,"?",&savedptr); + + if(base != NULL) { + ret = verify_gsb(gsb, msr, base, strlen(base)); + + if(ret > 0) { + set_match_to_tx(msr, capture, base, 0); + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", - log_escape_nq(msr->mp, ptr)); + log_escape_nq(msr->mp, base)); } - str = apr_pstrdup(msr->mp, match); + str = apr_pstrdup(msr->mp,match); - base = apr_strtok(str, "/", &savedptr); - if (base != NULL) + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) set_match_to_tx(msr, capture, base, 1); return 1; } - break; } - url[count_slash] = *canon; - count_slash++; - canon++; + + url = apr_palloc(msr->mp, strlen(canon)); + count_slash = 0; + + while(*canon != '\0') { + switch (*canon) { + case '/': + ptr = apr_psprintf(msr->mp,"%s/",url); + ret = verify_gsb(gsb, msr, ptr, strlen(ptr)); + if(ret > 0) { + set_match_to_tx(msr, capture, ptr, 0); + if (! *error_msg) { + *error_msg = apr_psprintf(msr->mp, "Gsb lookup for \"%s\" succeeded.", + log_escape_nq(msr->mp, ptr)); + } + str = apr_pstrdup(msr->mp,match); + + base = apr_strtok(str,"/",&savedptr); + if(base != NULL) + set_match_to_tx(msr, capture, base, 1); + return 1; + } + + break; + } + url[count_slash] = *canon; + count_slash++; + canon++; + } } } - } - break; + break; } domain = str; @@ -2124,17 +2103,17 @@ static int msre_op_gsbLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va /* within */ -static int msre_op_within_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); - const char* match = NULL; - const char* target; +static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; *error_msg = NULL; - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; @@ -2145,7 +2124,7 @@ static int msre_op_within_execute(modsec_rec * msr, msre_rule * rule, msre_var * expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null we give up without a match */ @@ -2161,7 +2140,7 @@ static int msre_op_within_execute(modsec_rec * msr, msre_rule * rule, msre_var * if (target_length == 0) { /* Match. */ *error_msg = apr_psprintf(msr->mp, "String match within \"\" at %s.", - var->name); + var->name); return 1; } @@ -2180,8 +2159,8 @@ static int msre_op_within_execute(modsec_rec * msr, msre_rule * rule, msre_var * if (memcmp((target + 1), (match + i + 1), (target_length - 1)) == 0) { /* match. */ *error_msg = apr_psprintf(msr->mp, "String match within \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } } @@ -2193,23 +2172,23 @@ static int msre_op_within_execute(modsec_rec * msr, msre_rule * rule, msre_var * /* contains */ -static int msre_op_contains_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - const char* match = NULL; - const char* target; + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (str == NULL) { *error_msg = "Internal Error: cannot allocate memory."; return -1; } - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2222,7 +2201,7 @@ static int msre_op_contains_execute(modsec_rec * msr, msre_rule * rule, msre_var expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null run against an empty @@ -2232,8 +2211,7 @@ static int msre_op_contains_execute(modsec_rec * msr, msre_rule * rule, msre_var if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2259,13 +2237,13 @@ static int msre_op_contains_execute(modsec_rec * msr, msre_rule * rule, msre_var /* First character matched - avoid func call */ if (target[i] == match[0]) { /* See if remaining matches */ - if ((match_length == 1) - || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) + if ( (match_length == 1) + || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) { /* Match. */ *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } } @@ -2279,8 +2257,8 @@ static int msre_op_contains_execute(modsec_rec * msr, msre_rule * rule, msre_var * links against files in libinjection directory * See www.client9.com/libinjection for details */ -static int msre_op_detectSQLi_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) { +static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); @@ -2299,17 +2277,16 @@ static int msre_op_detectSQLi_execute(modsec_rec * msr, msre_rule * rule, msre_v set_match_to_tx(msr, capture, fingerprint, 0); *error_msg = apr_psprintf(msr->mp, "detected SQLi using libinjection with fingerprint '%s'", - fingerprint); + fingerprint); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "ISSQL: libinjection fingerprint '%s' matched input '%s'", - fingerprint, - log_escape_ex(msr->mp, var->value, var->value_len)); + fingerprint, + log_escape_ex(msr->mp, var->value, var->value_len)); } - } - else { + } else { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "ISSQL: not sqli, no libinjection sqli fingerprint matched input '%s'", - log_escape_ex(msr->mp, var->value, var->value_len)); + log_escape_ex(msr->mp, var->value, var->value_len)); } } @@ -2318,8 +2295,8 @@ static int msre_op_detectSQLi_execute(modsec_rec * msr, msre_rule * rule, msre_v /** libinjection detectXSS */ -static int msre_op_detectXSS_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) { +static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); @@ -2338,8 +2315,7 @@ static int msre_op_detectXSS_execute(modsec_rec * msr, msre_rule * rule, msre_va if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "IS_XSS: libinjection detected XSS."); } - } - else { + } else { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "IS_XSS: not XSS, libinjection was not able to find any XSS."); } @@ -2351,24 +2327,24 @@ static int msre_op_detectXSS_execute(modsec_rec * msr, msre_rule * rule, msre_va /* containsWord */ -static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - const char* match = NULL; - const char* target; + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length = 0; unsigned int i, i_max; int rc = 0; - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (str == NULL) { *error_msg = "Internal Error: cannot allocate memory."; return -1; } - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2380,7 +2356,7 @@ static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null run against an empty @@ -2390,8 +2366,7 @@ static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2416,21 +2391,21 @@ static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre for (i = 0; i <= i_max; i++) { /* Previous char must have been a start or non-word */ - if ((i > 0) && (apr_isalnum(target[i - 1]) || (target[i - 1] == '_'))) + if ((i > 0) && (apr_isalnum(target[i-1])||(target[i-1] == '_'))) continue; /* First character matched - avoid func call */ if (target[i] == match[0]) { /* See if remaining matches */ - if ((match_length == 1) - || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) + if ( (match_length == 1) + || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0)) { /* check boundaries */ if (i == i_max) { /* exact/end word match */ rc = 1; } - else if (!(apr_isalnum(target[i + match_length]) || (target[i + match_length] == '_'))) { + else if (!(apr_isalnum(target[i + match_length])||(target[i + match_length] == '_'))) { /* start/mid word match */ rc = 1; } @@ -2441,8 +2416,8 @@ static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre if (rc == 1) { /* Maybe a match. */ *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } @@ -2453,22 +2428,22 @@ static int msre_op_containsWord_execute(modsec_rec * msr, msre_rule * rule, msre /* streq */ -static int msre_op_streq_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!str) { msr_log(msr, 1, "streq: Memory allocation error"); return -1; } - const char* match = NULL; - const char* target; + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length; - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2480,7 +2455,7 @@ static int msre_op_streq_execute(modsec_rec * msr, msre_rule * rule, msre_var * expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null run against an empty @@ -2490,8 +2465,7 @@ static int msre_op_streq_execute(modsec_rec * msr, msre_rule * rule, msre_var * if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2505,8 +2479,8 @@ static int msre_op_streq_execute(modsec_rec * msr, msre_rule * rule, msre_var * if (memcmp(match, target, target_length) == 0) { /* Match. */ *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } @@ -2516,22 +2490,22 @@ static int msre_op_streq_execute(modsec_rec * msr, msre_rule * rule, msre_var * /* beginsWith */ -static int msre_op_beginsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - const char* match = NULL; - const char* target; + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length; - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (str == NULL) { - *error_msg = "Internal Error: cannot allocate memory."; - return -1; - } + *error_msg = "Internal Error: cannot allocate memory."; + return -1; + } - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2544,7 +2518,7 @@ static int msre_op_beginsWith_execute(modsec_rec * msr, msre_rule * rule, msre_v expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null run against an empty @@ -2554,8 +2528,7 @@ static int msre_op_beginsWith_execute(modsec_rec * msr, msre_rule * rule, msre_v if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2576,8 +2549,8 @@ static int msre_op_beginsWith_execute(modsec_rec * msr, msre_rule * rule, msre_v if (memcmp(match, target, match_length) == 0) { /* Match. */ *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } @@ -2587,20 +2560,20 @@ static int msre_op_beginsWith_execute(modsec_rec * msr, msre_rule * rule, msre_v /* endsWith */ -static int msre_op_endsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); - const char* match = NULL; - const char* target; + const char *match = NULL; + const char *target; unsigned int match_length; unsigned int target_length; - msc_string* str = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (str == NULL) { *error_msg = "Internal Error: cannot allocate memory."; return -1; } - str->value = (char*)rule->op_param; + str->value = (char *)rule->op_param; if (str->value == NULL) { *error_msg = "Internal Error: match string is null."; return -1; @@ -2612,7 +2585,7 @@ static int msre_op_endsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var expand_macros(msr, str, rule, msr->mp); - match = (const char*)str->value; + match = (const char *)str->value; match_length = str->value_len; /* If the given target is null run against an empty @@ -2622,8 +2595,7 @@ static int msre_op_endsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2644,8 +2616,8 @@ static int msre_op_endsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var if (memcmp(match, (target + (target_length - match_length)), match_length) == 0) { /* Match. */ *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", - log_escape_ex(msr->mp, match, match_length), - var->name); + log_escape_ex(msr->mp, match, match_length), + var->name); return 1; } @@ -2655,10 +2627,10 @@ static int msre_op_endsWith_execute(modsec_rec * msr, msre_rule * rule, msre_var /* strmatch */ -static int msre_op_strmatch_param_init(msre_rule * rule, char** error_msg) { - const apr_strmatch_pattern* compiled_pattern; - char* processed = NULL; - const char* pattern = rule->op_param; +static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { + const apr_strmatch_pattern *compiled_pattern; + char *processed = NULL; + const char *pattern = rule->op_param; unsigned short int op_len; if (error_msg == NULL) return -1; @@ -2679,20 +2651,20 @@ static int msre_op_strmatch_param_init(msre_rule * rule, char** error_msg) { return 0; } - rule->op_param_data = (void*)compiled_pattern; + rule->op_param_data = (void *)compiled_pattern; return 1; /* OK */ } -static int msre_op_strmatch_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - apr_strmatch_pattern* compiled_pattern = (apr_strmatch_pattern*)rule->op_param_data; - const char* target; + apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; + const char *target; unsigned int target_length; - const char* rc; + const char *rc; *error_msg = NULL; @@ -2708,8 +2680,7 @@ static int msre_op_strmatch_execute(modsec_rec * msr, msre_rule * rule, msre_var if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -2721,7 +2692,7 @@ static int msre_op_strmatch_execute(modsec_rec * msr, msre_rule * rule, msre_var } *error_msg = apr_psprintf(msr->mp, "Pattern match \"%s\" at %s.", - log_escape(msr->mp, rule->op_param), var->name); + log_escape(msr->mp, rule->op_param), var->name); /* Match. */ return 1; @@ -2729,13 +2700,13 @@ static int msre_op_strmatch_execute(modsec_rec * msr, msre_rule * rule, msre_var /* validateDTD */ -static int msre_op_validateDTD_init(msre_rule * rule, char** error_msg) { +static int msre_op_validateDTD_init(msre_rule *rule, char **error_msg) { /* ENH Verify here the file actually exists. */ return 1; } -static int msre_op_validateDTD_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_validateDTD_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -2744,27 +2715,27 @@ static int msre_op_validateDTD_execute(modsec_rec * msr, msre_rule * rule, msre_ xmlValidCtxtPtr cvp; xmlDtdPtr dtd; - if ((msr->xml == NULL) || (msr->xml->doc == NULL)) { + if ((msr->xml == NULL)||(msr->xml->doc == NULL)) { *error_msg = apr_psprintf(msr->mp, - "XML document tree could not be found for DTD validation."); + "XML document tree could not be found for DTD validation."); return -1; } if (msr->xml->well_formed != 1) { *error_msg = apr_psprintf(msr->mp, - "XML: DTD validation failed because content is not well formed."); + "XML: DTD validation failed because content is not well formed."); return 1; } /* Make sure there were no other generic processing errors */ if (msr->msc_reqbody_error) { *error_msg = apr_psprintf(msr->mp, - "XML: DTD validation could not proceed due to previous" - " processing errors."); + "XML: DTD validation could not proceed due to previous" + " processing errors."); return 1; } - dtd = xmlParseDTD(NULL, (const xmlChar*)rule->op_param); /* EHN support relative filenames */ + dtd = xmlParseDTD(NULL, (const xmlChar *)rule->op_param); /* EHN support relative filenames */ if (dtd == NULL) { *error_msg = apr_psprintf(msr->mp, "XML: Failed to load DTD: %s", rule->op_param); return -1; @@ -2803,13 +2774,13 @@ static int msre_op_validateDTD_execute(modsec_rec * msr, msre_rule * rule, msre_ /* validateSchema */ -static int msre_op_validateSchema_init(msre_rule * rule, char** error_msg) { +static int msre_op_validateSchema_init(msre_rule *rule, char **error_msg) { /* ENH Verify here the file actually exists. */ return 1; } -static int msre_op_validateSchema_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -2820,30 +2791,30 @@ static int msre_op_validateSchema_execute(modsec_rec * msr, msre_rule * rule, ms xmlSchemaPtr schema; int rc; - if ((msr->xml == NULL) || (msr->xml->doc == NULL)) { + if ((msr->xml == NULL)||(msr->xml->doc == NULL)) { *error_msg = apr_psprintf(msr->mp, - "XML document tree could not be found for schema validation."); + "XML document tree could not be found for schema validation."); return -1; } if (msr->xml->well_formed != 1) { *error_msg = apr_psprintf(msr->mp, - "XML: Schema validation failed because content is not well formed."); + "XML: Schema validation failed because content is not well formed."); return 1; } /* Make sure there were no other generic processing errors */ if (msr->msc_reqbody_error) { *error_msg = apr_psprintf(msr->mp, - "XML: Schema validation could not proceed due to previous" - " processing errors."); + "XML: Schema validation could not proceed due to previous" + " processing errors."); return 1; } parserCtx = xmlSchemaNewParserCtxt(rule->op_param); /* ENH support relative filenames */ if (parserCtx == NULL) { *error_msg = apr_psprintf(msr->mp, "XML: Failed to load Schema from file: %s", - rule->op_param); + rule->op_param); return -1; } @@ -2891,7 +2862,7 @@ static int msre_op_validateSchema_execute(modsec_rec * msr, msre_rule * rule, ms /** * Luhn Mod-10 Method (ISO 2894/ANSI 4.13) */ -static int luhn_verify(const char* ccnumber, int len) { +static int luhn_verify(const char *ccnumber, int len) { int sum[2] = { 0, 0 }; int odd = 0; int digits = 0; @@ -2900,7 +2871,7 @@ static int luhn_verify(const char* ccnumber, int len) { /* Weighted lookup table which is just a precalculated (i = index): * i*2 + (( (i*2) > 9 ) ? -9 : 0) */ - static const int wtable[10] = { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 }; /* weight lookup table */ + static const int wtable[10] = {0, 2, 4, 6, 8, 1, 3, 5, 7, 9}; /* weight lookup table */ /* Add up only digits (weighted digits via lookup table) * for both odd and even CC numbers to avoid 2 passes. @@ -2924,11 +2895,11 @@ static int luhn_verify(const char* ccnumber, int len) { return sum[odd] ? 0 : 1; } -static int msre_op_verifyCC_init(msre_rule * rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; int options = 0; - msc_regex_t* regex; + msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; @@ -2942,7 +2913,7 @@ static int msre_op_verifyCC_init(msre_rule * rule, char** error_msg) { regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } @@ -2951,31 +2922,31 @@ static int msre_op_verifyCC_init(msre_rule * rule, char** error_msg) { return 1; /* OK */ } -static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; - const char* target; + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + const char *target; unsigned int target_length; - char* my_error_msg = NULL; + char *my_error_msg = NULL; int ovector[33]; int rc; int is_cc = 0; int offset; int options = 0; int matched_bytes = 0; - char* qspos = NULL; - const char* parm = NULL; - msc_parm* mparm = NULL; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + char *qspos = NULL; + const char *parm = NULL; + msc_parm *mparm = NULL; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int jit; -#endif -#endif + #endif + #endif - * error_msg = NULL; + *error_msg = NULL; if (regex == NULL) { *error_msg = "Internal Error: regex data is null."; @@ -2986,28 +2957,28 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var memset(ovector, 0, sizeof(ovector)); -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); msr_log(msr, 4, "%s.", *error_msg); } } -#endif -#endif + #endif + #endif /* If the given target is null run against an empty @@ -3017,8 +2988,7 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -3053,11 +3023,11 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var /* Verify a match. */ if (rc > 0) { - const char* match = target + ovector[0]; + const char *match = target + ovector[0]; int length = ovector[1] - ovector[0]; int i = 0; - offset = ovector[2 * i]; + offset = ovector[2*i]; /* Check the Luhn using the match string */ is_cc = luhn_verify(match, length); @@ -3076,12 +3046,12 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var */ matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if (!matched_bytes) + if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; if (apr_table_get(rule->actionset->actions, "capture")) { - for (; i < rc; i++) { - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_psprintf(msr->mp, "%d", i); if (s->name == NULL) return -1; @@ -3090,34 +3060,33 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var if (s->value == NULL) return -1; s->value_len = length; - apr_table_setn(msr->tx_vars, s->name, (void*)s); + apr_table_setn(msr->tx_vars, s->name, (void *)s); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, - log_escape_nq_ex(msr->mp, s->value, s->value_len)); + log_escape_nq_ex(msr->mp, s->value, s->value_len)); } - if ((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { qspos = apr_psprintf(msr->mp, "%s", var->name); parm = strstr(qspos, ":"); - if (parm != NULL) { + if (parm != NULL) { parm++; mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); mparm->pad_1 = rule->actionset->arg_min; mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void*)mparm); - } - else { + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void*)mparm); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); } } @@ -3125,7 +3094,7 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var } /* Unset the remaining TX vars (from previous invocations). */ - for (; i <= 9; i++) { + for(; i <= 9; i++) { char buf[24]; apr_snprintf(buf, sizeof(buf), "%i", i); apr_table_unset(msr->tx_vars, buf); @@ -3133,21 +3102,21 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var break; } - } + } if (is_cc) { /* Match. */ /* This message will be logged. */ *error_msg = apr_psprintf(msr->mp, "CC# match \"%s\" at %s. [offset \"%d\"]", - regex->pattern, var->name, offset); + regex->pattern, var->name, offset); return 1; } /* No match. */ return 0; - } +} /** * \brief Check for a valid CPF @@ -3158,7 +3127,7 @@ static int msre_op_verifyCC_execute(modsec_rec * msr, msre_rule * rule, msre_var * \retval 0 On Invalid CPF * \retval 1 On Valid CPF */ -static int cpf_verify(const char* cpfnumber, int len) { +static int cpf_verify(const char *cpfnumber, int len) { int factor, part_1, part_2, var_len = len; unsigned int sum = 0, i = 0, cpf_len = 11, c; @@ -3174,12 +3143,12 @@ static int cpf_verify(const char* cpfnumber, int len) { "66666666666", "77777777777", "88888888888", - "99999999999" }; + "99999999999"}; - while ((*cpfnumber != '\0') && (var_len > 0)) { + while((*cpfnumber != '\0') && ( var_len > 0)) { - if (*cpfnumber != '-' || *cpfnumber != '.') { - if (i < cpf_len && isdigit(*cpfnumber)) { + if(*cpfnumber != '-' || *cpfnumber != '.') { + if(i < cpf_len && isdigit(*cpfnumber)) { s_cpf[i] = *cpfnumber; cpf[i] = convert_to_int(*cpfnumber); i++; @@ -3193,47 +3162,45 @@ static int cpf_verify(const char* cpfnumber, int len) { if (i != cpf_len) return 0; else { - for (i = 0; i < cpf_len; i++) { - if (strncmp(s_cpf, bad_cpf[i], cpf_len) == 0) { + for(i = 0; i< cpf_len; i++) { + if(strncmp(s_cpf,bad_cpf[i],cpf_len) == 0) { return 0; } } } - part_1 = convert_to_int(s_cpf[cpf_len - 2]); - part_2 = convert_to_int(s_cpf[cpf_len - 1]); + part_1 = convert_to_int(s_cpf[cpf_len-2]); + part_2 = convert_to_int(s_cpf[cpf_len-1]); c = cpf_len; - for (i = 0; i < 9; i++) { + for(i = 0; i < 9; i++) { sum += (cpf[i] * --c); } factor = (sum % cpf_len); - if (factor < 2) { + if(factor < 2) { cpf[9] = 0; - } - else { - cpf[9] = cpf_len - factor; + } else { + cpf[9] = cpf_len-factor; } sum = 0; c = cpf_len; - for (i = 0; i < 10; i++) + for(i = 0;i < 10; i++) sum += (cpf[i] * c--); factor = (sum % cpf_len); - if (factor < 2) { + if(factor < 2) { cpf[10] = 0; - } - else { - cpf[10] = cpf_len - factor; + } else { + cpf[10] = cpf_len-factor; } - if (part_1 == cpf[9] && part_2 == cpf[10]) + if(part_1 == cpf[9] && part_2 == cpf[10]) return 1; return 0; @@ -3248,11 +3215,11 @@ static int cpf_verify(const char* cpfnumber, int len) { * \retval 0 On Failure * \retval 1 On Success */ -static int msre_op_verifyCPF_init(msre_rule * rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; int options = 0; - msc_regex_t* regex; + msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; @@ -3266,7 +3233,7 @@ static int msre_op_verifyCPF_init(msre_rule * rule, char** error_msg) { regex = msc_pregcomp_ex(rule->ruleset->mp, rule->op_param, options, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion); if (regex == NULL) { *error_msg = apr_psprintf(rule->ruleset->mp, "Error compiling pattern (offset %d): %s", - erroffset, errptr); + erroffset, errptr); return 0; } @@ -3287,32 +3254,32 @@ static int msre_op_verifyCPF_init(msre_rule * rule, char** error_msg) { * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; - const char* target; + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + const char *target; unsigned int target_length; - char* my_error_msg = NULL; + char *my_error_msg = NULL; int ovector[33]; int rc; int is_cpf = 0; int offset; int options = 0; int matched_bytes = 0; - char* qspos = NULL; - const char* parm = NULL; - msc_parm* mparm = NULL; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + char *qspos = NULL; + const char *parm = NULL; + msc_parm *mparm = NULL; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int jit; -#endif -#endif + #endif + #endif - * error_msg = NULL; + *error_msg = NULL; if (regex == NULL) { *error_msg = "Internal Error: regex data is null."; @@ -3323,28 +3290,28 @@ static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_va memset(ovector, 0, sizeof(ovector)); -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); msr_log(msr, 4, "%s.", *error_msg); } } -#endif -#endif + #endif + #endif /* If the given target is null run against an empty * string. This is a behaviour consistent with previous @@ -3353,8 +3320,7 @@ static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_va if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -3469,7 +3435,7 @@ static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_va break; } - } + } if (is_cpf) { /* Match. */ @@ -3483,7 +3449,7 @@ static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_va /* No match. */ return 0; - } +} /** * \brief Check for a valid SSN @@ -3495,7 +3461,7 @@ static int msre_op_verifyCPF_execute(modsec_rec * msr, msre_rule * rule, msre_va * \retval 0 On Invalid SSN * \retval 1 On Valid SSN */ -static int ssn_verify(modsec_rec * msr, const char* ssnumber, int len) { +static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) { assert(msr != NULL); assert(ssnumber != NULL); int i; @@ -3504,9 +3470,9 @@ static int ssn_verify(modsec_rec * msr, const char* ssnumber, int len) { int area, serial, grp; int sequencial = 0; int repetitions = 0; - char* str_area; - char* str_grp; - char* str_serial; + char *str_area; + char *str_grp; + char *str_serial; for (i = 0; i < len; i++) { if (apr_isdigit(ssnumber[i])) { @@ -3520,11 +3486,11 @@ static int ssn_verify(modsec_rec * msr, const char* ssnumber, int len) { if (digits != 9) goto invalid; - for (i = 0; i < 8; i++) { - if (num[i] == (num[i + 1] - 1)) + for (i=0; i < 8; i++) { + if (num[i] == (num[i+1]-1)) sequencial++; - if (num[i] == num[i + 1]) + if (num[i] == num[i+1]) repetitions++; } @@ -3535,11 +3501,11 @@ static int ssn_verify(modsec_rec * msr, const char* ssnumber, int len) { if (repetitions == 8) goto invalid; - str_area = apr_psprintf(msr->mp, "%d%d%d", num[0], num[1], num[2]); - str_grp = apr_psprintf(msr->mp, "%d%d", num[3], num[4]); - str_serial = apr_psprintf(msr->mp, "%d%d%d%d", num[5], num[6], num[7], num[8]); + str_area = apr_psprintf(msr->mp,"%d%d%d",num[0],num[1],num[2]); + str_grp = apr_psprintf(msr->mp,"%d%d",num[3],num[4]); + str_serial = apr_psprintf(msr->mp,"%d%d%d%d",num[5],num[6],num[7],num[8]); - if (str_area == NULL || str_grp == NULL || str_serial == NULL) + if(str_area == NULL || str_grp == NULL || str_serial == NULL) goto invalid; area = atoi(str_area); @@ -3569,11 +3535,11 @@ static int ssn_verify(modsec_rec * msr, const char* ssnumber, int len) { * \retval 0 On Failure * \retval 1 On Success */ -static int msre_op_verifySSN_init(msre_rule * rule, char** error_msg) { - const char* errptr = NULL; +static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { + const char *errptr = NULL; int erroffset; int options = 0; - msc_regex_t* regex; + msc_regex_t *regex; if (error_msg == NULL) return -1; *error_msg = NULL; @@ -3608,30 +3574,30 @@ static int msre_op_verifySSN_init(msre_rule * rule, char** error_msg) { * \retval 1 On Match * \retval 0 On No Match */ -static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); assert(var != NULL); assert(error_msg != NULL); - msc_regex_t* regex = (msc_regex_t*)rule->op_param_data; - const char* target; + msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; + const char *target; unsigned int target_length; - char* my_error_msg = NULL; + char *my_error_msg = NULL; int ovector[33]; int rc; int is_ssn = 0; int offset; int options = 0; int matched_bytes = 0; - char* qspos = NULL; - const char* parm = NULL; - msc_parm* mparm = NULL; -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + char *qspos = NULL; + const char *parm = NULL; + msc_parm *mparm = NULL; + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT int jit; -#endif -#endif + #endif + #endif if (error_msg == NULL) return -1; @@ -3646,28 +3612,28 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va memset(ovector, 0, sizeof(ovector)); -#ifdef WITH_PCRE_STUDY -#ifdef WITH_PCRE_JIT + #ifdef WITH_PCRE_STUDY + #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { -#ifdef WITH_PCRE2 + #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; -#else + #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); -#endif + #endif if ((rc != 0) || (jit != 1)) { *error_msg = apr_psprintf(msr->mp, - "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " - "Execution error - " - "Does not support JIT (%d)", - rule, ((rule->actionset != NULL) && ((rule->actionset->id != NULL) && - (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", - rule->filename != NULL ? rule->filename : "-", - rule->line_num, rc); + "Rule %pp [id \"%s\"][file \"%s\"][line \"%d\"] - " + "Execution error - " + "Does not support JIT (%d)", + rule,((rule->actionset != NULL)&&((rule->actionset->id != NULL)&& + (rule->actionset->id != NOT_SET_P))) ? rule->actionset->id : "-", + rule->filename != NULL ? rule->filename : "-", + rule->line_num,rc); msr_log(msr, 4, "%s.", *error_msg); } } -#endif -#endif + #endif + #endif /* If the given target is null run against an empty * string. This is a behaviour consistent with previous @@ -3676,8 +3642,7 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va if (var->value == NULL) { target = ""; target_length = 0; - } - else { + } else { target = var->value; target_length = var->value_len; } @@ -3712,11 +3677,11 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va /* Verify a match. */ if (rc > 0) { - const char* match = target + ovector[0]; + const char *match = target + ovector[0]; int length = ovector[1] - ovector[0]; int i = 0; - offset = ovector[2 * i]; + offset = ovector[2*i]; /* Check SSN using the match string */ is_ssn = ssn_verify(msr, match, length); @@ -3735,12 +3700,12 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va */ matched_bytes = apr_table_get(rule->actionset->actions, "sanitizeMatchedBytes") ? 1 : 0; - if (!matched_bytes) + if(!matched_bytes) matched_bytes = apr_table_get(rule->actionset->actions, "sanitiseMatchedBytes") ? 1 : 0; if (apr_table_get(rule->actionset->actions, "capture")) { - for (; i < rc; i++) { - msc_string* s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + for(; i < rc; i++) { + msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_psprintf(msr->mp, "%d", i); if (s->name == NULL) return -1; @@ -3749,34 +3714,33 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va if (s->value == NULL) return -1; s->value_len = length; - apr_table_setn(msr->tx_vars, s->name, (void*)s); + apr_table_setn(msr->tx_vars, s->name, (void *)s); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Added regex subexpression to TX.%d: %s", i, log_escape_nq_ex(msr->mp, s->value, s->value_len)); } - if ((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { + if((matched_bytes == 1) && (var != NULL) && (var->name != NULL)) { qspos = apr_psprintf(msr->mp, "%s", var->name); parm = strstr(qspos, ":"); - if (parm != NULL) { + if (parm != NULL) { parm++; mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); mparm->pad_1 = rule->actionset->arg_min; mparm->pad_2 = rule->actionset->arg_max; - apr_table_addn(msr->pattern_to_sanitize, parm, (void*)mparm); - } - else { + apr_table_addn(msr->pattern_to_sanitize, parm, (void *)mparm); + } else { mparm = apr_palloc(msr->mp, sizeof(msc_parm)); if (mparm == NULL) continue; - mparm->value = apr_pstrmemdup(msr->mp, s->value, s->value_len); - apr_table_addn(msr->pattern_to_sanitize, qspos, (void*)mparm); + mparm->value = apr_pstrmemdup(msr->mp,s->value,s->value_len); + apr_table_addn(msr->pattern_to_sanitize, qspos, (void *)mparm); } } @@ -3784,7 +3748,7 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va } /* Unset the remaining TX vars (from previous invocations). */ - for (; i <= 9; i++) { + for(; i <= 9; i++) { char buf[24]; apr_snprintf(buf, sizeof(buf), "%i", i); apr_table_unset(msr->tx_vars, buf); @@ -3792,7 +3756,7 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va break; } - } + } if (is_ssn) { /* Match. */ @@ -3806,21 +3770,21 @@ static int msre_op_verifySSN_execute(modsec_rec * msr, msre_rule * rule, msre_va /* No match. */ return 0; - } +} /** * Perform geograpical lookups on an IP/Host. */ -static int msre_op_geoLookup_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(var != NULL); assert(error_msg != NULL); geo_rec rec; - geo_db* geo = msr->txcfg->geo; - const char* geo_host = var->value; - msc_string* s = NULL; + geo_db *geo = msr->txcfg->geo; + const char *geo_host = var->value; + msc_string *s = NULL; int rc; *error_msg = NULL; @@ -3833,116 +3797,116 @@ static int msre_op_geoLookup_execute(modsec_rec * msr, msre_rule * rule, msre_va rc = geo_lookup(msr, &rec, geo_host, error_msg); if (rc <= 0) { - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed at %s.", log_escape_nq(msr->mp, geo_host), var->name); } apr_table_clear(msr->geo_vars); return rc; } - if (!*error_msg) { + if (! *error_msg) { *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded at %s.", log_escape_nq(msr->mp, geo_host), var->name); } if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "GEO: %s={country_code=%s, country_code3=%s, country_name=%s, country_continent=%s, region=%s, city=%s, postal_code=%s, latitude=%f, longitude=%f, dma_code=%d, area_code=%d}", - geo_host, - rec.country_code, - rec.country_code3, - rec.country_name, - rec.country_continent, - rec.region, - rec.city, - rec.postal_code, - rec.latitude, - rec.longitude, - rec.dma_code, - rec.area_code); - } - - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + geo_host, + rec.country_code, + rec.country_code3, + rec.country_name, + rec.country_continent, + rec.region, + rec.city, + rec.postal_code, + rec.latitude, + rec.longitude, + rec.dma_code, + rec.area_code); + } + + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.country_code ? rec.country_code : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "COUNTRY_CODE3"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.country_code3 ? rec.country_code3 : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "COUNTRY_NAME"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.country_name ? rec.country_name : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "COUNTRY_CONTINENT"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.country_continent ? rec.country_continent : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "REGION"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.region ? rec.region : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "CITY"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.city ? rec.city : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "POSTAL_CODE"); s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, rec.postal_code ? rec.postal_code : ""); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "LATITUDE"); s->name_len = strlen(s->name); s->value = apr_psprintf(msr->mp, "%f", rec.latitude); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "LONGITUDE"); s->name_len = strlen(s->name); s->value = apr_psprintf(msr->mp, "%f", rec.longitude); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "DMA_CODE"); s->name_len = strlen(s->name); s->value = apr_psprintf(msr->mp, "%d", rec.dma_code); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); - s = (msc_string*)apr_pcalloc(msr->mp, sizeof(msc_string)); + s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); s->name = apr_pstrdup(msr->mp, "AREA_CODE"); s->name_len = strlen(s->name); s->value = apr_psprintf(msr->mp, "%d", rec.area_code); s->value_len = strlen(s->value); - apr_table_setn(msr->geo_vars, s->name, (void*)s); + apr_table_setn(msr->geo_vars, s->name, (void *)s); return 1; } /* rbl */ -static int msre_op_rbl_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, char** error_msg) { +static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(rule->actionset != NULL); @@ -3950,9 +3914,9 @@ static int msre_op_rbl_execute(modsec_rec * msr, msre_rule * rule, msre_var * va assert(error_msg != NULL); unsigned int h0, h1, h2, h3; unsigned int high8bits = 0; - char* name_to_check = NULL; - char* target = NULL; - apr_sockaddr_t* sa = NULL; + char *name_to_check = NULL; + char *target = NULL; + apr_sockaddr_t *sa = NULL; apr_status_t rc; int capture = 0; @@ -3971,23 +3935,20 @@ static int msre_op_rbl_execute(modsec_rec * msr, msre_rule * rule, msre_var * va if (sscanf(target, "%d.%d.%d.%d", &h0, &h1, &h2, &h3) == 4) { /* IPv4 address */ /* If we're using the httpBl blocklist, we need to add the key */ - if (strstr(rule->op_param, "httpbl.org")) { + if(strstr(rule->op_param,"httpbl.org")) { if (msr->txcfg->httpBlkey == NULL) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "RBL httpBl called but no key defined: set SecHttpBlKey"); } *error_msg = "RBL httpBl called but no key defined: set SecHttpBlKey"; - } - else { + } else { name_to_check = apr_psprintf(msr->mp, "%s.%d.%d.%d.%d.%s", msr->txcfg->httpBlkey, h3, h2, h1, h0, rule->op_param); } - } - else { + } else { /* regular IPv4 RBLs */ name_to_check = apr_psprintf(msr->mp, "%d.%d.%d.%d.%s", h3, h2, h1, h0, rule->op_param); } - } - else { + } else { /* Assume the input is a domain name. */ name_to_check = apr_psprintf(msr->mp, "%s.%s", target, rule->op_param); } @@ -4002,126 +3963,122 @@ static int msre_op_rbl_execute(modsec_rec * msr, msre_rule * rule, msre_var * va /* multi.uribl.com */ - if (strstr(rule->op_param, "uribl.com")) { + if(strstr(rule->op_param,"uribl.com")) { - switch (high8bits) { - case 2: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - case 4: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (GREY).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - case 8: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (RED).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - case 14: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK,GREY,RED).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - case 255: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (DNS IS BLOCKED).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - default: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (WHITE).", - log_escape_nq(msr->mp, name_to_check), var->name); - break; - } - - set_match_to_tx(msr, capture, *error_msg, 0); - - } - else - if (strstr(rule->op_param, "spamhaus.org")) { - - switch (high8bits) { + switch(high8bits) { case 2: - case 3: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Static UBE sources).", - log_escape_nq(msr->mp, name_to_check), var->name); + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK).", + log_escape_nq(msr->mp, name_to_check), var->name); break; case 4: - case 5: - case 6: - case 7: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Illegal 3rd party exploits).", - log_escape_nq(msr->mp, name_to_check), var->name); + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (GREY).", + log_escape_nq(msr->mp, name_to_check), var->name); break; - case 10: - case 11: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Delivering unauthenticated SMTP email).", - log_escape_nq(msr->mp, name_to_check), var->name); + case 8: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (RED).", + log_escape_nq(msr->mp, name_to_check), var->name); + break; + case 14: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (BLACK,GREY,RED).", + log_escape_nq(msr->mp, name_to_check), var->name); + break; + case 255: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (DNS IS BLOCKED).", + log_escape_nq(msr->mp, name_to_check), var->name); break; default: - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.", - log_escape_nq(msr->mp, name_to_check), var->name); + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (WHITE).", + log_escape_nq(msr->mp, name_to_check), var->name); break; - } + } - set_match_to_tx(msr, capture, *error_msg, 0); + set_match_to_tx(msr, capture, *error_msg, 0); - } - else - if (strstr(rule->op_param, "httpbl.org")) { - char* respBl; - int first, days, score, type; + } else + if(strstr(rule->op_param,"spamhaus.org")) { - respBl = inet_ntoa(sa->sa.sin.sin_addr); - if (sscanf(respBl, "%d.%d.%d.%d", &first, &days, &score, &type) != 4) { - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s failed: bad response", log_escape_nq(msr->mp, name_to_check)); - } - else { - if (first != 127) { - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s failed: bad response", log_escape_nq(msr->mp, name_to_check)); - } - else { - char* ptype; - switch (type) { - case 0: - ptype = "Search Engine"; - break; - case 1: - ptype = "Suspicious IP"; - break; - case 2: - ptype = "Harvester IP"; - break; - case 3: - ptype = "Suspicious harvester IP"; - break; - case 4: - ptype = "Comment spammer IP"; - break; - case 5: - ptype = "Suspicious comment spammer IP"; - break; - case 6: - ptype = "Harvester and comment spammer IP"; - break; - case 7: - ptype = "Suspicious harvester comment spammer IP"; - break; - default: - ptype = " "; - } - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s. %s: %d days since last activity, threat score %d", - log_escape_nq(msr->mp, name_to_check), var->name, - ptype, days, score); - } - } - set_match_to_tx(msr, capture, *error_msg, 0); - /* end of httpBl code */ + switch(high8bits) { + case 2: + case 3: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Static UBE sources).", + log_escape_nq(msr->mp, name_to_check), var->name); + break; + case 4: + case 5: + case 6: + case 7: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Illegal 3rd party exploits).", + log_escape_nq(msr->mp, name_to_check), var->name); + break; + case 10: + case 11: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s (Delivering unauthenticated SMTP email).", + log_escape_nq(msr->mp, name_to_check), var->name); + break; + default: + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.", + log_escape_nq(msr->mp, name_to_check), var->name); + break; } - else { - *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.", + + set_match_to_tx(msr, capture, *error_msg, 0); + + } else + if(strstr(rule->op_param,"httpbl.org")) { + char *respBl; + int first, days, score, type; + + respBl = inet_ntoa(sa->sa.sin.sin_addr); + if (sscanf(respBl, "%d.%d.%d.%d", &first, &days, &score, &type) != 4) { + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s failed: bad response", log_escape_nq(msr->mp, name_to_check)); + } else { + if (first != 127) { + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s failed: bad response", log_escape_nq(msr->mp, name_to_check)); + } + else { + char *ptype; + switch(type) { + case 0: + ptype = "Search Engine"; + break; + case 1: + ptype = "Suspicious IP"; + break; + case 2: + ptype = "Harvester IP"; + break; + case 3: + ptype = "Suspicious harvester IP"; + break; + case 4: + ptype = "Comment spammer IP"; + break; + case 5: + ptype = "Suspicious comment spammer IP"; + break; + case 6: + ptype = "Harvester and comment spammer IP"; + break; + case 7: + ptype = "Suspicious harvester comment spammer IP"; + break; + default: + ptype = " "; + } + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s. %s: %d days since last activity, threat score %d", + log_escape_nq(msr->mp, name_to_check), var->name, + ptype, days, score); + } + } + set_match_to_tx(msr, capture, *error_msg, 0); + /* end of httpBl code */ + } else { + *error_msg = apr_psprintf(msr->r->pool, "RBL lookup of %s succeeded at %s.", log_escape_nq(msr->mp, name_to_check), var->name); - set_match_to_tx(msr, capture, *error_msg, 0); + set_match_to_tx(msr, capture, *error_msg, 0); - } + } return 1; /* Match. */ } @@ -4135,18 +4092,18 @@ static int msre_op_rbl_execute(modsec_rec * msr, msre_rule * rule, msre_var * va } /* fuzzyHash */ -static int msre_op_fuzzy_hash_init(msre_rule * rule, char** error_msg) +static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { #ifdef WITH_SSDEEP - struct fuzzy_hash_param_data* param_data; - struct fuzzy_hash_chunk* chunk, * t; - FILE* fp; - char* file; - int param_len, threshold; + struct fuzzy_hash_param_data *param_data; + struct fuzzy_hash_chunk *chunk, *t; + FILE *fp; + char *file; + int param_len,threshold; char line[1024]; - char* data = NULL; - char* threshold_str = NULL; + char *data = NULL; + char *threshold_str = NULL; param_data = apr_palloc(rule->ruleset->mp, sizeof(struct fuzzy_hash_param_data)); @@ -4211,8 +4168,7 @@ static int msre_op_fuzzy_hash_init(msre_rule * rule, char** error_msg) if (param_data->head == NULL) { param_data->head = chunk; - } - else { + } else { t = param_data->head; while (t->next) { @@ -4242,8 +4198,8 @@ static int msre_op_fuzzy_hash_init(msre_rule * rule, char** error_msg) return -1; } -static int msre_op_fuzzy_hash_execute(modsec_rec * msr, msre_rule * rule, - msre_var * var, char** error_msg) +static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, + msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4251,11 +4207,11 @@ static int msre_op_fuzzy_hash_execute(modsec_rec * msr, msre_rule * rule, assert(error_msg != NULL); #ifdef WITH_SSDEEP char result[FUZZY_MAX_RESULT]; - struct fuzzy_hash_param_data* param = rule->op_param_data; - struct fuzzy_hash_chunk* chunk = param->head; + struct fuzzy_hash_param_data *param = rule->op_param_data; + struct fuzzy_hash_chunk *chunk = param->head; #endif - * error_msg = NULL; + *error_msg = NULL; #ifdef WITH_SSDEEP if (fuzzy_hash_buf(var->value, var->value_len, result)) @@ -4280,7 +4236,7 @@ static int msre_op_fuzzy_hash_execute(modsec_rec * msr, msre_rule * rule, chunk = chunk->next; } #else - * error_msg = apr_psprintf(msr->mp, "ModSecurity was not " \ + *error_msg = apr_psprintf(msr->mp, "ModSecurity was not " \ "compiled with ssdeep support."); return -1; @@ -4293,13 +4249,13 @@ static int msre_op_fuzzy_hash_execute(modsec_rec * msr, msre_rule * rule, /* inspectFile */ -static int msre_op_inspectFile_init(msre_rule * rule, char** error_msg) { - char* filename = (char*)rule->op_param; +static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { + char *filename = (char *)rule->op_param; if (error_msg == NULL) return -1; *error_msg = NULL; - if ((filename == NULL) || (is_empty_string(filename))) { + if ((filename == NULL)||(is_empty_string(filename))) { *error_msg = apr_psprintf(rule->ruleset->mp, "Operator @inspectFile requires parameter."); return -1; } @@ -4309,10 +4265,10 @@ static int msre_op_inspectFile_init(msre_rule * rule, char** error_msg) { #if defined(WITH_LUA) /* ENH Write & use string_ends(s, e). */ if (strlen(rule->op_param) > 4) { - char* p = filename + strlen(filename) - 4; - if ((p[0] == '.') && (p[1] == 'l') && (p[2] == 'u') && (p[3] == 'a')) + char *p = filename + strlen(filename) - 4; + if ((p[0] == '.')&&(p[1] == 'l')&&(p[2] == 'u')&&(p[3] == 'a')) { - msc_script* script = NULL; + msc_script *script = NULL; /* Compile script. */ *error_msg = lua_compile(&script, filename, rule->ruleset->mp); @@ -4321,7 +4277,7 @@ static int msre_op_inspectFile_init(msre_rule * rule, char** error_msg) { rule->op_param_data = script; } } -#endif + #endif if (rule->op_param_data == NULL) { /* ENH Verify the script exists and that we have @@ -4332,8 +4288,8 @@ static int msre_op_inspectFile_init(msre_rule * rule, char** error_msg) { return 1; } -static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4343,10 +4299,10 @@ static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_ if (rule->op_param_data == NULL) { /* Execute externally, as native binary/shell script. */ - char* script_output = NULL; - char const* argv[5]; - const char* approver_script = rule->op_param; - const char* target_file = apr_pstrmemdup(msr->mp, var->value, var->value_len); + char *script_output = NULL; + char const *argv[5]; + const char *approver_script = rule->op_param; + const char *target_file = apr_pstrmemdup(msr->mp, var->value, var->value_len); if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Executing %s to inspect %s.", approver_script, target_file); @@ -4356,7 +4312,7 @@ static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_ argv[1] = target_file; argv[2] = NULL; - if (apache2_exec(msr, approver_script, (const char**)argv, &script_output) <= 0) { + if (apache2_exec(msr, approver_script, (const char **)argv, &script_output) <= 0) { *error_msg = apr_psprintf(msr->mp, "Execution of the approver script \"%s\" failed (invocation failed).", log_escape(msr->mp, approver_script)); return -1; @@ -4371,15 +4327,15 @@ static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_ if (script_output[0] != '1') { *error_msg = apr_psprintf(msr->mp, "File \"%s\" rejected by the approver script \"%s\": %s", log_escape(msr->mp, target_file), log_escape(msr->mp, approver_script), - log_escape_nq(msr->mp, script_output)); + log_escape_nq(msr->mp, script_output)); return 1; /* Match. */ } } -#if defined(WITH_LUA) + #if defined(WITH_LUA) else { /* Execute internally, as Lua script. */ - char* target = apr_pstrmemdup(msr->mp, var->value, var->value_len); - msc_script* script = (msc_script*)rule->op_param_data; + char *target = apr_pstrmemdup(msr->mp, var->value, var->value_len); + msc_script *script = (msc_script *)rule->op_param_data; int rc; rc = lua_execute(script, target, msr, rule, error_msg); @@ -4390,7 +4346,7 @@ static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_ return rc; } -#endif + #endif /* No match. */ return 0; @@ -4398,9 +4354,9 @@ static int msre_op_inspectFile_execute(modsec_rec * msr, msre_rule * rule, msre_ /* validateByteRange */ -static int msre_op_validateByteRange_init(msre_rule * rule, char** error_msg) { - char* p = NULL, * saveptr = NULL; - char* table = NULL, * data = NULL; +static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) { + char *p = NULL, *saveptr = NULL; + char *table = NULL, *data = NULL; if (error_msg == NULL) return -1; *error_msg = NULL; @@ -4413,33 +4369,32 @@ static int msre_op_validateByteRange_init(msre_rule * rule, char** error_msg) { /* Initialise. */ data = apr_pstrdup(rule->ruleset->mp, rule->op_param); rule->op_param_data = apr_pcalloc(rule->ruleset->mp, 32); - if ((data == NULL) || (rule->op_param_data == NULL)) return -1; + if ((data == NULL)||(rule->op_param_data == NULL)) return -1; table = rule->op_param_data; /* Extract parameters and update table. */ p = apr_strtok(data, ",", &saveptr); - while (p != NULL) { - char* s = strstr(p, "-"); + while(p != NULL) { + char *s = strstr(p, "-"); if (s == NULL) { /* Single value. */ int x = atoi(p); - if ((x < 0) || (x > 255)) { + if ((x < 0)||(x > 255)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range value: %d", x); return 0; } - table[x >> 3] = (table[x >> 3] | (1 << (x & 0x7))); - } - else { + table[x>>3] = (table[x>>3] | (1 << (x & 0x7))); + } else { /* Range. */ int start = atoi(p); int end = atoi(s + 1); - if ((start < 0) || (start > 255)) { + if ((start < 0)||(start > 255)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range start value: %d", start); return 0; } - if ((end < 0) || (end > 255)) { + if ((end < 0)||(end > 255)) { *error_msg = apr_psprintf(rule->ruleset->mp, "Invalid range end value: %d", end); return 0; } @@ -4448,7 +4403,7 @@ static int msre_op_validateByteRange_init(msre_rule * rule, char** error_msg) { return 0; } - while (start <= end) { + while(start <= end) { table[start >> 3] = (table[start >> 3] | (1 << (start & 0x7))); start++; } @@ -4460,14 +4415,14 @@ static int msre_op_validateByteRange_init(msre_rule * rule, char** error_msg) { return 1; } -static int msre_op_validateByteRange_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_validateByteRange_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); - char* table = rule->op_param_data; + char *table = rule->op_param_data; unsigned int i, count; *error_msg = NULL; @@ -4481,8 +4436,8 @@ static int msre_op_validateByteRange_execute(modsec_rec * msr, msre_rule * rule, /* Check every byte of the target to detect characters that are not allowed. */ count = 0; - for (i = 0; i < var->value_len; i++) { - int x = ((unsigned char*)var->value)[i]; + for(i = 0; i < var->value_len; i++) { + int x = ((unsigned char *)var->value)[i]; if (!(table[x >> 3] & (1 << (x & 0x7)))) { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Value %d in %s outside range: %s", x, var->name, rule->op_param); @@ -4501,10 +4456,10 @@ static int msre_op_validateByteRange_execute(modsec_rec * msr, msre_rule * rule, /* validateUrlEncoding */ -static int validate_url_encoding(const char* input, long int input_length) { +static int validate_url_encoding(const char *input, long int input_length) { int i; - if ((input == NULL) || (input_length < 0)) return -1; + if ((input == NULL)||(input_length < 0)) return -1; i = 0; while (i < input_length) { @@ -4520,18 +4475,16 @@ static int validate_url_encoding(const char* input, long int input_length) { char c1 = input[i + 1]; char c2 = input[i + 2]; - if ((((c1 >= '0') && (c1 <= '9')) || ((c1 >= 'a') && (c1 <= 'f')) || ((c1 >= 'A') && (c1 <= 'F'))) - && (((c2 >= '0') && (c2 <= '9')) || ((c2 >= 'a') && (c2 <= 'f')) || ((c2 >= 'A') && (c2 <= 'F')))) + if ( (((c1 >= '0')&&(c1 <= '9')) || ((c1 >= 'a')&&(c1 <= 'f')) || ((c1 >= 'A')&&(c1 <= 'F'))) + && (((c2 >= '0')&&(c2 <= '9')) || ((c2 >= 'a')&&(c2 <= 'f')) || ((c2 >= 'A')&&(c2 <= 'F'))) ) { i += 3; - } - else { + } else { /* Non-hexadecimal characters used in encoding. */ return -2; } } - } - else { + } else { i++; } } @@ -4539,33 +4492,33 @@ static int validate_url_encoding(const char* input, long int input_length) { return 1; } -static int msre_op_validateUrlEncoding_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_validateUrlEncoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(var != NULL); assert(error_msg != NULL); int rc = validate_url_encoding(var->value, var->value_len); - switch (rc) { - case 1: - /* Encoding is valid */ - *error_msg = apr_psprintf(msr->mp, "Valid URL Encoding at %s.", var->name); - break; - case -2: - *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Non-hexadecimal " - "digits used at %s.", var->name); - return 1; /* Invalid match. */ - break; - case -3: - *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Not enough characters " - "at the end of input at %s.", var->name); - return 1; /* Invalid match. */ - break; - case -1: - default: - *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Internal Error (rc = %d) at %s", rc, var->name); - return -1; - break; + switch(rc) { + case 1 : + /* Encoding is valid */ + *error_msg = apr_psprintf(msr->mp, "Valid URL Encoding at %s.", var->name); + break; + case -2 : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Non-hexadecimal " + "digits used at %s.", var->name); + return 1; /* Invalid match. */ + break; + case -3 : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Not enough characters " + "at the end of input at %s.", var->name); + return 1; /* Invalid match. */ + break; + case -1 : + default : + *error_msg = apr_psprintf(msr->mp, "Invalid URL Encoding: Internal Error (rc = %d) at %s", rc, var->name); + return -1; + break; } @@ -4576,7 +4529,7 @@ static int msre_op_validateUrlEncoding_execute(modsec_rec * msr, msre_rule * rul /* validateUtf8Encoding */ /* NOTE: This is over-commented for ease of verification */ -static int detect_utf8_character(const unsigned char* p_read, unsigned int length) { +static int detect_utf8_character(const unsigned char *p_read, unsigned int length) { int unicode_len = 0; unsigned int d = 0; unsigned char c; @@ -4662,8 +4615,8 @@ static int detect_utf8_character(const unsigned char* p_read, unsigned int lengt return unicode_len; } -static int msre_op_validateUtf8Encoding_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_validateUtf8Encoding_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(var != NULL); @@ -4672,39 +4625,39 @@ static int msre_op_validateUtf8Encoding_execute(modsec_rec * msr, msre_rule * ru bytes_left = var->value_len; - for (i = 0; i < var->value_len;) { - int rc = detect_utf8_character((unsigned char*)&var->value[i], bytes_left); + for(i = 0; i < var->value_len;) { + int rc = detect_utf8_character((unsigned char *)&var->value[i], bytes_left); - switch (rc) { - case UNICODE_ERROR_CHARACTERS_MISSING: - *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " - "not enough bytes in character " - "at %s. [offset \"%d\"]", var->name, i); - return 1; - break; - case UNICODE_ERROR_INVALID_ENCODING: - *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " - "invalid byte value in character " - "at %s. [offset \"%d\"]", var->name, i); - return 1; - break; - case UNICODE_ERROR_OVERLONG_CHARACTER: - *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " - "overlong character detected " - "at %s. [offset \"%d\"]", var->name, i); - return 1; - break; - case UNICODE_ERROR_RESTRICTED_CHARACTER: - *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " - "use of restricted character " - "at %s. [offset \"%d\"]", var->name, i); - return 1; - break; - case UNICODE_ERROR_DECODING_ERROR: - *error_msg = apr_psprintf(msr->mp, "Error validating UTF-8 decoding " - "at %s. [offset \"%d\"]", var->name, i); - return 1; - break; + switch(rc) { + case UNICODE_ERROR_CHARACTERS_MISSING : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "not enough bytes in character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_INVALID_ENCODING : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "invalid byte value in character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_OVERLONG_CHARACTER : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "overlong character detected " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_RESTRICTED_CHARACTER : + *error_msg = apr_psprintf(msr->mp, "Invalid UTF-8 encoding: " + "use of restricted character " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; + case UNICODE_ERROR_DECODING_ERROR : + *error_msg = apr_psprintf(msr->mp, "Error validating UTF-8 decoding " + "at %s. [offset \"%d\"]", var->name, i); + return 1; + break; } if (rc <= 0) { @@ -4722,25 +4675,25 @@ static int msre_op_validateUtf8Encoding_execute(modsec_rec * msr, msre_rule * ru /* eq */ -static int msre_op_eq_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); assert(error_msg != NULL); msc_string str; int left, right; - char* target = NULL; + char *target = NULL; if (error_msg == NULL) return -1; *error_msg = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } - str.value = (char*)rule->op_param; + str.value = (char *)rule->op_param; str.value_len = strlen(str.value); expand_macros(msr, &str, rule, msr->mp); @@ -4763,8 +4716,8 @@ static int msre_op_eq_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /* gt */ -static int msre_op_gt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_gt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4772,9 +4725,9 @@ static int msre_op_gt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var assert(error_msg != NULL); msc_string str; int left, right; - char* target = NULL; + char *target = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } @@ -4782,12 +4735,12 @@ static int msre_op_gt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var if (error_msg == NULL) return -1; *error_msg = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } - str.value = (char*)rule->op_param; + str.value = (char *)rule->op_param; str.value_len = strlen(str.value); expand_macros(msr, &str, rule, msr->mp); @@ -4810,8 +4763,8 @@ static int msre_op_gt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /* lt */ -static int msre_op_lt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_lt_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4819,16 +4772,16 @@ static int msre_op_lt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var assert(error_msg != NULL); msc_string str; int left, right; - char* target = NULL; + char *target = NULL; *error_msg = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } - str.value = (char*)rule->op_param; + str.value = (char *)rule->op_param; str.value_len = strlen(str.value); expand_macros(msr, &str, rule, msr->mp); @@ -4851,8 +4804,8 @@ static int msre_op_lt_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /* ge */ -static int msre_op_ge_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_ge_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4860,9 +4813,9 @@ static int msre_op_ge_execute(modsec_rec * msr, msre_rule * rule, msre_var * var assert(error_msg != NULL); msc_string str; int left, right; - char* target = NULL; + char *target = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } @@ -4870,12 +4823,12 @@ static int msre_op_ge_execute(modsec_rec * msr, msre_rule * rule, msre_var * var if (error_msg == NULL) return -1; *error_msg = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } - str.value = (char*)rule->op_param; + str.value = (char *)rule->op_param; str.value_len = strlen(str.value); expand_macros(msr, &str, rule, msr->mp); @@ -4898,8 +4851,8 @@ static int msre_op_ge_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /* le */ -static int msre_op_le_execute(modsec_rec * msr, msre_rule * rule, msre_var * var, - char** error_msg) +static int msre_op_le_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, + char **error_msg) { assert(msr != NULL); assert(rule != NULL); @@ -4907,21 +4860,21 @@ static int msre_op_le_execute(modsec_rec * msr, msre_rule * rule, msre_var * var assert(error_msg != NULL); msc_string str; int left, right; - char* target = NULL; + char *target = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } *error_msg = NULL; - if ((var->value == NULL) || (rule->op_param == NULL)) { + if ((var->value == NULL)||(rule->op_param == NULL)) { /* NULL values do not match anything. */ return 0; } - str.value = (char*)rule->op_param; + str.value = (char *)rule->op_param; str.value_len = strlen(str.value); expand_macros(msr, &str, rule, msr->mp); @@ -4947,7 +4900,7 @@ static int msre_op_le_execute(modsec_rec * msr, msre_rule * rule, msre_var * var /** * */ -void msre_engine_register_default_operators(msre_engine * engine) { +void msre_engine_register_default_operators(msre_engine *engine) { /* unconditionalMatch */ msre_engine_op_register(engine, "unconditionalMatch", @@ -5050,15 +5003,15 @@ void msre_engine_register_default_operators(msre_engine * engine) { /* detectSQLi */ msre_engine_op_register(engine, "detectSQLi", - NULL, - msre_op_detectSQLi_execute + NULL, + msre_op_detectSQLi_execute ); /* detectXSS */ msre_engine_op_register(engine, "detectXSS", - NULL, - msre_op_detectXSS_execute + NULL, + msre_op_detectXSS_execute ); /* streq */ From c7c7881c22df0450c5261bed0b466a9b4156075a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 16 May 2024 16:56:46 +0200 Subject: [PATCH 398/477] space --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 5f31933dee..178c7b7bb0 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -5167,4 +5167,4 @@ void msre_engine_register_default_operators(msre_engine *engine) { NULL, msre_op_ge_execute ); -} \ No newline at end of file +} From 98dba00231589ee36b71856134b9402cbbdfcb83 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Thu, 23 May 2024 09:40:09 -0300 Subject: [PATCH 399/477] docs: update README Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7223af738a..a823585172 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,13 @@ -ModSecurity for Apache 2.x -====== +# ModSecurity 2 -http://www.modsecurity.org/ +https://www.modsecurity.org/ -Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +Copyright (c) 2004-2024 Trustwave Holdings, Inc. (https://www.trustwave.com/) +Copyright (c) 2024-2024 OWASP ModSecurity Project (https://www.owasp.org/) You may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 -If any of the files related to licensing are missing or if you have any other questions related to licensing please contact Trustwave Holdings, Inc. directly using the email address: modsecurity@owasp.org. - +If any of the files related to licensing are missing or if you have any other questions related to licensing please contact us here: modsecurity@owasp.org. ## Documentation @@ -16,4 +15,8 @@ Please refer to: [the documentation folder](https://github.com/owasp-modsecurity ## Sponsor Note -Development of ModSecurity is sponsored by Trustwave. Sponsorship will end July 1, 2024. Additional information can be found here https://www.trustwave.com/en-us/resources/security-resources/software-updates/end-of-sale-and-trustwave-support-for-modsecurity-web-application-firewall/ +Original Development of ModSecurity was sponsored by Trustwave. In 2024, [stewardship was transferred to OWASP](https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/trustwave-transfers-modsecurity-custodianship-to-the-open-worldwide-application-security-project/). + +Contact us for sponsorship! + +You can also send us donations using the [OWASP donations page](https://owasp.org/donate/?reponame=www-project-modsecurity&title=OWASP+ModSecurity). From 4a992b5a16c8780091ef3a8f8b4607940f78555e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Tue, 28 May 2024 15:41:38 +0200 Subject: [PATCH 400/477] Replace a memset to 0 by a single assignment and fixing the 0 byte missing at the end when MSC_LARGE_STREAM_INPUT is not defined --- apache2/re_operators.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 178c7b7bb0..017103ed59 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -649,12 +649,8 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_length = 0; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = 0; - - msr->stream_input_data = (char *)malloc(size); -#else - msr->stream_input_data = (char *)malloc(size+1); #endif - + msr->stream_input_data = (char *)malloc(size+1); if(msr->stream_input_data == NULL) { return -1; } @@ -662,16 +658,11 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_length = size; #ifdef MSC_LARGE_STREAM_INPUT msr->stream_input_allocated_length = size; - memset(msr->stream_input_data, 0x0, size); -#else - memset(msr->stream_input_data, 0x0, size+1); #endif msr->if_stream_changed = 1; memcpy(msr->stream_input_data, data, size); -#ifndef MSC_LARGE_STREAM_INPUT msr->stream_input_data[size] = '\0'; -#endif var->value_len = size; var->value = msr->stream_input_data; From 84ad094ff66f2b08d0650d068acb71b81c6bbb31 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Tue, 28 May 2024 16:19:29 +0200 Subject: [PATCH 401/477] Use PCRE_STUDY_EXTRA_NEEDED flag --- apache2/msc_pcre.c | 14 +++----------- apache2/re_operators.c | 14 +++++++------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 6f1a9a186c..86bb16010c 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -31,11 +31,7 @@ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { } #else if (regex->pe != NULL) { -#if defined(VERSION_NGINX) pcre_free(regex->pe); -#else - free(regex->pe); -#endif regex->pe = NULL; } if (regex->re != NULL) { @@ -152,19 +148,15 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - pe = pcre_study(regex->re, PCRE_STUDY_JIT_COMPILE, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED|PCRE_STUDY_JIT_COMPILE, &errptr); #else - pe = pcre_study(regex->re, 0, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED, &errptr); #endif #endif /* Setup the pcre_extra record if pcre_study did not already do it */ if (pe == NULL) { -#if defined(VERSION_NGINX) - pe = pcre_malloc(sizeof(pcre_extra)); -#else - pe = malloc(sizeof(pcre_extra)); -#endif + pe = (pcre_extra*)pcre_malloc(sizeof(pcre_extra)); if (pe == NULL) { return NULL; } diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 178c7b7bb0..8bcb7d8f84 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -701,7 +701,7 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit; + int rc, jit = 0; #endif #endif @@ -784,7 +784,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v int rc; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -976,7 +976,7 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { const char *pattern = rule->op_param; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int rc, jit; + int rc, jit = 0; #endif #endif @@ -1059,7 +1059,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -2942,7 +2942,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -3275,7 +3275,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif @@ -3595,7 +3595,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var msc_parm *mparm = NULL; #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - int jit; + int jit = 0; #endif #endif From f08897003b794e58a02c3b439b742bf40146fed9 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Tue, 28 May 2024 16:25:26 +0200 Subject: [PATCH 402/477] msr->msc_full_request_buffer is freed but not assigned to NULL. It could be freed again later --- apache2/modsecurity.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index d6f2034990..dbcd3a451a 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -330,6 +330,7 @@ static apr_status_t modsecurity_tx_cleanup(void *data) { msr->msc_full_request_buffer != NULL) { msr->msc_full_request_length = 0; free(msr->msc_full_request_buffer); + msr->msc_full_request_buffer = NULL; } #if defined(WITH_LUA) From bc682d5b4afa405c393056958511e3c5366cc532 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 29 May 2024 11:38:10 +0200 Subject: [PATCH 403/477] Revert pcre_study() creating the extra data, as it's done afterwards anyway. --- apache2/msc_pcre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 86bb16010c..693f02b684 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -148,9 +148,9 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED|PCRE_STUDY_JIT_COMPILE, &errptr); + pe = pcre_study(regex->re, PCRE_STUDY_JIT_COMPILE, &errptr); #else - pe = pcre_study(regex->re, PCRE_STUDY_EXTRA_NEEDED, &errptr); + pe = pcre_study(regex->re, 0, &errptr); #endif #endif From 7f40b4071bea826bfd0c6aa09047ebcd983a6d8e Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Wed, 29 May 2024 14:26:27 -0300 Subject: [PATCH 404/477] chore: add gitignore file Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- .gitignore | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..3391ea5134 --- /dev/null +++ b/.gitignore @@ -0,0 +1,111 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Backup files +*~ + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# http://www.gnu.org/software/automake + +Makefile.in +/ar-lib +/mdate-sh +/py-compile +/test-driver +/ylwrap +.deps/ +.dirstamp + +# http://www.gnu.org/software/autoconf + +autom4te.cache +/autoscan.log +/autoscan-*.log +/aclocal.m4 +/compile +/config.cache +/config.guess +/config.h.in +/config.log +/config.status +/config.sub +/configure +/configure.scan +/depcomp +/install-sh +/missing +/stamp-h1 + +# https://www.gnu.org/software/libtool/ + +/ltmain.sh + +# http://www.gnu.org/software/texinfo + +/texinfo.tex + +# http://www.gnu.org/software/m4/ + +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 + +# Generated Makefile +# (meta build system like autotools, +# can automatically generate from config.status script +# (which is called by configure script)) +Makefile + +# IDEs +.idea \ No newline at end of file From d4d71b4f28909566883bec26c4893be06ee093a8 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Thu, 23 May 2024 10:40:46 -0300 Subject: [PATCH 405/477] fix: remove unsafe tmpnam usage Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- apache2/modsecurity.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index dbcd3a451a..2b4b9bf975 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -129,6 +129,12 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { */ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { apr_status_t rc; + apr_file_t *auditlog_lock_name; + apr_file_t *geo_lock_name; + apr_file_t *dbm_lock_name; + + // use temp path template for lock files + char *path = apr_pstrcat(p, temp_dir, "/modsec-lock-tmp.XXXXXX", NULL); msce->auditlog_lock = msce->geo_lock = NULL; #ifdef GLOBAL_COLLECTION_LOCK @@ -146,11 +152,12 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { curl_global_init(CURL_GLOBAL_ALL); #endif /* Serial audit log mutext */ - tmpnam(auditlog_lock_name); + rc = apr_file_mktemp(&auditlog_lock_name, path, 0, p) + if (rc != APR_SUCCESS) { + return -1 + } rc = apr_global_mutex_create(&msce->auditlog_lock, auditlog_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { - //ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock"); - //return HTTP_INTERNAL_SERVER_ERROR; return -1; } @@ -168,7 +175,10 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { } #endif /* SET_MUTEX_PERMS */ - tmpnam(geo_lock_name); + rc = apr_file_mktemp(&geo_lock_name, path, 0, p) + if (rc != APR_SUCCESS) { + return -1 + } rc = apr_global_mutex_create(&msce->geo_lock, geo_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { return -1; @@ -186,7 +196,10 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { #endif /* SET_MUTEX_PERMS */ #ifdef GLOBAL_COLLECTION_LOCK - tmpnam(dbm_lock_name); + rc = apr_file_mktemp(&dbm_lock_name, path, 0, p) + if (rc != APR_SUCCESS) { + return -1 + } rc = apr_global_mutex_create(&msce->dbm_lock, dbm_lock_name, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { return -1; From e9d0150102f2a2a8c0ea6364de241c199d17185e Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Wed, 29 May 2024 09:07:14 -0300 Subject: [PATCH 406/477] refactor: add acquire mutex function Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- apache2/modsecurity.c | 54 +++++++++++++++++++++++++------------------ apache2/modsecurity.h | 6 +---- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 2b4b9bf975..6cfa6f7153 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -122,6 +122,34 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { return msce; } +int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { + apr_status_t rc; + apr_file_t *lock_name; + const char *temp_dir; + const char *filename; + + // get platform temp dir + rc = apr_temp_dir_get(&temp_dir, mp); + if (rc != APR_SUCCESS) { + return -1; + } + + // use temp path template for lock files + char *path = apr_pstrcat(mp, temp_dir, GLOBAL_LOCK_TEMPLATE, NULL); + + rc = apr_file_mktemp(&lock_name, path, 0, mp); + if (rc != APR_SUCCESS) { + return -1; + } + // below func always return APR_SUCCESS + apr_file_name_get(&filename, lock_name); + + rc = apr_global_mutex_create(&lock, filename, APR_LOCK_DEFAULT, mp); + if (rc != APR_SUCCESS) { + return -1; + } + return APR_SUCCESS; +} /** * Initialise the modsecurity engine. This function must be invoked * after configuration processing is complete as Apache needs to know the @@ -129,12 +157,6 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { */ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { apr_status_t rc; - apr_file_t *auditlog_lock_name; - apr_file_t *geo_lock_name; - apr_file_t *dbm_lock_name; - - // use temp path template for lock files - char *path = apr_pstrcat(p, temp_dir, "/modsec-lock-tmp.XXXXXX", NULL); msce->auditlog_lock = msce->geo_lock = NULL; #ifdef GLOBAL_COLLECTION_LOCK @@ -151,12 +173,8 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { #ifdef WITH_CURL curl_global_init(CURL_GLOBAL_ALL); #endif - /* Serial audit log mutext */ - rc = apr_file_mktemp(&auditlog_lock_name, path, 0, p) - if (rc != APR_SUCCESS) { - return -1 - } - rc = apr_global_mutex_create(&msce->auditlog_lock, auditlog_lock_name, APR_LOCK_DEFAULT, mp); + /* Serial audit log mutex */ + rc = acquire_global_lock(msce->auditlog_lock, mp); if (rc != APR_SUCCESS) { return -1; } @@ -175,11 +193,7 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { } #endif /* SET_MUTEX_PERMS */ - rc = apr_file_mktemp(&geo_lock_name, path, 0, p) - if (rc != APR_SUCCESS) { - return -1 - } - rc = apr_global_mutex_create(&msce->geo_lock, geo_lock_name, APR_LOCK_DEFAULT, mp); + rc = acquire_global_lock(msce->geo_lock, mp); if (rc != APR_SUCCESS) { return -1; } @@ -196,11 +210,7 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { #endif /* SET_MUTEX_PERMS */ #ifdef GLOBAL_COLLECTION_LOCK - rc = apr_file_mktemp(&dbm_lock_name, path, 0, p) - if (rc != APR_SUCCESS) { - return -1 - } - rc = apr_global_mutex_create(&msce->dbm_lock, dbm_lock_name, APR_LOCK_DEFAULT, mp); + rc = acquire_global_lock(&msce->dbm_lock, mp); if (rc != APR_SUCCESS) { return -1; } diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 8e1880edc2..ba5fa7e610 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -135,11 +135,7 @@ typedef struct msc_parm msc_parm; #define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!" -static char auditlog_lock_name[L_tmpnam]; -static char geo_lock_name[L_tmpnam]; -#ifdef GLOBAL_COLLECTION_LOCK -static char dbm_lock_name[L_tmpnam]; -#endif +#define GLOBAL_LOCK_TEMPLATE "/modsec-lock-tmp.XXXXXX" extern DSOLOCAL char *new_server_signature; extern DSOLOCAL char *real_server_signature; From 54f531efd76373576a1e2175cc06dc1908a9b8e2 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Wed, 29 May 2024 14:18:55 -0300 Subject: [PATCH 407/477] fix: add error logging Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- apache2/modsecurity.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 6cfa6f7153..a76506b578 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -131,6 +131,7 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { // get platform temp dir rc = apr_temp_dir_get(&temp_dir, mp); if (rc != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, "ModSecurity: Could not get temp dir"); return -1; } @@ -139,6 +140,7 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { rc = apr_file_mktemp(&lock_name, path, 0, mp); if (rc != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create temporary file for global lock"); return -1; } // below func always return APR_SUCCESS @@ -146,6 +148,7 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { rc = apr_global_mutex_create(&lock, filename, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create global mutex"); return -1; } return APR_SUCCESS; From 93aa06bc1ff764b43c3e50c6d1c8e6aed800de55 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Thu, 30 May 2024 09:32:50 -0300 Subject: [PATCH 408/477] feat: consolidate into acquire_global_lock and export prototype Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- apache2/modsecurity.c | 53 ++++++++++++------------------------------- apache2/modsecurity.h | 3 +++ 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index a76506b578..74b6eca9e1 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -151,6 +151,18 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create global mutex"); return -1; } +#if !defined(MSC_TEST) +#ifdef __SET_MUTEX_PERMS +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 + rc = ap_unixd_set_global_mutex_perms(lock); +#else + rc = unixd_set_global_mutex_perms(lock); +#endif + if (rc != APR_SUCCESS) { + return -1; + } +#endif /* SET_MUTEX_PERMS */ +#endif /* MSC_TEST */ return APR_SUCCESS; } /** @@ -163,7 +175,7 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { msce->auditlog_lock = msce->geo_lock = NULL; #ifdef GLOBAL_COLLECTION_LOCK - msce->geo_lock = NULL; + msce->dbm_lock = NULL; #endif /** @@ -182,54 +194,17 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { return -1; } -#if !defined(MSC_TEST) -#ifdef __SET_MUTEX_PERMS -#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - rc = ap_unixd_set_global_mutex_perms(msce->auditlog_lock); -#else - rc = unixd_set_global_mutex_perms(msce->auditlog_lock); -#endif - if (rc != APR_SUCCESS) { - // ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_security: Could not set permissions on modsec_auditlog_lock; check User and Group directives"); - // return HTTP_INTERNAL_SERVER_ERROR; - return -1; - } -#endif /* SET_MUTEX_PERMS */ - rc = acquire_global_lock(msce->geo_lock, mp); if (rc != APR_SUCCESS) { return -1; } -#ifdef __SET_MUTEX_PERMS -#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - rc = ap_unixd_set_global_mutex_perms(msce->geo_lock); -#else - rc = unixd_set_global_mutex_perms(msce->geo_lock); -#endif - if (rc != APR_SUCCESS) { - return -1; - } -#endif /* SET_MUTEX_PERMS */ - #ifdef GLOBAL_COLLECTION_LOCK rc = acquire_global_lock(&msce->dbm_lock, mp); if (rc != APR_SUCCESS) { return -1; } - -#ifdef __SET_MUTEX_PERMS -#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - rc = ap_unixd_set_global_mutex_perms(msce->dbm_lock); -#else - rc = unixd_set_global_mutex_perms(msce->dbm_lock); -#endif - if (rc != APR_SUCCESS) { - return -1; - } -#endif /* SET_MUTEX_PERMS */ -#endif -#endif +#endif /* GLOBAL_COLLECTION_LOCK */ return 1; } diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index ba5fa7e610..143a82314b 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -705,6 +705,9 @@ struct msc_parm { int pad_2; }; +/* Reusable functions */ +int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp); + /* Engine functions */ msc_engine DSOLOCAL *modsecurity_create(apr_pool_t *mp, int processing_mode); From bf6bf64cf3f2f238a4255de3bd8afe367dedb83d Mon Sep 17 00:00:00 2001 From: Felipe Zipitria <felipe.zipitria@owasp.org> Date: Thu, 30 May 2024 09:45:02 -0300 Subject: [PATCH 409/477] chore: add PR template Signed-off-by: Felipe Zipitria <felipe.zipitria@owasp.org> --- .github/PULL_REQUEST_TEMPLATE.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..4d274644a4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,24 @@ +<!-- Thank you for contributing to OWASP ModSecurity, your effort is greatly appreciated --> +<!-- Please help us by adding the information below in this PR so it aids reviewers --> + +## what + +<!-- +- Describe high-level what changed as a result of these commits (i.e. in plain-english, what do these changes mean?) +- Use bullet points to be concise and to the point. +--> + +## why + +<!-- +- Provide the justifications for the changes (e.g. business case). +- Describe why these changes were made (e.g. why do these commits fix the problem?) +- Use bullet points to be concise and to the point. +--> + +## references + +<!-- +- Link to any supporting github issues or helpful documentation to add some context (e.g. stackoverflow). +- Use `closes #123`, if this PR closes a GitHub issue `#123` +--> From bcd50bec840ab9bbac184358c2902256dc716a3d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 12 Jun 2024 14:51:51 +0200 Subject: [PATCH 410/477] Show error.log after httpd start --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d931133834..0c32ce189a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,4 +48,5 @@ jobs: - name: start apache with module run: | sudo systemctl restart apache2.service + sudo cat /var/log/apache2/error.log From 9fb773c1ce0f0cad5a3b83ebef3c021bb9043f39 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Sat, 20 Jul 2024 18:45:14 +0200 Subject: [PATCH 411/477] Invalid pointer access in case rule id == NOT_SET_P --- apache2/apache2_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index c0464f50eb..78797ae4cd 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -35,7 +35,7 @@ const char* id_log(msre_rule* rule) { assert(rule != NULL); assert(rule->actionset != NULL); const char* id = rule->actionset->id; - if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + if (!id || id == NOT_SET_P || !*id) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; } From ca593a4a401308bb12749fa52cc93d2b2ddff395 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Sat, 20 Jul 2024 18:53:30 +0200 Subject: [PATCH 412/477] Passing address of lock instead of lock in acquire_global_lock() --- apache2/modsecurity.c | 25 ++++++++++--------------- apache2/modsecurity.h | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 74b6eca9e1..2990e407ba 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -122,7 +122,7 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { return msce; } -int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { +int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { apr_status_t rc; apr_file_t *lock_name; const char *temp_dir; @@ -146,7 +146,7 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { // below func always return APR_SUCCESS apr_file_name_get(&filename, lock_name); - rc = apr_global_mutex_create(&lock, filename, APR_LOCK_DEFAULT, mp); + rc = apr_global_mutex_create(lock, filename, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create global mutex"); return -1; @@ -154,11 +154,12 @@ int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp) { #if !defined(MSC_TEST) #ifdef __SET_MUTEX_PERMS #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - rc = ap_unixd_set_global_mutex_perms(lock); + rc = ap_unixd_set_global_mutex_perms(*lock); #else - rc = unixd_set_global_mutex_perms(lock); + rc = unixd_set_global_mutex_perms(*lock); #endif if (rc != APR_SUCCESS) { + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not set permissions on global mutex"); return -1; } #endif /* SET_MUTEX_PERMS */ @@ -189,21 +190,15 @@ int modsecurity_init(msc_engine *msce, apr_pool_t *mp) { curl_global_init(CURL_GLOBAL_ALL); #endif /* Serial audit log mutex */ - rc = acquire_global_lock(msce->auditlog_lock, mp); - if (rc != APR_SUCCESS) { - return -1; - } + rc = acquire_global_lock(&msce->auditlog_lock, mp); + if (rc != APR_SUCCESS) return -1; - rc = acquire_global_lock(msce->geo_lock, mp); - if (rc != APR_SUCCESS) { - return -1; - } + rc = acquire_global_lock(&msce->geo_lock, mp); + if (rc != APR_SUCCESS) return -1; #ifdef GLOBAL_COLLECTION_LOCK rc = acquire_global_lock(&msce->dbm_lock, mp); - if (rc != APR_SUCCESS) { - return -1; - } + if (rc != APR_SUCCESS) return -1; #endif /* GLOBAL_COLLECTION_LOCK */ return 1; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 143a82314b..d1aa1d8346 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -706,7 +706,7 @@ struct msc_parm { }; /* Reusable functions */ -int acquire_global_lock(apr_global_mutex_t *lock, apr_pool_t *mp); +int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp); /* Engine functions */ From 9808ce47c597a25dd4662374b5bc30fe2a89f281 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 15:23:51 +0200 Subject: [PATCH 413/477] CI improvement: First check syntax & always display error/audit logs --- .github/workflows/ci.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c32ce189a..4694c50711 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,8 +45,14 @@ jobs: sudo cp unicode.mapping /etc/apache2/ sudo mkdir -p /var/cache/modsecurity sudo chown -R www-data:www-data /var/cache/modsecurity + - name: first check config (to get syntax errors) + run: sudo apachectl configtest - name: start apache with module - run: | - sudo systemctl restart apache2.service - sudo cat /var/log/apache2/error.log - + run: sudo systemctl restart apache2.service + - name: Show httpd error log + if: always() + run: sudo cat /var/log/apache2/error.log + - name: Show mod_security2 audit log + if: always() + run: sudo cat /var/log/apache2/modsec_audit.log + # For non-regression tests: /home/runner/work/ModSecurity/ModSecurity/tests/regression/server_root/logs/audit/audit.log From ee9a2353a5ce56ec273e2f8873f68fa20f4d585d Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 15:29:45 +0200 Subject: [PATCH 414/477] create audit log --- .github/security2.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/security2.conf b/.github/security2.conf index a503848acd..d9051b007c 100644 --- a/.github/security2.conf +++ b/.github/security2.conf @@ -4,3 +4,5 @@ LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so SecDataDir /var/cache/modsecurity Include /etc/apache2/modsecurity.conf </IfModule> + +SecAuditLog /var/log/apache2/modsec_audit.log From 243d9c978ace342a10cb73a6a000e535ae31d378 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 15:57:15 +0200 Subject: [PATCH 415/477] Log audit lock name in case of problem --- apache2/msc_logging.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 92160adc60..2dc6a91b08 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1474,7 +1474,8 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Unlock the mutex we used to serialise access to the audit log file. */ rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", + msr_log(msr, 1, "Audit log: Failed to unlock global mutex '%s': %s", + apr_global_mutex_lockfile(msr->modsecurity->auditlog_lock), get_apr_error(msr->mp, rc)); } @@ -2254,7 +2255,8 @@ void sec_audit_logger_native(modsec_rec *msr) { /* Unlock the mutex we used to serialise access to the audit log file. */ rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", + msr_log(msr, 1, "Audit log: Failed to unlock global mutex '%s': %s", + apr_global_mutex_lockfile(msr->modsecurity->auditlog_lock), get_apr_error(msr->mp, rc)); } From a32b512a7fbef7952e2e3e948a82d5dd1539f37f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 15:59:28 +0200 Subject: [PATCH 416/477] Systematically log problems in update_rule_target_ex(). Fix some memory leaks in update_rule_target_ex(). --- apache2/re.c | 203 +++++++++++++++++++++++---------------------------- 1 file changed, 90 insertions(+), 113 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 8e69f5bafa..b4f2339ca3 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -65,13 +65,13 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va char *myvalue = NULL, *myname = NULL; int match = 0; - if(var == NULL) + if (var == NULL) return 0; - if(rule == NULL) + if (rule == NULL) return 0; - if(rule->actionset == NULL) + if (rule->actionset == NULL) return 0; assert(exceptions != NULL); @@ -81,7 +81,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va c = strchr(myvar,':'); - if(c != NULL) { + if (c != NULL) { myname = apr_strtok(myvar,":",&myvalue); } else { myname = myvar; @@ -91,7 +91,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va targets = apr_pstrdup(msr->mp, exceptions); - if(targets != NULL) { + if (targets != NULL) { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "fetch_target_exception: Found exception target list [%s] for rule id %s", targets, id_log(rule)); } @@ -103,18 +103,18 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va c = strchr(variable,':'); - if(c != NULL) { + if (c != NULL) { name = apr_strtok(variable,":",&value); } else { name = variable; value = NULL; } - if((strlen(myname) == strlen(name)) && + if ((strlen(myname) == strlen(name)) && (strncasecmp(myname, name,strlen(myname)) == 0)) { - if(value != NULL && myvalue != NULL) { - if((strlen(myvalue) == strlen(value)) && + if (value != NULL && myvalue != NULL) { + if ((strlen(myvalue) == strlen(value)) && strncasecmp(myvalue,value,strlen(myvalue)) == 0) { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "fetch_target_exception: Target %s will not be processed.", target); @@ -145,7 +145,7 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va } - if(match == 1) + if (match == 1) return 1; return 0; @@ -163,10 +163,10 @@ static int fetch_target_exception(msre_rule *rule, modsec_rec *msr, msre_var *va char *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re, const char *p2, const char *p3) { char *err; - if(ruleset == NULL) + if (ruleset == NULL) return NULL; - if(p2 == NULL) { + if (p2 == NULL) { return apr_psprintf(ruleset->mp, "Trying to update without a target"); } @@ -249,26 +249,24 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r char *target_list = NULL, *replace = NULL; int i, rc, match = 0, var_appended = 0; - if(rule != NULL) { - + if (rule != NULL) { target_list = strdup(p2); - if(target_list == NULL) - return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");; + if (target_list == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - memory allocation"); + goto end; + } - if(p3 != NULL) { + if (p3 != NULL) { replace = strdup(p3); - if(replace == NULL) { - free(target_list); - target_list = NULL; - return apr_psprintf(ruleset->mp, "Error to update target - memory allocation");; + if (replace == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - memory allocation"); + goto end; } } - if(replace != NULL) { - + if (replace != NULL) { opt = strchr(replace,'!'); - - if(opt != NULL) { + if (opt != NULL) { *opt = '\0'; opt++; param = opt; @@ -284,29 +282,22 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r opt = strchr(param,':'); - if(opt != NULL) { + if (opt != NULL) { name = apr_strtok(param,":",&value); } else { name = param; } - if(apr_table_get(ruleset->engine->variables, name) == NULL) { - if(target_list != NULL) - free(target_list); - if(replace != NULL) - free(replace); - if(msr) { - msr_log(msr, 9, "Error to update target - [%s] is not valid target", name); - } - return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name); + if (apr_table_get(ruleset->engine->variables, name) == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name); + goto end; } name_len = strlen(name); - if(value != NULL) - value_len = strlen(value); + if (value != NULL) value_len = strlen(value); - if(msr) { + if (msr) { msr_log(msr, 9, "Trying to replace by variable name [%s] value [%s]", name, value); } #if !defined(MSC_TEST) @@ -318,13 +309,13 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r targets = (msre_var **)rule->targets->elts; // TODO need a good way to remove the element from array, maybe change array by tables or rings for (i = 0; i < rule->targets->nelts; i++) { - if((strlen(targets[i]->name) == strlen(name)) && + if ((strlen(targets[i]->name) == strlen(name)) && (strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) && (targets[i]->is_negated == is_negated) && (targets[i]->is_counting == is_counting)) { - if(value != NULL && targets[i]->param != NULL) { - if((strlen(targets[i]->param) == strlen(value)) && + if (value != NULL && targets[i]->param != NULL) { + if ((strlen(targets[i]->param) == strlen(value)) && strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) { memset(targets[i]->name,0,strlen(targets[i]->name)); memset(targets[i]->param,0,strlen(targets[i]->param)); @@ -346,12 +337,12 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r p = apr_strtok(target_list, ",", &savedptr); - while(p != NULL) { - if(replace != NULL) { - if(match == 1) { + while (p != NULL) { + if (replace != NULL) { + if (match == 1) { rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { - if(msr) { + if (msr) { msr_log(msr, 9, "Error parsing rule targets to replace variable"); } #if !defined(MSC_TEST) @@ -361,7 +352,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r #endif goto end; } - if(msr) { + if (msr) { msr_log(msr, 9, "Successfully replaced variable"); } #if !defined(MSC_TEST) @@ -372,28 +363,31 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r var_appended = 1; } else { - if(msr) { + if (msr) { msr_log(msr, 9, "Cannot find variable to replace"); } #if !defined(MSC_TEST) else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find varibale to replace"); + ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find variable to replace"); } #endif goto end; } - } else { + } + else { target = strdup(p); - if(target == NULL) - return NULL; + if (target == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - memory allocation"); + goto end; + } is_negated = is_counting = 0; param = name = value = NULL; opt = strchr(target,'!'); - if(opt != NULL) { + if (opt != NULL) { *opt = '\0'; opt++; param = opt; @@ -408,30 +402,22 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } opt = strchr(param,':'); - - if(opt != NULL) { + if (opt != NULL) { name = apr_strtok(param,":",&value); } else { name = param; } - if(apr_table_get(ruleset->engine->variables, name) == NULL) { - if(target_list != NULL) - free(target_list); - if(replace != NULL) - free(replace); - if(msr) { - msr_log(msr, 9, "Error to update target - [%s] is not valid target", name); - } - return apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name); + if (apr_table_get(ruleset->engine->variables, name) == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - [%s] is not valid target", name); + goto end; } name_len = strlen(name); - if(value != NULL) - value_len = strlen(value); + if (value != NULL) value_len = strlen(value); - if(msr) { + if (msr) { msr_log(msr, 9, "Trying to append variable name [%s] value [%s]", name, value); } #if !defined(MSC_TEST) @@ -443,33 +429,32 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r targets = (msre_var **)rule->targets->elts; for (i = 0; i < rule->targets->nelts; i++) { - if((strlen(targets[i]->name) == strlen(name)) && + if ((strlen(targets[i]->name) == strlen(name)) && (strncasecmp(targets[i]->name,name,strlen(targets[i]->name)) == 0) && (targets[i]->is_negated == is_negated) && (targets[i]->is_counting == is_counting)) { - if(value != NULL && targets[i]->param != NULL) { - if((strlen(targets[i]->param) == strlen(value)) && + if (value != NULL && targets[i]->param != NULL) { + if ((strlen(targets[i]->param) == strlen(value)) && strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) { match = 1; } } else if (value == NULL && targets[i]->param == NULL){ match = 1; - } else - continue; + } else continue; } } - if(target != NULL) { + if (target != NULL) { free(target); target = NULL; } - if(match == 0 ) { + if (match == 0 ) { rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { - if(msr) { + if (msr) { msr_log(msr, 9, "Error parsing rule targets to append variable"); } #if !defined(MSC_TEST) @@ -481,7 +466,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } var_appended = 1; } else { - if(msr) { + if (msr) { msr_log(msr, 9, "Skipping variable, already appended"); } #if !defined(MSC_TEST) @@ -495,11 +480,11 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r p = apr_strtok(NULL,",",&savedptr); } - if(var_appended == 1) { + if (var_appended == 1) { current_targets = msre_generate_target_string(ruleset->mp, rule); rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, current_targets, NULL, NULL); rule->p1 = apr_pstrdup(ruleset->mp, current_targets); - if(msr) { + if (msr) { msr_log(msr, 9, "Successfully appended variable"); } #if !defined(MSC_TEST) @@ -511,19 +496,11 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } end: - if(target_list != NULL) { - free(target_list); - target_list = NULL; - } - if(replace != NULL) { - free(replace); - replace = NULL; - } - if(target != NULL) { - free(target); - target = NULL; - } - return NULL; + if (msr && my_error_msg) msr_log(msr, 9, my_error_msg); + if (target_list != NULL) free(target_list); + if (replace != NULL) free(replace); + if (target != NULL) free(target); + return my_error_msg; } int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) { @@ -567,7 +544,7 @@ int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) { for (act = 0; act < tarr->nelts; act++) { msre_action *action = (msre_action *)telts[act].val; - if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) { + if ((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) { int rc = msc_regexec(re->param_data, action->param, strlen(action->param), @@ -618,7 +595,7 @@ static char *msre_generate_target_string(apr_pool_t *pool, msre_rule *rule) { for (i = 0; i < rule->targets->nelts; i++) { - if(targets[i]->name != NULL && strlen(targets[i]->name) > 0) { + if (targets[i]->name != NULL && strlen(targets[i]->name) > 0) { target_str = apr_pstrcat(pool, (target_str == NULL) ? "" : apr_psprintf(pool, "%s|", target_str), (targets[i]->is_negated == 0) ? "" : "!", @@ -1558,12 +1535,12 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re if ((rule->placeholder == RULE_PH_NONE) || (rule->actionset->id == NULL) || (strcmp(skip_after, rule->actionset->id) != 0)) { - if(i-1 >=0) + if (i-1 >=0) last_rule = rules[i-1]; else last_rule = rules[0]; - if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained && (saw_starter == 1)) { + if ((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained && (saw_starter == 1)) { mode = NEXT_RULE; skipped = 1; --i; @@ -1655,7 +1632,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re for(j = 0; j < msr->removed_rules_msg->nelts; j++) { re = ((rule_exception **)msr->removed_rules_msg->elts)[j]; - if(rule->actionset->msg !=NULL) { + if (rule->actionset->msg !=NULL) { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Checking removal of rule msg=\"%s\" against: %s", rule->actionset->msg, re->param); @@ -1674,7 +1651,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re for(j = 0; j < msr->removed_rules->nelts; j++) { range = ((const char**)msr->removed_rules->elts)[j]; - if(rule->actionset->id !=NULL) { + if (rule->actionset->id !=NULL) { if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Checking removal of rule id=\"%s\" against: %s", rule->actionset->id, range); @@ -1693,13 +1670,13 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re for (act = 0; act < tag_tarr->nelts; act++) { msre_action *action = (msre_action *)tag_telts[act].val; - if((action != NULL) && (action->metadata != NULL ) && strcmp("tag", action->metadata->name) == 0) { + if ((action != NULL) && (action->metadata != NULL ) && strcmp("tag", action->metadata->name) == 0) { for(j = 0; j < msr->removed_rules_tag->nelts; j++) { re = ((rule_exception **)msr->removed_rules_tag->elts)[j]; - if(action->param != NULL) { + if (action->param != NULL) { /* Expand variables in the tag argument. */ msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); @@ -1745,7 +1722,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re } } - if(msr->txcfg->is_enabled == MODSEC_DISABLED) { + if (msr->txcfg->is_enabled == MODSEC_DISABLED) { saw_starter = 0; skipped = 0; skip_after = NULL; @@ -1825,12 +1802,12 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re msr_log(msr, 9, "Match, intercepted -> returning."); } - if(i-1 >= 0) + if (i-1 >= 0) last_rule = rules[i-1]; else last_rule = rules[0]; - if((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained) { + if ((last_rule != NULL) && (last_rule->actionset != NULL) && last_rule->actionset->is_chained) { int st = 0; @@ -1838,8 +1815,8 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re rule_starter = rules[st]; - if(rule_starter != NULL && rule_starter->chain_starter != NULL) { - if((msr != NULL) && (msr->intercept_actionset != NULL) && (rule_starter->actionset != NULL)) + if (rule_starter != NULL && rule_starter->chain_starter != NULL) { + if ((msr != NULL) && (msr->intercept_actionset != NULL) && (rule_starter->actionset != NULL)) msr->intercept_actionset->intercept_uri = rule_starter->actionset->intercept_uri; break; } @@ -1863,7 +1840,7 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re continue; } - if(skipped == 1) { + if (skipped == 1) { mode = SKIP_RULES; continue; } @@ -2024,7 +2001,7 @@ static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, co && (strcmp(rule->actionset->id, id) == 0)) { /* Return rule that matched unless it is a placeholder */ - if(offset == 0) { + if (offset == 0) { return (rule->placeholder == RULE_PH_NONE) ? rule : NULL; } else { @@ -2121,7 +2098,7 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, for (act = 0; act < tarr->nelts; act++) { msre_action *action = (msre_action *)telts[act].val; - if((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) { + if ((action != NULL) && (action->metadata != NULL) && (strcmp("tag", action->metadata->name) == 0)) { int rc = msc_regexec(re->param_data, action->param, strlen(action->param), @@ -2653,7 +2630,7 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, if (rc > 0) { rc = fetch_target_exception(rule, msr, var, exceptions); - if(rc > 0) { + if (rc > 0) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Executing operator \"%s%s\" with param \"%s\" against %s skipped.", @@ -2701,22 +2678,22 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, msr_log(msr, 4, "Operator completed in %" APR_TIME_T_FMT " usec.", (t1 - time_before_op)); } - if(msr->txcfg->max_rule_time > 0) { + if (msr->txcfg->max_rule_time > 0) { apr_time_t t1 = apr_time_now(); apr_time_t rule_time = 0; const char *rt_time = NULL; - if(rule->actionset->id != NULL) { + if (rule->actionset->id != NULL) { rt_time = apr_table_get(msr->perf_rules, rule->actionset->id); - if(rt_time == NULL) { + if (rt_time == NULL) { rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (t1 - time_before_op)); rule_time = (apr_time_t)atoi(rt_time); - if(rule_time >= msr->txcfg->max_rule_time) + if (rule_time >= msr->txcfg->max_rule_time) apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time); } else { rule_time = (apr_time_t)atoi(rt_time); rule_time += (t1 - time_before_op); - if(rule_time >= msr->txcfg->max_rule_time) { + if (rule_time >= msr->txcfg->max_rule_time) { rt_time = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, rule_time); apr_table_setn(msr->perf_rules, rule->actionset->id, rt_time); } @@ -2754,7 +2731,7 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, *(const msre_rule **)apr_array_push(msr->matched_rules) = rule; /* Save the last matched var data */ - if(var != NULL && msr != NULL) { + if (var != NULL && msr != NULL) { msc_string *mvar = NULL; msr->matched_var->name = apr_pstrdup(msr->mp, var->name); From f32be70793ffc2374875d0646f0ee715b06af00f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 16:24:56 +0200 Subject: [PATCH 417/477] Use standard httpd logging format in error log --- apache2/mod_security2.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 0ee72865fc..1850191eb7 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -103,17 +103,17 @@ static int server_limit, thread_limit; * * \param mp Pointer to memory pool */ -static void version(apr_pool_t *mp) { +static void version(apr_pool_t *mp, server_rec* s) { char *pcre_vrs = NULL; const char *pcre_loaded_vrs = NULL; char pcre2_loaded_vrs_buffer[80] ={0}; - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "ModSecurity: APR compiled version=\"%s\"; " "loaded version=\"%s\"", APR_VERSION_STRING, apr_version_string()); if (strstr(apr_version_string(), APR_VERSION_STRING) == NULL) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded APR do not match with compiled!"); + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "ModSecurity: Loaded APR do not match with compiled!"); } #ifdef WITH_PCRE2 @@ -134,21 +134,21 @@ static void version(apr_pool_t *mp) { "loaded version=\"%s\"", pcre_vrs, pcre_loaded_vrs); if (strstr(pcre_loaded_vrs,pcre_vrs) == NULL) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded PCRE do not match with compiled!"); + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "ModSecurity: Loaded PCRE do not match with compiled!"); } /* Lua version function was removed in current 5.1. Need to check in future versions if it's back */ #if defined(WITH_LUA) - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "ModSecurity: LUA compiled version=\"%s\"", LUA_VERSION); #endif /* WITH_LUA */ #ifdef WITH_YAJL - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "ModSecurity: YAJL compiled version=\"%d.%d.%d\"", YAJL_MAJOR, YAJL_MINOR, YAJL_MICRO); #endif /* WITH_YAJL */ - ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, "ModSecurity: LIBXML compiled version=\"%s\"", LIBXML_DOTTED_VERSION); } @@ -778,7 +778,7 @@ static int hook_post_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_t ap_log_error(APLOG_MARK, APLOG_NOTICE | APLOG_NOERRNO, 0, s, "%s configured.", MODSEC_MODULE_NAME_FULL); - version(mp); + version(mp, s); /* If we've changed the server signature make note of the original. */ if (new_server_signature != NULL) { From cd65a44d64d61c84f20207e8a618f93c9ce47178 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 16:53:58 +0200 Subject: [PATCH 418/477] Removed useless code --- apache2/apache2_io.c | 2 -- apache2/msc_crypt.c | 8 ++--- apache2/msc_reqbody.c | 15 +++----- apache2/msc_util.c | 24 ++++--------- apache2/re.c | 6 ++-- apache2/re_actions.c | 77 ++++++++++++++++++++---------------------- apache2/re_operators.c | 34 +++++-------------- apache2/re_variables.c | 2 +- 8 files changed, 63 insertions(+), 105 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 5d2ef85bd9..405b649ae4 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -629,7 +629,6 @@ static int flatten_response_body(modsec_rec *msr) { return -1; } - memset(msr->stream_output_data, 0, msr->stream_output_length+1); memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length); msr->stream_output_data[msr->stream_output_length] = '\0'; } else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_ENABLED) { @@ -662,7 +661,6 @@ static int flatten_response_body(modsec_rec *msr) { return -1; } - memset(msr->stream_output_data, 0, msr->stream_output_length+1); memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length); msr->stream_output_data[msr->stream_output_length] = '\0'; } diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 3287eeff2e..4f73d15a7a 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -1156,8 +1156,8 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { return -1; } - memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%zu] bytes.", xmlOutputBufferGetSize(output_buf)); @@ -1187,8 +1187,8 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { return -1; } - memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%zu] bytes.", xmlOutputBufferGetSize(output_buf)); @@ -1222,9 +1222,9 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { return -1; } - memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, (char *)xmlBufferContent(output_buf->buffer), msr->stream_output_length); //memcpy(msr->stream_output_data, output_buf->buffer->content, msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", msr->stream_output_length); @@ -1254,9 +1254,9 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { return -1; } - memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, (char *)xmlBufferContent(output_buf->conv), msr->stream_output_length); //memcpy(msr->stream_output_data, output_buf->conv->content, msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", msr->stream_output_length); diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index ba8bdfd416..c7c081fb6a 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -461,8 +461,8 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf if(data == NULL) return -1; - memset(data, 0, msr->stream_input_length + 1 - buflen); memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen); + data[msr->stream_input_length - buflen] = '\0'; stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1); @@ -470,28 +470,21 @@ apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buf } if (msr->stream_input_data == NULL) { - if(data) { - free(data); - data = NULL; - } + if (data) free(data); *error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length + 1); return -1; } - memset(msr->stream_input_data, 0, msr->stream_input_length+1); - if(first_pkt) { memcpy(msr->stream_input_data, buffer, msr->stream_input_length); } else { memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen); memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen); } + msr->stream_input_data[msr->stream_input_length] = '\0'; - if(data) { - free(data); - data = NULL; - } + if (data) free(data); #else if (msr->stream_input_data == NULL) { // Is the request body length known beforehand? (requests that are not Transfer-Encoding: chunked) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index fd318a087a..bce5b24ffe 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2473,28 +2473,16 @@ int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer, int read_line(char *buf, int len, FILE *fp) { - char *tmp; + if (buf == NULL) return -1; - if (buf == NULL) - { - return -1; - } - - memset(buf, '\0', len*sizeof(char)); - - if (fgets(buf, len, fp) == NULL) - { + if (fgets(buf, len, fp) == NULL) { *buf = '\0'; return 0; } - else - { - if ((tmp = strrchr(buf, '\n')) != NULL) - { - *tmp = '\0'; - } - } - + + char* tmp; + if ((tmp = strrchr(buf, '\n')) != NULL) *tmp = '\0'; + return 1; } diff --git a/apache2/re.c b/apache2/re.c index 8e69f5bafa..6476a94fb6 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -326,14 +326,14 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if(value != NULL && targets[i]->param != NULL) { if((strlen(targets[i]->param) == strlen(value)) && strncasecmp(targets[i]->param,value,strlen(targets[i]->param)) == 0) { - memset(targets[i]->name,0,strlen(targets[i]->name)); - memset(targets[i]->param,0,strlen(targets[i]->param)); + targets[i]->name[0] = '\0'; + targets[i]->param[0] = '\0'; targets[i]->is_counting = 0; targets[i]->is_negated = 1; match = 1; } } else if (value == NULL && targets[i]->param == NULL){ - memset(targets[i]->name,0,strlen(targets[i]->name)); + targets[i]->name[0] = '\0'; targets[i]->is_counting = 0; targets[i]->is_negated = 1; match = 1; diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 36f898dd23..c5cdd45394 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1251,19 +1251,19 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return -1; } - re = apr_pcalloc(msr->mp, sizeof(rule_exception)); - if (re == NULL) { - msr_log(msr, 1, "Ctl: Memory allocation error"); - return -1; - } - re->type = RULE_EXCEPTION_REMOVE_ID; - re->param = (const char *)apr_pstrdup(msr->mp, p1); - if (re->param == NULL) { - msr_log(msr, 1, "Ctl: Memory allocation error"); - return -1; - } - apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); - return 1; + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); + if (re == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } + re->type = RULE_EXCEPTION_REMOVE_ID; + re->param = (const char *)apr_pstrdup(msr->mp, p1); + if (re->param == NULL) { + msr_log(msr, 1, "Ctl: Memory allocation error"); + return -1; + } + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); + return 1; } else if (strcasecmp(name, "ruleRemoveTargetByTag") == 0) { rule_exception *re = NULL; @@ -1271,7 +1271,6 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, char *savedptr = NULL; p1 = apr_strtok(value,";",&savedptr); - p2 = apr_strtok(NULL,";",&savedptr); if (msr->txcfg->debuglog_level >= 4) { @@ -1282,16 +1281,16 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return -1; } - re = apr_pcalloc(msr->mp, sizeof(rule_exception)); - re->type = RULE_EXCEPTION_REMOVE_TAG; - re->param = (const char *)apr_pstrdup(msr->mp, p1); - re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); - if (re->param_data == NULL) { - msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); - return -1; - } - apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); - return 1; + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); + re->type = RULE_EXCEPTION_REMOVE_TAG; + re->param = (const char *)apr_pstrdup(msr->mp, p1); + re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); + return -1; + } + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); + return 1; } else if (strcasecmp(name, "ruleRemoveTargetByMsg") == 0) { rule_exception *re = NULL; @@ -1299,7 +1298,6 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, char *savedptr = NULL; p1 = apr_strtok(value,";",&savedptr); - p2 = apr_strtok(NULL,";",&savedptr); if (msr->txcfg->debuglog_level >= 4) { @@ -1310,23 +1308,20 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return -1; } - re = apr_pcalloc(msr->mp, sizeof(rule_exception)); - re->type = RULE_EXCEPTION_REMOVE_MSG; - re->param = apr_pstrdup(msr->mp, p1); - re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); - if (re->param_data == NULL) { - msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); - return -1; - } - apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); - return 1; - } - else { - /* Should never happen, but log if it does. */ - msr_log(msr, 1, "Internal Error: Unknown ctl action \"%s\".", name); - return -1; + re = apr_pcalloc(msr->mp, sizeof(rule_exception)); + re->type = RULE_EXCEPTION_REMOVE_MSG; + re->param = apr_pstrdup(msr->mp, p1); + re->param_data = msc_pregcomp(msr->mp, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + msr_log(msr, 1, "ModSecurity: Invalid regular expression \"%s\"", p1); + return -1; + } + apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); + return 1; } + /* Should never happen, but log if it does. */ + msr_log(msr, 1, "Internal Error: Unknown ctl action \"%s\".", name); return -1; } @@ -1764,7 +1759,7 @@ static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, var_value = s + 1; *s = '\0'; - while ((*var_value != '\0')&&(isspace(*var_value))) var_value++; + while (isspace(*var_value)) var_value++; } return msre_action_setvar_execute(msr,mptmp,rule,var_name,var_value); diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 1d8122638f..30176c5149 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -617,24 +617,15 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, size+=sl; *data_out=0; - if(msr->stream_output_data != NULL && output_body == 1) { - - memset(msr->stream_output_data, 0x0, msr->stream_output_length); + if (msr->stream_output_data != NULL && output_body == 1) { free(msr->stream_output_data); msr->stream_output_data = NULL; msr->stream_output_length = 0; - msr->stream_output_data = (char *)malloc(size+1); - - if(msr->stream_output_data == NULL) { - return -1; - } + if (msr->stream_output_data == NULL) return -1; msr->stream_output_length = size; - memset(msr->stream_output_data, 0x0, size+1); - msr->of_stream_changed = 1; - memcpy(msr->stream_output_data, data, size); msr->stream_output_data[size] = '\0'; @@ -642,8 +633,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, var->value = msr->stream_output_data; } - if(msr->stream_input_data != NULL && input_body == 1) { - memset(msr->stream_input_data, 0x0, msr->stream_input_length); + if (msr->stream_input_data != NULL && input_body == 1) { free(msr->stream_input_data); msr->stream_input_data = NULL; msr->stream_input_length = 0; @@ -651,9 +641,7 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, msr->stream_input_allocated_length = 0; #endif msr->stream_input_data = (char *)malloc(size+1); - if(msr->stream_input_data == NULL) { - return -1; - } + if(msr->stream_input_data == NULL) return -1; msr->stream_input_length = size; #ifdef MSC_LARGE_STREAM_INPUT @@ -1573,12 +1561,11 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l int match = 0; url = apr_palloc(pool, len + 1); + if (!url) return NULL; data = apr_palloc(pool, len + 1); + if (!data) return NULL; - memset(data, 0, len+1); - memset(url, 0, len+1); - - memcpy(url, domain, len); + url[len] = 0; while(( pos = strstr(url , "/./" )) != NULL) { match = 1; @@ -1589,8 +1576,7 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l strncpy(url , data, len); } - if(match == 0) - return domain; + if (match == 0) return domain; return url; } @@ -1681,8 +1667,6 @@ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned const char *hash = NULL; const char *search = NULL; - memset(digest, 0, sizeof(digest)); - apr_md5_init(&ctx); if ((rc = apr_md5_update(&ctx, match, match_length)) != APR_SUCCESS) @@ -1690,7 +1674,7 @@ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned apr_md5_final(digest, &ctx); - hash = apr_psprintf(msr->mp, "%s", bytes2hex(msr->mp, digest, 16)); + hash = apr_psprintf(msr->mp, "%s", bytes2hex(msr->mp, digest, APR_MD5_DIGESTSIZE)); if ((hash != NULL) && (gsb->gsb_table != NULL)) { search = apr_hash_get(gsb->gsb_table, hash, APR_HASH_KEY_STRING); diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 5aa7589a2b..dee23af24b 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -2491,7 +2491,7 @@ static int var_full_request_generate(modsec_rec *msr, msre_var *var, } goto failed_not_enough_mem; } - memset(full_request, '\0', sizeof(char)*msr->msc_full_request_length); + full_request[0] = '\0'; msr->msc_full_request_buffer = full_request; msr->msc_full_request_length = full_request_length; From 9b987cc3f92d06f50c430732413ee96dc22b681a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 22 Jul 2024 17:08:16 +0200 Subject: [PATCH 419/477] Return of msc_regexec() compared with PCRE_ERROR_NOMATCH (!=) to check if match. Other errors may happen that would return -2, -3, ... Matching would be incorrectly set in this case. We must check if >= 0 --- apache2/re_variables.c | 116 +++++++++++++---------------------------- 1 file changed, 35 insertions(+), 81 deletions(-) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 5aa7589a2b..c627759303 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -120,8 +120,7 @@ static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; /* Run the regex against the argument name. */ - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -198,8 +197,7 @@ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *ru else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -250,8 +248,7 @@ static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; /* Run the regex against the argument name. */ - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -300,8 +297,7 @@ static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -352,8 +348,7 @@ static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rul if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; /* Run the regex against the argument name. */ - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -402,8 +397,7 @@ static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rul else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, arg->name, - arg->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, arg->name, arg->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(arg->name, var->param) == 0) match = 1; } @@ -899,8 +893,7 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -955,8 +948,7 @@ static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1016,8 +1008,7 @@ static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1096,8 +1087,7 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1152,8 +1142,7 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1212,8 +1201,7 @@ static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1264,8 +1252,7 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - str->name_len, &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, str->name_len, &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -1306,38 +1293,21 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, 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)) - { + 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) - { + 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; - } + if (msc_regexec((msc_regex_t*)var->param_data, parts[i]->name, strlen(parts[i]->name), &my_error_msg) >= 0) match = 1; } - else - { + else { /* Simple comparison. */ - if (strcasecmp(parts[i]->name, var->param) == 0) - { - match = 1; - } + if (strcasecmp(parts[i]->name, var->param) == 0)match = 1; } } /* If we had a match add this argument to the collection. */ @@ -1351,10 +1321,7 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, msre_var *rvar = NULL; file = fopen(parts[i]->tmp_file_name, "r"); - if (file == NULL) - { - continue; - } + if (file == NULL) continue; full_content = (char *)apr_pcalloc(mptmp, (sizeof(char)*parts[i]->length) + 1); if (full_content == NULL) { @@ -1416,8 +1383,7 @@ static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule 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; + if (msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, strlen(parts[i]->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; } @@ -1465,8 +1431,7 @@ static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, 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; + if (msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, strlen(parts[i]->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; } @@ -1514,8 +1479,7 @@ static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *r 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; + if (msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, strlen(parts[i]->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; } @@ -1632,8 +1596,7 @@ static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, m 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; + if (msc_regexec((msc_regex_t *)var->param_data, parts[i]->name, strlen(parts[i]->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(parts[i]->name, var->param) == 0) match = 1; } @@ -2105,8 +2068,7 @@ static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *ru else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -2591,8 +2553,7 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_ else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - strlen(str->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, strlen(str->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -2660,8 +2621,7 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule * else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, str->name, - strlen(str->name), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, str->name, strlen(str->name), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(str->name, var->param) == 0) match = 1; } @@ -2728,8 +2688,7 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -2783,8 +2742,7 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -2838,8 +2796,7 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -2893,8 +2850,7 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -3171,8 +3127,7 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } @@ -3226,8 +3181,7 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m else { if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; - if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, - strlen(te[i].key), &my_error_msg) == PCRE_ERROR_NOMATCH)) match = 1; + if (msc_regexec((msc_regex_t *)var->param_data, te[i].key, strlen(te[i].key), &my_error_msg) >= 0) match = 1; } else { /* Simple comparison. */ if (strcasecmp(te[i].key, var->param) == 0) match = 1; } From b53c2277d7e3cec2a5e6f0530b8c9edad71cfc4c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 25 Jul 2024 08:39:44 +0200 Subject: [PATCH 420/477] removed duplicate log entry --- apache2/re.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index b4f2339ca3..7c96977e55 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -300,11 +300,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if (msr) { msr_log(msr, 9, "Trying to replace by variable name [%s] value [%s]", name, value); } -#if !defined(MSC_TEST) - else { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Trying to replace by variable name [%s] value [%s]", name, value); - } -#endif targets = (msre_var **)rule->targets->elts; // TODO need a good way to remove the element from array, maybe change array by tables or rings From 73a79af593867aa37926a90af844cf3bbb86a5f7 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 25 Jul 2024 08:55:26 +0200 Subject: [PATCH 421/477] Fixed duplicate log entry use ap_log_error() if msr is NULL Fixed indentation --- apache2/re.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 7c96977e55..56aebea420 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -297,10 +297,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if (value != NULL) value_len = strlen(value); - if (msr) { - msr_log(msr, 9, "Trying to replace by variable name [%s] value [%s]", name, value); - } - targets = (msre_var **)rule->targets->elts; // TODO need a good way to remove the element from array, maybe change array by tables or rings for (i = 0; i < rule->targets->nelts; i++) { @@ -372,10 +368,10 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r else { target = strdup(p); - if (target == NULL) { - my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - memory allocation"); - goto end; - } + if (target == NULL) { + my_error_msg = apr_psprintf(ruleset->mp, "Error to update target - memory allocation"); + goto end; + } is_negated = is_counting = 0; param = name = value = NULL; @@ -491,7 +487,14 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } end: - if (msr && my_error_msg) msr_log(msr, 9, my_error_msg); + if (my_error_msg) { + if (msr) msr_log(msr, 9, my_error_msg); +#if !defined(MSC_TEST) + else { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfully appended variable"); + } +#endif + } if (target_list != NULL) free(target_list); if (replace != NULL) free(replace); if (target != NULL) free(target); From f143663cf0ddee6a2458d3d7806fc151a6b5e99c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 25 Jul 2024 09:30:48 +0200 Subject: [PATCH 422/477] Add collection in log in case of writing error --- apache2/persist_dbm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index 6634151ca4..c685e1de3b 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -638,9 +638,9 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { #endif if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").", + msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\", length=%d).", log_escape_ex(msr->mp, var_name->value, var_name->value_len), - log_escape_ex(msr->mp, var_key->value, var_key->value_len)); + log_escape_ex(msr->mp, var_key->value, var_key->value_len), value.dsize); } return 0; From 223ce91aeeb49e59590f4dcc295cacee48cb60c1 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Thu, 25 Jul 2024 20:52:55 +0200 Subject: [PATCH 423/477] Move xmlFree() call to the right place --- apache2/re_variables.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 5aa7589a2b..a080a863dd 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -745,13 +745,12 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, } /* Create one variable for each node in the result. */ + char* content = NULL; for(i = 0; i < nodes->nodeNr; i++) { msre_var *rvar = NULL; - char *content = NULL; content = (char *)xmlNodeGetContent(nodes->nodeTab[i]); if (content != NULL) { - xmlFree(content); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); if (!rvar) { msr_log(msr, 1, "XML: Memory allocation error"); @@ -766,12 +765,15 @@ static int var_xml_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, } rvar->value_len = strlen(rvar->value); apr_table_addn(vartab, rvar->name, (void *)rvar); + xmlFree(content); + content = NULL; count++; } } var_xml_generate_Error: + if (content != NULL) xmlFree(content); xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); From 0be1f1566a6a98e48822be0d6bea1a5dfc28ecab Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 31 Jul 2024 09:38:20 +0200 Subject: [PATCH 424/477] Remove redundant entry [client %s] is added by the standard httpd log function => remove it --- apache2/apache2_util.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index 20ea940ee5..f42436790f 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -286,19 +286,16 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, - "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1, - hostname, log_escape(msr->mp, r->uri), unique_id); + "ModSecurity: %s%s [uri \"%s\"]%s", str1, hostname, log_escape(msr->mp, r->uri), unique_id); #else ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, - "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", msr->remote_addr ? msr->remote_addr : r->connection->remote_ip, str1, - hostname, log_escape(msr->mp, r->uri), unique_id); + "ModSecurity: %s%s [uri \"%s\"]%s", str1, hostname, log_escape(msr->mp, r->uri), unique_id); #endif /* Add this message to the list. */ if (msr != NULL) { /* Force relevency if this is an alert */ msr->is_relevant++; - *(const char **)apr_array_push(msr->alerts) = apr_pstrdup(msr->mp, str1); } } From 7c379c8d5944578284e9baa3849f993168007fd3 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 31 Jul 2024 11:17:36 +0200 Subject: [PATCH 425/477] Fixed assert() usage: - added some missing - removed some invalid - removed some that were not relevant in the context of the current function, when done in a called function --- apache2/apache2_config.c | 378 +++++++++++++++++++++++++++------------ apache2/modsecurity.c | 2 + apache2/msc_json.c | 10 ++ apache2/msc_logging.c | 5 +- apache2/msc_multipart.c | 1 + apache2/msc_parsers.c | 1 + apache2/msc_reqbody.c | 3 + apache2/msc_xml.c | 2 + apache2/re.c | 36 +++- apache2/re_actions.c | 89 +++++++++ apache2/re_operators.c | 76 ++++++-- apache2/re_variables.c | 93 ++++++++-- 12 files changed, 552 insertions(+), 144 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index c0464f50eb..cc37d8eb9e 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -34,6 +34,7 @@ const char* id_log(msre_rule* rule) { assert(rule != NULL); assert(rule->actionset != NULL); + assert(rule->ruleset != NULL); const char* id = rule->actionset->id; if (!id || !*id || id == NOT_SET_P) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); return id; @@ -188,6 +189,9 @@ static void copy_rules_phase(apr_pool_t *mp, apr_array_header_t *child_phase_arr, apr_array_header_t *exceptions_arr) { + assert(parent_phase_arr != NULL); + assert(child_phase_arr != NULL); + assert(exceptions_arr != NULL); rule_exception **exceptions; msre_rule **rules; int i, j; @@ -196,11 +200,14 @@ static void copy_rules_phase(apr_pool_t *mp, rules = (msre_rule **)parent_phase_arr->elts; for(i = 0; i < parent_phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; + assert(rule != NULL); + assert(rule->actionset != NULL); int copy = 1; if (mode == 0) { /* First rule in the chain. */ exceptions = (rule_exception **)exceptions_arr->elts; + assert(exceptions != NULL); for(j = 0; j < exceptions_arr->nelts; j++) { /* Process exceptions. */ @@ -290,14 +297,11 @@ static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, msre_ruleset *child_ruleset, apr_array_header_t *exceptions_arr) { + assert(parent_ruleset != NULL); + assert(child_ruleset != NULL); + assert(exceptions_arr != NULL); int ret = 0; - if (parent_ruleset == NULL || child_ruleset == NULL || - exceptions_arr == NULL) { - ret = -1; - goto failed; - } - copy_rules_phase(mp, parent_ruleset->phase_request_headers, child_ruleset->phase_request_headers, exceptions_arr); copy_rules_phase(mp, parent_ruleset->phase_request_body, @@ -318,6 +322,8 @@ static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, */ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) { + assert(_parent != NULL); + assert(_child != NULL); directory_config *parent = (directory_config *)_parent; directory_config *child = (directory_config *)_child; directory_config *merged = create_directory_config(mp, NULL); @@ -785,11 +791,14 @@ void init_directory_config(directory_config *dcfg) static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(dcfg != NULL); char *my_error_msg = NULL; //msre_rule *rule = NULL, *tmp_rule = NULL; char *rid = NULL; msre_rule *rule = NULL; extern msc_engine *modsecurity; + assert(modsecurity != NULL); int type_with_lua = 1; int type_rule; int rule_actionset; @@ -1017,9 +1026,12 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(dcfg != NULL); char *my_error_msg = NULL; msre_rule *rule = NULL; extern msc_engine *modsecurity; + assert(modsecurity != NULL); int p; #ifdef DEBUG_CONF @@ -1068,11 +1080,14 @@ static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, const char *p1, const char *p2, int offset) { + assert(cmd != NULL); + assert(dcfg != NULL); char *my_error_msg = NULL; msre_rule *rule = NULL; msre_actionset *new_actionset = NULL; msre_ruleset *ruleset = dcfg->ruleset; extern msc_engine *modsecurity; + assert(modsecurity != NULL); /* Get the ruleset if one exists */ if ((ruleset == NULL)||(ruleset == NOT_SET_P)) { @@ -1151,6 +1166,7 @@ static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL); return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action); @@ -1159,6 +1175,9 @@ static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; if (strlen(p1) != 1) { @@ -1173,6 +1192,9 @@ static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg, static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; if (strlen(p1) != 1) { @@ -1186,6 +1208,9 @@ static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON; @@ -1202,6 +1227,9 @@ static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; dcfg->auditlog_name = (char *)p1; @@ -1239,6 +1267,9 @@ static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; if (dcfg->auditlog_name == NOT_SET_P) { @@ -1281,6 +1312,9 @@ static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; if (is_valid_parts_specification((char *)p1) != 1) { @@ -1294,6 +1328,9 @@ static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; #ifdef WITH_PCRE2 @@ -1311,6 +1348,9 @@ static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL; @@ -1327,6 +1367,9 @@ static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; if (strcasecmp(p1, "JSON") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_JSON; @@ -1343,10 +1386,11 @@ static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "default") == 0) { dcfg->auditlog_dirperms = NOT_SET; } @@ -1365,10 +1409,11 @@ static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "default") == 0) { dcfg->auditlog_fileperms = NOT_SET; } @@ -1387,6 +1432,9 @@ static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = _dcfg; dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1); @@ -1397,6 +1445,9 @@ static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0; @@ -1411,6 +1462,8 @@ static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg, static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); char cwd[1025] = ""; if (cmd->server->is_virtual) { @@ -1442,6 +1495,8 @@ static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */ @@ -1452,14 +1507,17 @@ static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; dcfg->content_injection_enabled = flag; return NULL; } static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; if (cmd->server->is_virtual) { @@ -1473,6 +1531,9 @@ static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; apr_status_t rc; @@ -1503,6 +1564,9 @@ static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; dcfg->col_timeout = atoi(p1); @@ -1515,6 +1579,9 @@ static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg, static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; dcfg->debuglog_level = atoi(p1); @@ -1526,6 +1593,8 @@ static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg, static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; extern msc_engine *modsecurity; char *my_error_msg = NULL; @@ -1602,8 +1671,8 @@ static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; dcfg->disable_backend_compression = flag; return NULL; } @@ -1611,6 +1680,8 @@ static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(p1 != NULL); extern char *guardianlog_name; extern apr_file_t *guardianlog_fd; extern char *guardianlog_condition; @@ -1671,8 +1742,8 @@ static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, */ static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; dcfg->stream_inbody_inspection = flag; return NULL; } @@ -1690,8 +1761,8 @@ static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int */ static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; dcfg->stream_outbody_inspection = flag; return NULL; } @@ -1708,11 +1779,12 @@ static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, in static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRulePerfTime: %s", p1); @@ -1727,6 +1799,10 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, TreeRoot **whitelist, TreeRoot **suspicious_list, const char *filename) { + assert(p2 != NULL); + assert(whitelist != NULL); + assert(suspicious_list != NULL); + assert(filename != NULL); int res = 0; char *config_orig_path; char *param = strchr(p2, ' '); @@ -1801,11 +1877,12 @@ char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ @@ -1829,6 +1906,7 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_read_state_limit(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "SecReadStateLimit is depricated, use SecConnReadStateLimit " \ "instead."); @@ -1850,11 +1928,12 @@ static const char *cmd_read_state_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ @@ -1877,6 +1956,7 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_write_state_limit(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "SecWriteStateLimit is depricated, use SecConnWriteStateLimit " \ "instead."); @@ -1889,11 +1969,12 @@ static const char *cmd_write_state_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1); @@ -1907,11 +1988,12 @@ static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1); @@ -1925,11 +2007,12 @@ static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1); @@ -1943,11 +2026,12 @@ static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyJsonDepthLimit: %s", p1); @@ -1961,11 +2045,12 @@ static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; - if (dcfg == NULL) return NULL; - limit = strtol(p1, NULL, 10); if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecArgumentsLimit: %s", p1); @@ -1979,9 +2064,11 @@ static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1; else if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0; @@ -2004,9 +2091,11 @@ static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1; else if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0; @@ -2020,11 +2109,10 @@ static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + /* ENH Validate encoding */ - dcfg->request_encoding = p1; return NULL; @@ -2033,9 +2121,11 @@ static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1; else if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0; @@ -2048,6 +2138,9 @@ static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -2068,9 +2161,11 @@ static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL; return NULL; @@ -2098,9 +2193,11 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL; return NULL; @@ -2118,6 +2215,9 @@ static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg, static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, const char *_p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(_p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; char *p1 = apr_pstrdup(cmd->pool, _p1); @@ -2136,9 +2236,9 @@ static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, void *_dcfg) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + dcfg->of_mime_types_cleared = 1; if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) { @@ -2162,10 +2262,11 @@ static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); - if (dcfg == NULL) return NULL; - + if(p1 == NULL) { return apr_psprintf(cmd->pool, "Updating target by ID with no ID"); } @@ -2199,10 +2300,11 @@ static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); - if (dcfg == NULL) return NULL; - + if(p1 == NULL) { return apr_psprintf(cmd->pool, "Updating target by tag with no tag"); } @@ -2234,10 +2336,12 @@ static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); - if (dcfg == NULL) return NULL; - + if(p1 == NULL) { return apr_psprintf(cmd->pool, "Updating target by message with no message"); } @@ -2262,10 +2366,11 @@ static const char *cmd_rule(cmd_parms *cmd, void *_dcfg, static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { conn_limits_filter_state = MODSEC_ENABLED; @@ -2289,10 +2394,11 @@ static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { dcfg->is_enabled = MODSEC_ENABLED; @@ -2318,8 +2424,11 @@ static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; + if (strncasecmp(p1, "warn", 4) == 0) { remote_rules_fail_action = REMOTE_RULES_WARN_ON_FAIL; @@ -2340,6 +2449,9 @@ static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2, const char *p3) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); char *error_msg = NULL; directory_config *dcfg = (directory_config *)_dcfg; #ifdef WITH_REMOTE_RULES @@ -2348,8 +2460,6 @@ static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, const char *key = p1; #endif - if (dcfg == NULL) return NULL; - #ifdef WITH_REMOTE_RULES if (strncasecmp(p1, "crypto", 6) == 0) { @@ -2412,6 +2522,8 @@ static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); if (strcasecmp(p1, "on") == 0) { status_engine_state = STATUS_ENGINE_ENABLED; } @@ -2429,8 +2541,8 @@ static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1 static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) { + assert(_dcfg != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; dcfg->rule_inheritance = flag; return NULL; } @@ -2438,7 +2550,9 @@ static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { - #if defined(WITH_LUA) + assert(cmd != NULL); + assert(p1 != NULL); +#if defined(WITH_LUA) const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL); #else @@ -2450,8 +2564,10 @@ static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; rule_exception* re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); if (re == NULL) { ap_log_perror(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, cmd->pool, "cmd_rule_remove_by_id: Cannot allocate memory"); @@ -2481,10 +2597,12 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); - if (dcfg == NULL) return NULL; - + re->type = RULE_EXCEPTION_REMOVE_TAG; re->param = p1; re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); @@ -2506,10 +2624,12 @@ static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); - if (dcfg == NULL) return NULL; - + re->type = RULE_EXCEPTION_REMOVE_MSG; re->param = p1; re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); @@ -2531,6 +2651,8 @@ static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(p1 != NULL); int offset = 0, rule_id = atoi(p1); char *opt = strchr(p1,':'); char *savedptr = NULL; @@ -2553,6 +2675,8 @@ static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg, static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); if (cmd->server->is_virtual) { return "ModSecurity: SecServerSignature not allowed in VirtualHost"; } @@ -2562,10 +2686,11 @@ static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL; else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1); @@ -2574,10 +2699,11 @@ static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL; else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1); @@ -2587,10 +2713,11 @@ static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "default") == 0) { dcfg->upload_file_limit = NOT_SET; } @@ -2604,10 +2731,11 @@ static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg, static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "default") == 0) { dcfg->upload_filemode = NOT_SET; } @@ -2626,10 +2754,11 @@ static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { dcfg->upload_keep_files = KEEP_FILES_ON; } else @@ -2648,10 +2777,11 @@ static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { dcfg->upload_validates_files = 1; @@ -2671,6 +2801,9 @@ static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; /* ENH enforce format (letters, digits, ., _, -) */ @@ -2681,6 +2814,9 @@ static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; /* ENH enforce format (letters, digits, ., _, -) */ @@ -2701,9 +2837,10 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) */ static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { dcfg->xml_external_entity = 1; } @@ -2728,9 +2865,10 @@ static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const ch */ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) { dcfg->hash_is_enabled = HASH_ENABLED; dcfg->hash_enforcement = HASH_ENABLED; @@ -2745,7 +2883,7 @@ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) } /** -* \brief Add SecHashPram configuration option +* \brief Add SecHashParam configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -2755,11 +2893,11 @@ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) */ static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - - if (p1 == NULL) return NULL; dcfg->crypto_param_name = p1; return NULL; @@ -2777,12 +2915,13 @@ static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) */ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(_p1 != NULL); + assert(_p2 != NULL); directory_config *dcfg = (directory_config *)_dcfg; char *p1 = NULL; - if (dcfg == NULL) return NULL; - if (_p1 == NULL) return NULL; - if (strcasecmp(_p1, "Rand") == 0) { p1 = apr_pstrdup(cmd->pool, getkey(cmd->pool)); dcfg->crypto_key = p1; @@ -2793,16 +2932,13 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co dcfg->crypto_key_len = strlen(p1); } - if(_p2 == NULL) { - return NULL; - } else { - if (strcasecmp(_p2, "KeyOnly") == 0) - dcfg->crypto_key_add = HASH_KEYONLY; - else if (strcasecmp(_p2, "SessionID") == 0) - dcfg->crypto_key_add = HASH_SESSIONID; - else if (strcasecmp(_p2, "RemoteIP") == 0) - dcfg->crypto_key_add = HASH_REMOTEIP; - } + if (strcasecmp(_p2, "KeyOnly") == 0) + dcfg->crypto_key_add = HASH_KEYONLY; + else if (strcasecmp(_p2, "SessionID") == 0) + dcfg->crypto_key_add = HASH_SESSIONID; + else if (strcasecmp(_p2, "RemoteIP") == 0) + dcfg->crypto_key_add = HASH_REMOTEIP; + return NULL; } @@ -2820,6 +2956,10 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); + assert(p2 != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); @@ -2827,8 +2967,6 @@ static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, const char *phrase = NULL; const char *next = NULL; - if (dcfg == NULL) return NULL; - p = acmp_create(0, cmd->pool); if (p == NULL) return NULL; @@ -2911,11 +3049,14 @@ static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); + assert(p2 != NULL); directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); - if (dcfg == NULL) return NULL; - + if (strcasecmp(p1, "HashHref") == 0) { re->type = HASH_URL_HREF_HASH_RX; re->param = _p2; @@ -2978,11 +3119,11 @@ static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, */ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - - if (p1 == NULL) return NULL; dcfg->httpBlkey = p1; return NULL; @@ -2993,6 +3134,8 @@ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_pcre_match_limit(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); long val; if (cmd->server->is_virtual) { @@ -3012,6 +3155,8 @@ static const char *cmd_pcre_match_limit(cmd_parms *cmd, static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); long val; if (cmd->server->is_virtual) { @@ -3034,11 +3179,12 @@ static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd, static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); char *error_msg; directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (geo_init(dcfg, filename, &error_msg) <= 0) { return error_msg; } @@ -3060,6 +3206,8 @@ static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, static const char *cmd_unicode_codepage(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); long val; val = atol(p1); @@ -3085,12 +3233,14 @@ static const char *cmd_unicode_codepage(cmd_parms *cmd, static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(p1 != NULL); + assert(p2 != NULL); const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); char *error_msg; long val = 0; directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if(p2 != NULL) { val = atol(p2); if (val <= 0) { @@ -3120,11 +3270,12 @@ static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg, static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg, const char *p1) { + assert(cmd != NULL); + assert(p1 != NULL); const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); char *error_msg; directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - + if (gsb_db_init(dcfg, filename, &error_msg) <= 0) { return error_msg; } @@ -3137,10 +3288,11 @@ static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg, static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, const char *p1, const char *p2) { + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); directory_config *dcfg = (directory_config *)_dcfg; - if (dcfg == NULL) return NULL; - if (strcasecmp(p1, "on") == 0) dcfg->cache_trans = MODSEC_CACHE_ENABLED; else if (strcasecmp(p1, "off") == 0) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 74b6eca9e1..48341774ed 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -675,6 +675,7 @@ static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) * */ static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) { + assert(msr != NULL); apr_time_t time_before; apr_status_t rc = 0; @@ -706,6 +707,7 @@ static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) { * */ static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) { + assert(msr != NULL); apr_time_t time_before, time_after; if (msr->txcfg->debuglog_level >= 4) { diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 136e8ad9cb..0656fc2588 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -21,6 +21,7 @@ const char *base_offset=NULL; int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { assert(msr != NULL); + assert(msr->json != NULL); msc_arg *arg = (msc_arg *) NULL; /** @@ -89,6 +90,7 @@ static int yajl_map_key(void *ctx, const unsigned char *key, size_t length) { modsec_rec *msr = (modsec_rec *) ctx; assert(msr != NULL); + assert(msr->json != NULL); unsigned char *safe_key = (unsigned char *) NULL; /** @@ -168,6 +170,7 @@ static int yajl_number(void *ctx, const char *value, size_t length) static int yajl_start_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; assert(msr != NULL); + assert(msr->json != NULL); if (!msr->json->current_key && !msr->json->prefix) { msr->json->prefix = apr_pstrdup(msr->mp, "array"); @@ -198,6 +201,7 @@ static int yajl_start_array(void *ctx) { static int yajl_end_array(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; assert(msr != NULL); + assert(msr->json != NULL); unsigned char *separator = (unsigned char *) NULL; /** @@ -235,6 +239,7 @@ static int yajl_start_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; assert(msr != NULL); + assert(msr->json != NULL); /** * If we do not have a current_key, this is a top-level hash, so we do not @@ -274,6 +279,7 @@ static int yajl_end_map(void *ctx) { modsec_rec *msr = (modsec_rec *) ctx; assert(msr != NULL); + assert(msr->json != NULL); unsigned char *separator = (unsigned char *) NULL; /** @@ -365,6 +371,7 @@ int json_init(modsec_rec *msr, char **error_msg) { */ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) { assert(msr != NULL); + assert(msr->json != NULL); assert(error_msg != NULL); *error_msg = NULL; base_offset=buf; @@ -393,6 +400,7 @@ int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char */ int json_complete(modsec_rec *msr, char **error_msg) { assert(msr != NULL); + assert(msr->json != NULL); assert(error_msg != NULL); char *json_data = (char *) NULL; @@ -419,6 +427,8 @@ int json_complete(modsec_rec *msr, char **error_msg) { * Frees the resources used for JSON parsing. */ apr_status_t json_cleanup(modsec_rec *msr) { + assert(msr != NULL); + assert(msr->json != NULL); msr_log(msr, 4, "JSON: Cleaning up JSON results"); if (msr->json->handle != NULL) { yajl_free(msr->json->handle); diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 92160adc60..e8236d88a4 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -654,6 +654,7 @@ static void write_rule_json(modsec_rec *msr, const msre_rule *rule, yajl_gen g) * Produce an audit log entry in JSON format. */ void sec_audit_logger_json(modsec_rec *msr) { + assert(msr != NULL); const apr_array_header_t *arr = NULL; apr_table_entry_t *te = NULL; const apr_array_header_t *tarr_pattern = NULL; @@ -1547,6 +1548,7 @@ void sec_audit_logger_json(modsec_rec *msr) { * Produce an audit log entry in native format. */ void sec_audit_logger_native(modsec_rec *msr) { + assert(msr != NULL); const apr_array_header_t *arr = NULL; apr_table_entry_t *te = NULL; const apr_array_header_t *tarr_pattern = NULL; @@ -2235,7 +2237,7 @@ void sec_audit_logger_native(modsec_rec *msr) { sec_auditlog_write(msr, text, strlen(text)); } else { if ((rule != NULL) && (rule->actionset != NULL) && !rule->actionset->is_chained && (rule->chain_starter == NULL)) { - text = apr_psprintf(msr->mp, "%s\n\n", rule->unparsed); + text = apr_psprintf(msr->mp, "%s\n", rule->unparsed); sec_auditlog_write(msr, text, strlen(text)); } } @@ -2327,6 +2329,7 @@ void sec_audit_logger_native(modsec_rec *msr) { */ void sec_audit_logger(modsec_rec *msr) { #ifdef WITH_YAJL + assert(msr != NULL); if (msr->txcfg->auditlog_format == AUDITLOGFORMAT_JSON) { sec_audit_logger_json(msr); } else { diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 7d56dd64e0..ae88c8ef84 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -1317,6 +1317,7 @@ int multipart_process_chunk(modsec_rec *msr, const char *buf, * */ apr_status_t multipart_cleanup(modsec_rec *msr) { + assert(msr != NULL); int keep_files = 0; if (msr->mpd == NULL) return -1; diff --git a/apache2/msc_parsers.c b/apache2/msc_parsers.c index 894c84b9de..9a84e2adf4 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -245,6 +245,7 @@ int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength, apr_table_t *arguments, int *invalid_count) { assert(msr != NULL); + assert(invalid_count != NULL); msc_arg *arg; apr_size_t i, j; char *value = NULL; diff --git a/apache2/msc_reqbody.c b/apache2/msc_reqbody.c index ba8bdfd416..a52af7312b 100644 --- a/apache2/msc_reqbody.c +++ b/apache2/msc_reqbody.c @@ -25,6 +25,7 @@ void msre_engine_reqbody_processor_register(msre_engine *engine, const char *name, void *fn_init, void *fn_process, void *fn_complete) { + assert(engine != NULL); msre_reqbody_processor_metadata *metadata = (msre_reqbody_processor_metadata *)apr_pcalloc(engine->mp, sizeof(msre_reqbody_processor_metadata)); @@ -440,6 +441,7 @@ apr_status_t modsecurity_request_body_store(modsec_rec *msr, apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) { assert(msr != NULL); assert(error_msg != NULL); + assert(buffer != NULL || buflen == 0); #ifndef MSC_LARGE_STREAM_INPUT char *stream_input_body = NULL; char *data = NULL; @@ -819,6 +821,7 @@ apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **err * */ apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) { + assert(msr != NULL); if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) { if (msr->msc_reqbody_fd > 0) { close(msr->msc_reqbody_fd); diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 808f7e9097..2b6681639e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -140,6 +140,8 @@ int xml_complete(modsec_rec *msr, char **error_msg) { * Frees the resources used for XML parsing. */ apr_status_t xml_cleanup(modsec_rec *msr) { + assert(msr != NULL); + assert(msr->xml != NULL); if (msr->xml->parsing_ctx != NULL) { if (msr->xml->parsing_ctx->myDoc) { xmlFreeDoc(msr->xml->parsing_ctx->myDoc); diff --git a/apache2/re.c b/apache2/re.c index 8e69f5bafa..47a390e0df 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -203,6 +203,7 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, const char *p3) { assert(ruleset != NULL); + assert(phase_arr != NULL); msre_rule **rules; int i, j, mode; char *err; @@ -212,7 +213,10 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { msre_rule *rule = (msre_rule *)rules[i]; + assert(rule != NULL); + if (mode == 0) { /* Looking for next rule. */ + assert(rule->actionset != NULL); if (msre_ruleset_rule_matches_exception(rule, re)) { err = update_rule_target_ex(msr, ruleset, rule, p2, p3); if (err) return err; @@ -527,10 +531,12 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r } int msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re) { + assert(rule != NULL); int match = 0; /* Only remove non-placeholder rules */ if (rule->placeholder == RULE_PH_NONE) { + assert(re != NULL); switch(re->type) { case RULE_EXCEPTION_REMOVE_ID : if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { @@ -1468,6 +1474,7 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) rules = (msre_rule **)arr->elts; for (i = 0; i < arr->nelts; i++) { msre_rule *rule = rules[i]; + assert(rule != NULL); rule->execution_time = 0; } @@ -1480,6 +1487,7 @@ apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) rules = (msre_rule **)arr->elts; for (i = 0; i < arr->nelts; i++) { msre_rule *rule = rules[i]; + assert(rule != NULL); /* Ignore markers, which are never processed. */ if (rule->placeholder == RULE_PH_MARKER) continue; @@ -1498,6 +1506,8 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re #else apr_status_t msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr) { #endif + assert(ruleset != NULL); + assert(msr != NULL); apr_array_header_t *arr = NULL; msre_rule **rules; apr_status_t rc; @@ -1542,10 +1552,11 @@ static apr_status_t msre_ruleset_process_phase_(msre_ruleset *ruleset, modsec_re rules = (msre_rule **)arr->elts; for (i = 0; i < arr->nelts; i++) { msre_rule *rule = rules[i]; + assert(rule != NULL); + assert(rule->actionset != NULL); #if defined(PERFORMANCE_MEASUREMENT) apr_time_t time1 = 0; #endif - assert(rule->actionset != NULL); /* Reset the rule interception flag */ msr->rule_was_intercepted = 0; @@ -1974,6 +1985,9 @@ msre_ruleset *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp) { * Adds one rule to the given phase of the ruleset. */ int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) { + assert(ruleset != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); apr_array_header_t *arr = NULL; switch (phase) { @@ -2011,6 +2025,8 @@ int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) { static msre_rule * msre_ruleset_fetch_phase_rule(const msre_ruleset *ruleset, const char *id, const apr_array_header_t *phase_arr, int offset) { + assert(id != NULL); + assert(phase_arr != NULL); msre_rule **rules = (msre_rule **)phase_arr->elts; int i; @@ -2067,6 +2083,7 @@ msre_rule * msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id, int o static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re, apr_array_header_t *phase_arr) { + assert(phase_arr != NULL); msre_rule **rules; int i, j, mode, removed_count; @@ -2084,6 +2101,7 @@ static int msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, /* Only remove non-placeholder rules */ if (rule->placeholder == RULE_PH_NONE) { + assert(re != NULL); switch(re->type) { case RULE_EXCEPTION_REMOVE_ID : if (rule->actionset->id != NULL) { @@ -2304,6 +2322,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) { char * msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, const char *args, const char *actions) { + assert(rule != NULL); char *unparsed = NULL; const char *r_targets = targets; const char *r_args = args; @@ -2363,12 +2382,14 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type, const char *fn, int line, const char *targets, const char *args, const char *actions, char **error_msg) { + assert(ruleset != NULL); + assert(args != NULL); + assert(error_msg != NULL); msre_rule *rule; char *my_error_msg; const char *argsp; int rc; - if (error_msg == NULL) return NULL; *error_msg = NULL; rule = (msre_rule *)apr_pcalloc(ruleset->mp, sizeof(msre_rule)); @@ -2521,6 +2542,8 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, { assert(msr != NULL); assert(actionset != NULL); + assert(actionset->intercept_action_rec != NULL); + assert(actionset->intercept_action_rec->metadata != NULL); const apr_array_header_t *tarr; const apr_table_entry_t *telts; int i; @@ -2534,6 +2557,7 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule, telts = (const apr_table_entry_t*)tarr->elts; for (i = 0; i < tarr->nelts; i++) { msre_action *action = (msre_action *)telts[i].val; + assert(action->metadata != NULL); if (action->metadata->type == ACTION_DISRUPTIVE) { if (action->metadata->execute != NULL) { action->metadata->execute(msr, mptmp, rule, action); @@ -2797,6 +2821,11 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr, * Executes rule against the given transaction. */ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->targets != NULL); + assert(msr != NULL); + assert(msr->txcfg != NULL); const apr_array_header_t *arr = NULL; const apr_table_entry_t *te = NULL; msre_actionset *acting_actionset = NULL; @@ -3343,6 +3372,8 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) { * */ static apr_status_t msre_rule_process_lua(msre_rule *rule, modsec_rec *msr) { + assert(rule != NULL); + assert(msr != NULL); msre_actionset *acting_actionset = NULL; char *my_error_msg = NULL; int rc; @@ -3380,6 +3411,7 @@ static apr_status_t msre_rule_process_lua(msre_rule *rule, modsec_rec *msr) { * */ static apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) { + assert(msr != NULL); /* Use a fresh memory sub-pool for processing each rule */ if (msr->msc_rule_mptmp == NULL) { if (apr_pool_create(&msr->msc_rule_mptmp, msr->mp) != APR_SUCCESS) { diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 36f898dd23..f307119f38 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -27,6 +27,8 @@ static void msre_engine_action_register(msre_engine *engine, const char *name, unsigned int cardinality_group, fn_action_validate_t validate, fn_action_init_t init, fn_action_execute_t execute) { + assert(engine != NULL); + assert(name != NULL); msre_action_metadata *metadata = (msre_action_metadata *)apr_pcalloc(engine->mp, sizeof(msre_action_metadata)); if (metadata == NULL) return; @@ -93,6 +95,8 @@ msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t rvar->value = rval; rvar->value_len = rval_len; + assert(msr != NULL); + assert(msr->txcfg != NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "T (%d) %s: \"%s\"", rc, tfn->name, log_escape_nq_ex(mptmp, rvar->value, rvar->value_len)); @@ -172,6 +176,7 @@ apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header */ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->txcfg != NULL); assert(var != NULL); char *data = NULL; apr_array_header_t *arr = NULL; @@ -321,6 +326,7 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t */ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var) { assert(msr != NULL); + assert(msr->txcfg != NULL); apr_table_t *table = NULL; msc_string *var = NULL; const char *var_name = NULL; @@ -379,6 +385,8 @@ apr_status_t collection_original_setvar(modsec_rec *msr, const char *col_name, c static apr_status_t msre_action_marker_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->id = action->param; return 1; } @@ -388,6 +396,8 @@ static apr_status_t msre_action_marker_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_id_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->id = action->param; return 1; } @@ -414,6 +424,8 @@ static char *msre_action_id_validate(msre_engine *engine, apr_pool_t *mp, msre_a static apr_status_t msre_action_rev_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->rev = action->param; return 1; } @@ -423,6 +435,8 @@ static apr_status_t msre_action_rev_init(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_msg_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->msg = action->param; return 1; } @@ -432,6 +446,8 @@ static apr_status_t msre_action_msg_init(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_logdata_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->logdata = action->param; return 1; } @@ -441,6 +457,8 @@ static apr_status_t msre_action_logdata_init(msre_engine *engine, apr_pool_t *mp static apr_status_t msre_action_sanitizeMatchedBytes_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); char *parse_parm = NULL; char *ac_param = NULL; char *savedptr = NULL; @@ -469,6 +487,8 @@ static apr_status_t msre_action_sanitizeMatchedBytes_init(msre_engine *engine, a static apr_status_t msre_action_accuracy_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->accuracy = atoi(action->param); return 1; } @@ -478,6 +498,8 @@ static apr_status_t msre_action_accuracy_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_maturity_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->maturity = atoi(action->param); return 1; } @@ -487,6 +509,8 @@ static apr_status_t msre_action_maturity_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_ver_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->version = action->param; return 1; } @@ -496,6 +520,8 @@ static apr_status_t msre_action_ver_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_severity_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); if (strcasecmp(action->param, "emergency") == 0) { actionset->severity = 0; } else if (strcasecmp(action->param, "alert") == 0) { @@ -523,6 +549,7 @@ static apr_status_t msre_action_severity_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_chain_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->is_chained = 1; return 1; } @@ -531,6 +558,7 @@ static apr_status_t msre_action_chain_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_log_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->log = 1; return 1; } @@ -539,6 +567,7 @@ static apr_status_t msre_action_log_init(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_nolog_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->log = 0; actionset->auditlog = 0; return 1; @@ -548,6 +577,7 @@ static apr_status_t msre_action_nolog_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_auditlog_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->auditlog = 1; return 1; } @@ -556,6 +586,7 @@ static apr_status_t msre_action_auditlog_init(msre_engine *engine, apr_pool_t *m static apr_status_t msre_action_noauditlog_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->auditlog = 0; return 1; } @@ -564,6 +595,7 @@ static apr_status_t msre_action_noauditlog_init(msre_engine *engine, apr_pool_t static apr_status_t msre_action_block_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); /* Right now we just set a flag and inherit the real disruptive action */ actionset->block = 1; return 1; @@ -573,6 +605,7 @@ static apr_status_t msre_action_block_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_deny_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); actionset->intercept_action = ACTION_DENY; actionset->intercept_action_rec = action; return 1; @@ -587,6 +620,8 @@ static char *msre_action_status_validate(msre_engine *engine, apr_pool_t *mp, ms static apr_status_t msre_action_status_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_status = atoi(action->param); return 1; } @@ -595,6 +630,8 @@ static apr_status_t msre_action_status_init(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_drop_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_DROP; actionset->intercept_action_rec = action; return 1; @@ -609,6 +646,8 @@ static char *msre_action_pause_validate(msre_engine *engine, apr_pool_t *mp, msr static apr_status_t msre_action_pause_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_PAUSE; actionset->intercept_pause = action->param; return 1; @@ -624,6 +663,8 @@ static char *msre_action_redirect_validate(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_redirect_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_REDIRECT; actionset->intercept_uri = action->param; actionset->intercept_action_rec = action; @@ -634,6 +675,8 @@ static apr_status_t msre_action_redirect_execute(modsec_rec *msr, apr_pool_t *mp msre_rule *rule, msre_action *action) { assert(msr != NULL); + assert(rule != NULL); + assert(rule->actionset != NULL); assert(action != NULL); msc_string *var = NULL; @@ -658,6 +701,8 @@ static char *msre_action_proxy_validate(msre_engine *engine, apr_pool_t *mp, msr static apr_status_t msre_action_proxy_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_PROXY; actionset->intercept_uri = action->param; actionset->intercept_action_rec = action; @@ -668,6 +713,7 @@ static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp msre_rule *rule, msre_action *action) { assert(msr != NULL); + assert(rule != NULL); assert(action != NULL); msc_string *var = NULL; @@ -692,6 +738,8 @@ static apr_status_t msre_action_proxy_execute(modsec_rec *msr, apr_pool_t *mptmp static apr_status_t msre_action_pass_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_NONE; actionset->intercept_action_rec = action; return 1; @@ -707,6 +755,8 @@ static char *msre_action_skip_validate(msre_engine *engine, apr_pool_t *mp, msre static apr_status_t msre_action_skip_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->skip_count = atoi(action->param); if (actionset->skip_count <= 0) actionset->skip_count = 1; return 1; @@ -722,6 +772,8 @@ static char *msre_action_skipAfter_validate(msre_engine *engine, apr_pool_t *mp, static apr_status_t msre_action_skipAfter_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->skip_after = action->param; return 1; } @@ -731,6 +783,8 @@ static apr_status_t msre_action_skipAfter_init(msre_engine *engine, apr_pool_t * static apr_status_t msre_action_allow_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); actionset->intercept_action = ACTION_ALLOW; actionset->intercept_action_rec = action; @@ -747,6 +801,7 @@ static apr_status_t msre_action_allow_init(msre_engine *engine, apr_pool_t *mp, } static char *msre_action_allow_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { + assert(action != NULL); if (action->param != NULL) { if (strcasecmp(action->param, "phase") == 0) { return NULL; @@ -771,6 +826,8 @@ static char *msre_action_phase_validate(msre_engine *engine, apr_pool_t *mp, msr static apr_status_t msre_action_phase_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(actionset != NULL); + assert(action != NULL); if(strcasecmp(action->param,"request") == 0) actionset->phase = 2; else if(strcasecmp(action->param,"response") == 0) @@ -786,6 +843,7 @@ static apr_status_t msre_action_phase_init(msre_engine *engine, apr_pool_t *mp, /* t */ static char *msre_action_t_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { + assert(action != NULL); msre_tfn_metadata *metadata = NULL; metadata = msre_engine_tfn_resolve(engine, action->param); if (metadata == NULL) return apr_psprintf(mp, "Invalid transformation function: %s", @@ -797,6 +855,7 @@ static char *msre_action_t_validate(msre_engine *engine, apr_pool_t *mp, msre_ac static apr_status_t msre_action_t_init(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action) { + assert(action != NULL); msre_tfn_metadata *metadata = (msre_tfn_metadata *)action->param_data; action->param_data = metadata; return 1; @@ -804,6 +863,7 @@ static apr_status_t msre_action_t_init(msre_engine *engine, apr_pool_t *mp, msre /* ctl */ static char *msre_action_ctl_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { + assert(action != NULL); char *name = NULL; char *value = NULL; @@ -1332,6 +1392,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, /* xmlns */ static char *msre_action_xmlns_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { + assert(action != NULL); char *name = NULL; char *value = NULL; @@ -1392,12 +1453,14 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo const apr_table_entry_t *telts; int i, type = 0; msc_string *mvar = msr->matched_var; + assert(mvar != NULL); if (mvar->name_len == 0) return 0; /* IMP1 We need to extract the variable name properly here, * taking into account it may have been escaped. */ + assert(mvar->name != NULL); if ((mvar->name_len > 5) && (strncmp(mvar->name, "ARGS:", 5) == 0)) { sargname = apr_pstrdup(msr->mp, mvar->name + 5); type = SANITISE_ARG; @@ -1432,10 +1495,13 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo switch(type) { case SANITISE_ARG : + assert(msr->arguments_to_sanitize != NULL); tarr = apr_table_elts(msr->arguments); + assert(tarr != NULL); telts = (const apr_table_entry_t*)tarr->elts; for (i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; + assert(arg != NULL); if (strcasecmp(sargname, arg->name) == 0) { apr_table_addn(msr->arguments_to_sanitize, arg->name, (void *)arg); } @@ -1443,10 +1509,12 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo break; case SANITISE_REQUEST_HEADER : + assert(msr->request_headers_to_sanitize != NULL); apr_table_set(msr->request_headers_to_sanitize, sargname, "1"); break; case SANITISE_RESPONSE_HEADER : + assert(msr->response_headers_to_sanitize != NULL); apr_table_set(msr->response_headers_to_sanitize, sargname, "1"); break; @@ -1463,7 +1531,9 @@ static apr_status_t msre_action_sanitizeRequestHeader_execute(modsec_rec *msr, a msre_rule *rule, msre_action *action) { assert(msr != NULL); + assert(msr->request_headers_to_sanitize != NULL); assert(action != NULL); + assert(action->param != NULL); apr_table_set(msr->request_headers_to_sanitize, action->param, "1"); return 1; } @@ -1473,7 +1543,9 @@ static apr_status_t msre_action_sanitizeResponseHeader_execute(modsec_rec *msr, msre_rule *rule, msre_action *action) { assert(msr != NULL); + assert(msr->response_headers_to_sanitize != NULL); assert(action != NULL); + assert(action->param != NULL); apr_table_set(msr->response_headers_to_sanitize, action->param, "1"); return 1; } @@ -1484,6 +1556,7 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); char *data = apr_pstrdup(mptmp, action->param); char *env_name = NULL, *env_value = NULL; char *s = NULL; @@ -1501,6 +1574,7 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm *s = '\0'; } + assert(msr->txcfg != NULL); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Setting env variable: %s=%s", env_name, env_value); } @@ -1519,6 +1593,7 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm /* Execute the requested action. */ if (env_name != NULL && env_name[0] == '!') { /* Delete */ + assert(msr->r != NULL); apr_table_unset(msr->r->subprocess_env, env_name + 1); if (msr->txcfg->debuglog_level >= 9) { @@ -1539,6 +1614,7 @@ static apr_status_t msre_action_setenv_execute(modsec_rec *msr, apr_pool_t *mptm expand_macros(msr, val, rule, mptmp); /* To be safe, we escape NULs as it goes in subprocess_env. */ + assert(msr->mp != NULL); val_value = log_escape_nul(msr->mp, (const unsigned char *)val->value, val->value_len); apr_table_set(msr->r->subprocess_env, env_name, val_value); @@ -1749,6 +1825,7 @@ static apr_status_t msre_action_setvar_parse(modsec_rec *msr, apr_pool_t *mptmp, { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); char *data = apr_pstrdup(mptmp, action->param); char *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1776,6 +1853,7 @@ static apr_status_t msre_action_expirevar_execute(modsec_rec *msr, apr_pool_t *m { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -1875,6 +1953,7 @@ static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); char *data = apr_pstrdup(mptmp, action->param); char *col_name = NULL, *var_name = NULL, *var_value = NULL; char *s = NULL; @@ -2010,6 +2089,8 @@ static apr_status_t init_collection(modsec_rec *msr, const char *real_col_name, const char *col_name, const char *col_key, unsigned int col_key_len) { assert(msr != NULL); + assert(msr->collections != NULL); + assert(msr->txcfg != NULL); assert(real_col_name != NULL); apr_table_t *table = NULL; msc_string *var = NULL; @@ -2146,6 +2227,7 @@ static apr_status_t msre_action_initcol_execute(modsec_rec *msr, apr_pool_t *mpt { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); char *data = apr_pstrdup(msr->mp, action->param); char *col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2179,6 +2261,7 @@ static apr_status_t msre_action_setsid_execute(modsec_rec *msr, apr_pool_t *mptm { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2205,6 +2288,7 @@ static apr_status_t msre_action_setuid_execute(modsec_rec *msr, apr_pool_t *mptm { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2231,6 +2315,7 @@ static apr_status_t msre_action_setrsc_execute(modsec_rec *msr, apr_pool_t *mptm { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); msc_string *var = NULL; char *real_col_name = NULL, *col_key = NULL; unsigned int col_key_len; @@ -2252,6 +2337,8 @@ static apr_status_t msre_action_setrsc_execute(modsec_rec *msr, apr_pool_t *mptm /* exec */ static char *msre_action_exec_validate(msre_engine *engine, apr_pool_t *mp, msre_action *action) { + assert(action != NULL); + assert(action->param != NULL); #if defined(WITH_LUA) char *filename = (char *)action->param; @@ -2311,6 +2398,7 @@ static apr_status_t msre_action_prepend_execute(modsec_rec *msr, apr_pool_t *mpt { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); msc_string *var = NULL; /* Expand any macros in the text */ @@ -2333,6 +2421,7 @@ static apr_status_t msre_action_append_execute(modsec_rec *msr, apr_pool_t *mptm { assert(msr != NULL); assert(action != NULL); + assert(action->param != NULL); msc_string *var = NULL; /* Expand any macros in the text */ diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 1d8122638f..612bff9156 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -44,6 +44,8 @@ void msre_engine_op_register(msre_engine *engine, const char *name, fn_op_param_init_t fn1, fn_op_execute_t fn2) { + assert(engine != NULL); + assert(name != NULL); msre_op_metadata *metadata = (msre_op_metadata *)apr_pcalloc(engine->mp, sizeof(msre_op_metadata)); if (metadata == NULL) return; @@ -58,6 +60,7 @@ void msre_engine_op_register(msre_engine *engine, const char *name, * */ msre_op_metadata *msre_engine_op_resolve(msre_engine *engine, const char *name) { + assert(engine != NULL); return (msre_op_metadata *)apr_table_get(engine->operators, name); } @@ -101,13 +104,12 @@ static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, * \retval 0 On Fail */ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(error_msg != NULL); char *param = NULL; int res = 0; - if (error_msg == NULL) - return -1; - else - *error_msg = NULL; + *error_msg = NULL; param = apr_pstrdup(rule->ruleset->mp, rule->op_param); @@ -173,6 +175,8 @@ static int msre_op_ipmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var *v * \retval 0 On Fail */ static int msre_op_ipmatchFromFile_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(error_msg != NULL); const char *rootpath = NULL; const char *filepath = NULL; const char *ipfile_path = NULL; @@ -300,6 +304,8 @@ static int msre_op_ipmatchFromFile_execute(modsec_rec *msr, msre_rule *rule, /* rsub */ static char *param_remove_escape(msre_rule *rule, char *str, int len) { + assert(rule != NULL); + assert(str != NULL); char *parm = apr_pcalloc(rule->ruleset->mp, len); char *ret = parm; @@ -332,6 +338,9 @@ static char *param_remove_escape(msre_rule *rule, char *str, int len) { */ #if !defined(MSC_TEST) static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 ap_regex_t *regex; #else @@ -349,7 +358,6 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { int ignore_case = 0; unsigned short int op_len = 0; - if (error_msg == NULL) return -1; *error_msg = NULL; line = rule->op_param; @@ -686,6 +694,8 @@ static int msre_op_rsub_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, * \retval 0 On fail */ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; msc_regex_t *regex; @@ -961,6 +971,8 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v /* rx */ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; msc_regex_t *regex; @@ -1282,6 +1294,9 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c /* pm */ static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); ACMP *p; const char *phrase; const char *next; @@ -1320,6 +1335,9 @@ static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) { /* pmFromFile */ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); char errstr[1024]; char buf[HUGE_STRING_LEN + 1]; char *fn = NULL; @@ -1567,7 +1585,7 @@ static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c * \retval url On Success */ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int len) { - + assert(domain != NULL); char *pos = NULL, *data = NULL; char *url = NULL; int match = 0; @@ -1605,7 +1623,7 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l * \retval reduced On Success */ static const char *gsb_reduce_char(apr_pool_t *pool, const char *domain) { - + assert(domain != NULL); char *ptr = apr_pstrdup(pool, domain); char *data = NULL; char *reduced = NULL; @@ -1712,6 +1730,8 @@ static int verify_gsb(gsb_db *gsb, modsec_rec *msr, const char *match, unsigned * \retval 0 On Fail */ static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; int options = 0; @@ -2095,6 +2115,10 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var /* within */ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { + assert(msr != NULL); + assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); const char *match = NULL; const char *target; @@ -2255,7 +2279,6 @@ static int msre_op_detectSQLi_execute(modsec_rec *msr, msre_rule *rule, msre_var assert(rule->actionset != NULL); assert(rule->actionset->actions != NULL); assert(var != NULL); - assert(var != NULL); assert(error_msg != NULL); char fingerprint[8]; int issqli; @@ -2292,6 +2315,7 @@ static int msre_op_detectXSS_execute(modsec_rec *msr, msre_rule *rule, msre_var assert(rule != NULL); assert(rule->actionset != NULL); assert(rule->actionset->actions != NULL); + assert(var != NULL); assert(error_msg != NULL); int capture; int is_xss; @@ -2554,6 +2578,8 @@ static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); + assert(var != NULL); + assert(error_msg != NULL); const char *match = NULL; const char *target; unsigned int match_length; @@ -2619,12 +2645,14 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var * /* strmatch */ static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); const apr_strmatch_pattern *compiled_pattern; char *processed = NULL; const char *pattern = rule->op_param; unsigned short int op_len; - if (error_msg == NULL) return -1; *error_msg = NULL; op_len = strlen(pattern); @@ -2854,6 +2882,7 @@ static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre * Luhn Mod-10 Method (ISO 2894/ANSI 4.13) */ static int luhn_verify(const char *ccnumber, int len) { + assert(ccnumber != NULL); int sum[2] = { 0, 0 }; int odd = 0; int digits = 0; @@ -2887,6 +2916,9 @@ static int luhn_verify(const char *ccnumber, int len) { } static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; int options = 0; @@ -2916,6 +2948,7 @@ static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) { assert(msr != NULL); assert(rule != NULL); + assert(rule->actionset != NULL); assert(var != NULL); assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; @@ -3119,7 +3152,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * * \retval 1 On Valid CPF */ static int cpf_verify(const char *cpfnumber, int len) { - + assert(cpfnumber != NULL); int factor, part_1, part_2, var_len = len; unsigned int sum = 0, i = 0, cpf_len = 11, c; int cpf[11]; @@ -3207,12 +3240,14 @@ static int cpf_verify(const char *cpfnumber, int len) { * \retval 1 On Success */ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; int options = 0; msc_regex_t *regex; - if (error_msg == NULL) return -1; *error_msg = NULL; #ifdef WITH_PCRE2 @@ -3527,6 +3562,9 @@ static int ssn_verify(modsec_rec *msr, const char *ssnumber, int len) { * \retval 1 On Success */ static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); const char *errptr = NULL; int erroffset; int options = 0; @@ -4085,6 +4123,9 @@ static int msre_op_rbl_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, /* fuzzyHash */ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; struct fuzzy_hash_chunk *chunk, *t; @@ -4105,11 +4146,6 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) threshold_str = data; #endif - if (error_msg == NULL) - { - return -1; - } - *error_msg = NULL; #ifdef WITH_SSDEEP @@ -4241,9 +4277,11 @@ static int msre_op_fuzzy_hash_execute(modsec_rec *msr, msre_rule *rule, /* inspectFile */ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); char *filename = (char *)rule->op_param; - if (error_msg == NULL) return -1; *error_msg = NULL; if ((filename == NULL)||(is_empty_string(filename))) { @@ -4346,6 +4384,9 @@ static int msre_op_inspectFile_execute(modsec_rec *msr, msre_rule *rule, msre_va /* validateByteRange */ static int msre_op_validateByteRange_init(msre_rule *rule, char **error_msg) { + assert(rule != NULL); + assert(rule->ruleset != NULL); + assert(error_msg != NULL); char *p = NULL, *saveptr = NULL; char *table = NULL, *data = NULL; @@ -4671,6 +4712,7 @@ static int msre_op_eq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, { assert(msr != NULL); assert(rule != NULL); + assert(var != NULL); assert(error_msg != NULL); msc_string str; int left, right; diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 5aa7589a2b..a37124d5f3 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -30,6 +30,9 @@ static int var_simple_generate_ex(msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp, const char *value, int value_len) { + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = NULL; if (value == NULL) return 0; @@ -57,6 +60,9 @@ static int var_simple_generate(msre_var *var, apr_table_t *vartab, apr_pool_t *m * care of the case when the parameter is a regular expression. */ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { + assert(ruleset != NULL); + assert(var != NULL); + /* It's OK if there's no parameter. */ if (var->param == NULL) return NULL; @@ -112,6 +118,7 @@ static int var_args_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Figure out if we want to include this argument. */ @@ -162,6 +169,7 @@ static int var_args_combined_size_generate(modsec_rec *msr, msre_var *var, msre_ te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); combined_size += arg->name_len; combined_size += arg->value_len; } @@ -191,6 +199,7 @@ static int var_args_names_generate(modsec_rec *msr, msre_var *var, msre_rule *ru te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Figure out if we want to include this variable. */ @@ -239,6 +248,7 @@ static int var_args_get_generate(modsec_rec *msr, msre_var *var, msre_rule *rule te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Only QUERY_STRING arguments */ @@ -290,6 +300,7 @@ static int var_args_get_names_generate(modsec_rec *msr, msre_var *var, msre_rule te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Only QUERY_STRING arguments */ @@ -341,6 +352,7 @@ static int var_args_post_generate(modsec_rec *msr, msre_var *var, msre_rule *rul te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Only BODY arguments */ @@ -392,6 +404,7 @@ static int var_args_post_names_generate(modsec_rec *msr, msre_var *var, msre_rul te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_arg *arg = (msc_arg *)te[i].val; + assert(arg != NULL); int match = 0; /* Only BODY arguments */ @@ -476,6 +489,7 @@ static int var_rule_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static char *var_env_validate(msre_ruleset *ruleset, msre_var *var) { assert(ruleset != NULL); + assert(var != NULL); if (var->param == NULL) { return apr_psprintf(ruleset->mp, "Parameter required for ENV."); } @@ -491,6 +505,7 @@ static int var_env_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); assert(var != NULL); char *value = get_env_var(msr->r, (char *)var->param); if (value != NULL) { @@ -505,6 +520,7 @@ static int var_request_uri_raw_generate(modsec_rec *msr, msre_var *var, msre_rul apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri); } @@ -551,6 +567,8 @@ static int var_reqbody_processor_generate(modsec_rec *msr, msre_var *var, msre_r apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); if (!rvar) { msr_log(msr, 1, "REQBODY_PROCESSOR: Memory allocation error"); @@ -575,7 +593,6 @@ static int var_sdbm_delete_error_generate(modsec_rec *msr, msre_var *var, msre_r apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); - assert(msr->r != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -602,6 +619,9 @@ static int var_reqbody_processor_error_generate(modsec_rec *msr, msre_var *var, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); if (!rvar) { msr_log(msr, 1, "REQBODY_ERROR: Memory allocation error"); @@ -622,7 +642,6 @@ static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *v { assert(msr != NULL); assert(var != NULL); - assert(rule != NULL); assert(vartab != NULL); assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); @@ -647,6 +666,8 @@ static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *v /* XML */ static char *var_xml_validate(msre_ruleset *ruleset, msre_var *var) { + assert(var != NULL); + /* It's OK if there's no parameter. */ if (var->param == NULL) return NULL; @@ -835,6 +856,8 @@ static int var_remote_addr_generate(modsec_rec *msr, msre_var *var, msre_rule *r #if !defined(MSC_TEST) #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 3 if (ap_find_linked_module("mod_remoteip.c") != NULL) { + assert(msr->r != NULL); + assert(msr->r->useragent_ip != NULL); if(msr->r->useragent_ip != NULL) msr->remote_addr = apr_pstrdup(msr->mp, msr->r->useragent_ip); return var_simple_generate(var, vartab, mptmp, msr->remote_addr); } @@ -850,6 +873,7 @@ static int var_remote_host_generate(modsec_rec *msr, msre_var *var, msre_rule *r apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); const char *value1 = ap_get_remote_host(msr->r->connection, msr->r->per_dir_config, REMOTE_NAME, NULL); return var_simple_generate(var, vartab, mptmp, value1); @@ -888,9 +912,11 @@ static int var_tx_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, int i, count = 0; arr = apr_table_elts(msr->tx_vars); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -944,9 +970,11 @@ static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, int i, count = 0; arr = apr_table_elts(msr->geo_vars); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -983,6 +1011,7 @@ static int var_geo_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, static int var_highest_severity_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); return var_simple_generate(var, vartab, mptmp, apr_psprintf(mptmp, "%d", msr->highest_severity)); } @@ -993,6 +1022,7 @@ static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->collections != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -1005,9 +1035,11 @@ static int var_ip_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, if (target_col == NULL) return 0; arr = apr_table_elts(target_col); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -1073,6 +1105,7 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->collections != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -1088,6 +1121,7 @@ static int var_session_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -1129,6 +1163,7 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->collections != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -1144,6 +1179,7 @@ static int var_user_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -1189,6 +1225,7 @@ static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->collections != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -1204,6 +1241,7 @@ static int var_global_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -1241,6 +1279,7 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->collections != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -1256,6 +1295,7 @@ static int var_resource_generate(modsec_rec *msr, msre_var *var, msre_rule *rule te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); int match; /* Figure out if we want to include this variable. */ @@ -1304,6 +1344,7 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var, int i, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for (i = 0; i < msr->mpd->parts->nelts; i++) @@ -1405,9 +1446,11 @@ static int var_files_tmpnames_generate(modsec_rec *msr, msre_var *var, msre_rule int i, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); if ((parts[i]->type == MULTIPART_FILE)&&(parts[i]->tmp_file_name != NULL)) { int match = 0; @@ -1454,9 +1497,11 @@ static int var_files_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, int i, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); if (parts[i]->type == MULTIPART_FILE) { int match = 0; @@ -1503,9 +1548,11 @@ static int var_files_sizes_generate(modsec_rec *msr, msre_var *var, msre_rule *r int i, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); if (parts[i]->type == MULTIPART_FILE) { int match = 0; @@ -1552,9 +1599,11 @@ static int var_files_names_generate(modsec_rec *msr, msre_var *var, msre_rule *r int i, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); if (parts[i]->type == MULTIPART_FILE) { msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); if (!rvar) { @@ -1591,6 +1640,7 @@ static int var_files_combined_size_generate(modsec_rec *msr, msre_var *var, msre if (msr->mpd != NULL) { parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); if (parts[i]->type == MULTIPART_FILE) { combined_size += parts[i]->tmp_file_size; } @@ -1622,9 +1672,11 @@ static int var_multipart_part_headers_generate(modsec_rec *msr, msre_var *var, m int i, j, count = 0; if (msr->mpd == NULL) return 0; + assert(msr->mpd->parts != NULL); parts = (multipart_part **)msr->mpd->parts->elts; for(i = 0; i < msr->mpd->parts->nelts; i++) { + assert(parts[i] != NULL); int match = 0; /* Figure out if we want to include this variable. */ @@ -1937,6 +1989,7 @@ static int var_outbound_error_generate(modsec_rec *msr, msre_var *var, msre_rule } static apr_time_t calculate_perf_combined(modsec_rec *msr) { + assert(msr != NULL); return msr->time_phase1 + msr->time_phase2 + msr->time_phase3 + msr->time_phase4 + msr->time_phase5 + msr->time_storage_write /* time_storage_read is already included in phases */ + msr->time_logging + msr->time_gc; @@ -1957,9 +2010,8 @@ char *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp) { static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp, apr_time_t value) { - assert(msr != NULL); assert(var != NULL); - assert( vartab!= NULL); + assert(vartab != NULL); assert(mptmp != NULL); msre_var *rvar = NULL; @@ -1977,7 +2029,6 @@ static int generate_performance_variable(modsec_rec *msr, msre_var *var, msre_ru static int var_perf_all_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { - assert(msr != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -2096,6 +2147,7 @@ static int var_perf_rules_generate(modsec_rec *msr, msre_var *var, msre_rule *ru int i, count = 0; arr = apr_table_elts(msr->perf_rules); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -2359,11 +2411,6 @@ static int var_time_mon_generate(modsec_rec *msr, msre_var *var, msre_rule *rule tm = localtime(&tc); rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); assert(msr != NULL); - assert(msr->r != NULL); - assert(var != NULL); - assert(rule != NULL); - assert(vartab != NULL); - assert(mptmp != NULL); if (!rvar) { msr_log(msr, 1, "TIME_MON: Memory allocation error"); return -1; @@ -2385,7 +2432,6 @@ static int var_time_day_generate(modsec_rec *msr, msre_var *var, msre_rule *rule apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); - assert(msr->r != NULL); assert(var != NULL); assert(vartab != NULL); assert(mptmp != NULL); @@ -2465,6 +2511,10 @@ static int var_request_basename_generate(modsec_rec *msr, msre_var *var, msre_ru static int var_full_request_generate(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *vartab, apr_pool_t *mptmp) { + assert(msr != NULL); + assert(var != NULL); + assert(vartab != NULL); + assert(mptmp != NULL); const apr_array_header_t *arr = NULL; char *full_request = NULL; int full_request_length = 0; @@ -2585,6 +2635,7 @@ static int var_matched_vars_names_generate(modsec_rec *msr, msre_var *var, msre_ for (i = 0; i < arr->nelts; i++) { int match = 0; msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; @@ -2650,10 +2701,12 @@ static int var_matched_vars_generate(modsec_rec *msr, msre_var *var, msre_rule * int i, count = 0; arr = apr_table_elts(msr->matched_vars); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; msc_string *str = (msc_string *)te[i].val; + assert(str != NULL); /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; @@ -2719,6 +2772,7 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul int i, count = 0; arr = apr_table_elts(msr->request_cookies); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -2726,6 +2780,7 @@ static int var_request_cookies_generate(modsec_rec *msr, msre_var *var, msre_rul /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -2774,6 +2829,7 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms int i, count = 0; arr = apr_table_elts(msr->request_cookies); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -2781,6 +2837,7 @@ static int var_request_cookies_names_generate(modsec_rec *msr, msre_var *var, ms /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -2829,6 +2886,7 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul int i, count = 0; arr = apr_table_elts(msr->request_headers); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -2836,6 +2894,7 @@ static int var_request_headers_generate(modsec_rec *msr, msre_var *var, msre_rul /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -2884,6 +2943,7 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms int i, count = 0; arr = apr_table_elts(msr->request_headers); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -2891,6 +2951,7 @@ static int var_request_headers_names_generate(modsec_rec *msr, msre_var *var, ms /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -2931,6 +2992,7 @@ static int var_request_filename_generate(modsec_rec *msr, msre_var *var, msre_ru apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path); } @@ -3090,6 +3152,7 @@ static int var_auth_type_generate(modsec_rec *msr, msre_var *var, msre_rule *rul apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); char *value = msr->r->ap_auth_type; return var_simple_generate(var, vartab, mptmp, value); } @@ -3100,6 +3163,8 @@ static int var_path_info_generate(modsec_rec *msr, msre_var *var, msre_rule *rul apr_table_t *vartab, apr_pool_t *mptmp) { assert(msr != NULL); + assert(msr->r != NULL); + assert(mptmp != NULL); const char *value = msr->r->path_info; return var_simple_generate(var, vartab, mptmp, value); } @@ -3162,6 +3227,7 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru if (msr->response_headers == NULL) return 0; arr = apr_table_elts(msr->response_headers); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -3169,6 +3235,7 @@ static int var_response_headers_generate(modsec_rec *msr, msre_var *var, msre_ru /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -3217,6 +3284,7 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m int i, count = 0; arr = apr_table_elts(msr->response_headers); + assert(arr != NULL); te = (apr_table_entry_t *)arr->elts; for (i = 0; i < arr->nelts; i++) { int match = 0; @@ -3224,6 +3292,7 @@ static int var_response_headers_names_generate(modsec_rec *msr, msre_var *var, m /* Figure out if we want to include this variable. */ if (var->param == NULL) match = 1; else { + assert(te[i].key != NULL); if (var->param_data != NULL) { /* Regex. */ char *my_error_msg = NULL; if (!(msc_regexec((msc_regex_t *)var->param_data, te[i].key, @@ -3350,6 +3419,7 @@ void msre_engine_variable_register(msre_engine *engine, const char *name, fn_var_validate_t validate, fn_var_generate_t generate, unsigned int is_cacheable, unsigned int availability) { + assert(engine != NULL); msre_var_metadata *metadata = (msre_var_metadata *)apr_pcalloc(engine->mp, sizeof(msre_var_metadata)); if (metadata == NULL) return; @@ -3370,6 +3440,7 @@ void msre_engine_variable_register(msre_engine *engine, const char *name, * */ void msre_engine_register_default_variables(msre_engine *engine) { + assert(engine != NULL); /* ARGS */ msre_engine_variable_register(engine, From 8723294cd188264d00b96bd925728737e60a4b66 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 2 Aug 2024 11:19:34 +0200 Subject: [PATCH 426/477] Search for errors/warnings in error log and stop if found --- .github/workflows/ci.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4694c50711..4eed4ef654 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,14 @@ jobs: run: sudo apachectl configtest - name: start apache with module run: sudo systemctl restart apache2.service + - name: Search for errors/warnings in error log + run: | + errors="$(grep -E ":(?error|warn)[]]" /var/log/apache2/error.log)" + if [ -n "${errors}" ]; then + echo "Found errors/warnings in error.log" + echo "${errors}" + exit 1 + fi - name: Show httpd error log if: always() run: sudo cat /var/log/apache2/error.log From 4399ee9ba9ad73fcf3d8ced2dfaedd6653cb2266 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 2 Aug 2024 11:28:07 +0200 Subject: [PATCH 427/477] Fixed quotes --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4eed4ef654..516d5b210e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: run: sudo systemctl restart apache2.service - name: Search for errors/warnings in error log run: | - errors="$(grep -E ":(?error|warn)[]]" /var/log/apache2/error.log)" + errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) if [ -n "${errors}" ]; then echo "Found errors/warnings in error.log" echo "${errors}" From f5bbb0b8516cce33fca8f043f872f0a7a0dc6c51 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 2 Aug 2024 11:43:09 +0200 Subject: [PATCH 428/477] Fixed exit code in case of success --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 516d5b210e..9ec469c1a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,11 +52,12 @@ jobs: - name: Search for errors/warnings in error log run: | errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) - if [ -n "${errors}" ]; then + if [[ -n "${errors}" ]]; then echo "Found errors/warnings in error.log" echo "${errors}" exit 1 fi + exit 0 - name: Show httpd error log if: always() run: sudo cat /var/log/apache2/error.log From 5de53cc72897f7e7e5dead81205f0ed3c4958293 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 2 Aug 2024 12:11:16 +0200 Subject: [PATCH 429/477] handles the case grep doesn't match, otherwise the script exits with 1 (error) --- .github/workflows/ci.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9ec469c1a7..5e6e58392d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,13 +51,12 @@ jobs: run: sudo systemctl restart apache2.service - name: Search for errors/warnings in error log run: | - errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) - if [[ -n "${errors}" ]]; then - echo "Found errors/warnings in error.log" - echo "${errors}" - exit 1 - fi - exit 0 + # '|| :' handles the case grep doesn't match, otherwise the script exits with 1 (error) + errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) || : + if [[ -z "${errors}" ]]; then exit 0; fi + echo "Found errors/warnings in error.log" + echo "${errors}" + exit 1 - name: Show httpd error log if: always() run: sudo cat /var/log/apache2/error.log From ccebb58c94947cc4dc6475cf133fdc4e8d4e7ccc Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sat, 3 Aug 2024 16:22:45 +0200 Subject: [PATCH 430/477] Add PR's to CHANGES --- CHANGES | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 80d8520c47..3a9e5c2574 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,77 @@ -DD mmm YYYY - 2.9.x (to be released) +DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Move xmlFree() call to the right place + [Issue #3199 - @airween] + * Add collection size in log in case of writing error + [Issue #3198 - @marcstern] + * Passing address of lock instead of lock in acquire_global_lock() + [Issue #3188 - @marcstern] + * Invalid pointer access in case rule id == NOT_SET_P + [Issue #3187 - @marcstern] + * Show error.log after httpd start in CI + [Issue #3171 - @marcstern] + * chore: add pull request template + [Issue #3159 - @fzipi] + * chore: add gitignore file + [Issue #3158 - @fzipi] + * Possible double free + [Issue #3155 - @marcstern] + * Set 'jit' variable's initial value + [Issue #3154 - @marcstern] + * Missing null byte + optimization + [Issue #3153 - @marcstern] + * fix: remove usage of insecure tmpnam + [Issue #3149 - @fzipi] + * docs: update copyright + [Issue #3148 - @fzipi] + * Enhanced logging [Issue #3107] + [Issue #3139 - @marcstern] + * Check for null pointer dereference (almost) everywhere + [Issue #3120 - @marcstern] + * Fix possible segfault in collection_unpack + [Issue #3099 - @twouters] + * fix: Replace obsolote macros + [Issue #3094 - @airween] + * chore: update bug-report-for-version-2-x.md + [Issue #3087 - @fzipi] + * feat: Add more steps: install built module and restart the server + [Issue #3078 - @airween] + * Add new flag: --without-lua + [Issue #3076 - @airween] + * Initial release of CI worklow + [Issue #3075 - @airween] + * V2/fixbuildissue + [Issue #3074 - @airween] + * ; incorrectly replaced by space in cmdline + [Issue #3051 - @marcstern] + * Detailed error message when writing collections + [Issue #3050 - @marcstern] + * docs: Fix organization name in references and security e-mail (v2) + [Issue #3043 - @airween] + * ctl:ruleRemoveByTag isn't executed if no rule id is present in the rule + [Issue #3012 - @marcstern] + * Suppress useless loop on tag matching + [Issue #3009 - @marcstern] + * Optimization: Avoid last loop and storing an empty value in case nothing + after last %{..} macro + [Issue #3004 - @marcstern] + * Ignore (consistently) empty actions + [Issue #3003 - @marcstern] + * Add context info to error message + [Issue #2997 - @marcstern] + * Implement msre_action_phase_validate() + [Issue #2994 - @marcstern] + * Avoid some useless code and memory allocation in case no macro is present + [Issue #2992 - @marcstern] + * 'jit' variable not initialized when WITH_PCRE2 is defined + [Issue #2987 - @marcstern] + * Configure: do not check for pcre1 if pcre2 requested + [Issue #2975 - @martinhsv] + * Double memory allocation + [Issue #2969 - @marcstern] + * Fix for DEBUG_CONF compile flag + [Issue #2963 - @marcstern] * Enhance logging [Issue #3107 - @marcstern] * Fix possible segfault in collection_unpack From 8dd5d5f46ba1d9588b23c7b64fd3a45bddfb5117 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 7 Aug 2024 09:42:40 +0200 Subject: [PATCH 431/477] re_operators.c: removed invalid check (done correctly on line 1067) copy_rules(): only one return code => void --- apache2/apache2_config.c | 10 ++-------- apache2/re_operators.c | 4 ---- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index cc37d8eb9e..895c0b4252 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -293,15 +293,14 @@ static void copy_rules_phase(apr_pool_t *mp, * @retval -1 Something went wrong. * */ -static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, +static void copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, msre_ruleset *child_ruleset, apr_array_header_t *exceptions_arr) { assert(parent_ruleset != NULL); assert(child_ruleset != NULL); assert(exceptions_arr != NULL); - int ret = 0; - + copy_rules_phase(mp, parent_ruleset->phase_request_headers, child_ruleset->phase_request_headers, exceptions_arr); copy_rules_phase(mp, parent_ruleset->phase_request_body, @@ -312,9 +311,6 @@ static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, child_ruleset->phase_response_body, exceptions_arr); copy_rules_phase(mp, parent_ruleset->phase_logging, child_ruleset->phase_logging, exceptions_arr); - -failed: - return ret; } /** @@ -439,7 +435,6 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) /* Copy the rules from the parent context. */ merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); - /* TODO: copy_rules return code should be taken into consideration. */ copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); } else if (parent->ruleset == NULL) { @@ -466,7 +461,6 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) /* Copy parent rules, then add child rules to it. */ merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); - /* TODO: copy_rules return code should be taken into consideration. */ copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); apr_array_cat(merged->ruleset->phase_request_headers, diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 612bff9156..73b0d8fb49 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1037,10 +1037,6 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c assert(var != NULL); assert(error_msg != NULL); msc_regex_t *regex = (msc_regex_t *)rule->op_param_data; - if (!regex) { - msr_log(msr, 1, "rx: Memory allocation error"); - return -1; - } msc_string *re_pattern = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (!re_pattern) { msr_log(msr, 1, "rx: Memory allocation error"); From 692710cab7a1bbe13ac9dd8ae3f42c02c64595b6 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 7 Aug 2024 13:45:09 +0200 Subject: [PATCH 432/477] Replaced 0 by '\0' for char --- apache2/re_operators.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 30176c5149..5beccc8d43 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -1565,7 +1565,7 @@ static const char *gsb_replace_tpath(apr_pool_t *pool, const char *domain, int l data = apr_palloc(pool, len + 1); if (!data) return NULL; - url[len] = 0; + url[len] = '\0'; while(( pos = strstr(url , "/./" )) != NULL) { match = 1; From 686a74173ff1a7d3fbca777194643980bd278760 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 7 Aug 2024 17:01:20 +0200 Subject: [PATCH 433/477] # Send some requests & check log format --- .github/workflows/ci.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c32ce189a..d4925d441d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,4 +49,14 @@ jobs: run: | sudo systemctl restart apache2.service sudo cat /var/log/apache2/error.log - + - name: Check error.log + run: | + # Send requests & check log format + # Valid request + curl -s http://127.0.01/ > /dev/null || echo $? + # Invalid request + curl -s http://127.0.01/%2e%2f > /dev/null || echo $? + # Check log format + grep -F ModSecurity < /var/log/apache2/error.log | grep -vP "^\[[^\]]+\] \[security2:[a-z]+\] \[pid [0-9]+:tid [0-9]+\] (?:\[client [0-9.:]+\] )?ModSecurity" || exit 0 + # grep -v succeeded => found some lines with invalid format + exit 1 From d704af657ca8ea10400fdb60424ef57c42719245 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 8 Aug 2024 16:16:14 +0200 Subject: [PATCH 434/477] Define _FORTIFY_SOURCE=3 & _GLIBCXX_ASSERTIONS that add glibc/libstdc++ assertions. See https://www.gnu.org/software/libc/manual/html_node/Source-Fortification.html & https://gcc.gnu.org/wiki/LibstdcxxDebugMode _GLIBCXX_ASSERTIONS is probably useless as we have pure C here, but let's define it in case some checks are included (or will be in a future version). As we handle some requests here, that may help to trap a problem. --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c75335c14d..69228a6b93 100644 --- a/configure.ac +++ b/configure.ac @@ -309,10 +309,10 @@ fi AC_ARG_ENABLE(assertions, AS_HELP_STRING([--enable-assertions], - [Turn on assertions checks (undefine NDEBUG)]), + [Turn on assertions checks (undefine NDEBUG, define _GLIBCXX_ASSERTIONS & _FORTIFY_SOURCE)]), [ if test "${enableval}" = "yes"; then - assertions='-UNDEBUG' + assertions='-UNDEBUG -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS' else assertions='-DNDEBUG' fi From d32c8f1ad8b6b8e33661a94e3c0faee626fa59d6 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 12 Aug 2024 17:06:35 +0200 Subject: [PATCH 435/477] Fixed invalid logging --- apache2/re.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 56aebea420..6b2753e0d5 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -489,11 +489,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r end: if (my_error_msg) { if (msr) msr_log(msr, 9, my_error_msg); -#if !defined(MSC_TEST) - else { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, " ModSecurity: Successfully appended variable"); - } -#endif + else ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, my_error_msg); } if (target_list != NULL) free(target_list); if (replace != NULL) free(replace); From f27c85cf472465377e9658723ddfadb44a25118d Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 13 Aug 2024 11:07:18 +0200 Subject: [PATCH 436/477] Check if the MP header contains invalid character --- apache2/msc_multipart.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c index 7d56dd64e0..92f466e3db 100644 --- a/apache2/msc_multipart.c +++ b/apache2/msc_multipart.c @@ -402,7 +402,7 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { if (msr->mpd->mpp->last_header_line != NULL) { *(char **)apr_array_push(msr->mpd->mpp->header_lines) = msr->mpd->mpp->last_header_line; msr_log(msr, 9, "Multipart: Added part header line \"%s\"", msr->mpd->mpp->last_header_line); - } + } data = msr->mpd->buf; @@ -424,6 +424,16 @@ static int multipart_process_part_header(modsec_rec *msr, char **error_msg) { return -1; } + /* check if multipart header contains any invalid characters */ + char *ch = header_name; + while(*ch != '\0') { + if (*ch < 33 || *ch > 126) { + *error_msg = apr_psprintf(msr->mp, "Multipart: Invalid part header (contains invalid character)."); + return -1; + } + ch++; + } + /* extract the value value */ data++; while((*data == '\t') || (*data == ' ')) data++; From e6e3417e9d642eadac2136c1ded2f36cc5cf5b92 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 13 Aug 2024 11:07:44 +0200 Subject: [PATCH 437/477] Remove unnecessary assert() --- apache2/re_variables.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index b3ea4fac34..5bf307af98 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -616,7 +616,6 @@ static int var_reqbody_processor_error_msg_generate(modsec_rec *msr, msre_var *v { assert(msr != NULL); assert(var != NULL); - assert(rule != NULL); assert(vartab != NULL); assert(mptmp != NULL); msre_var *rvar = apr_pmemdup(mptmp, var, sizeof(msre_var)); From ffecae98d3159c9a985dab422fd685f18d0d5013 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 13 Aug 2024 19:35:17 +0200 Subject: [PATCH 438/477] Update CHANGES --- CHANGES | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGES b/CHANGES index 3a9e5c2574..87e8e76f6f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Use standard httpd logging format in error log + [PR #3192 - @marcstern] + * fix msc_regexec() != PCRE_ERROR_NOMATCH strict check + [PR #3194 - @marcstern] * Move xmlFree() call to the right place [Issue #3199 - @airween] * Add collection size in log in case of writing error From 0a9e0aa67baeac4dc2615341803447e8463058a7 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 14 Aug 2024 09:32:08 +0200 Subject: [PATCH 439/477] Added PR #3226 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 87e8e76f6f..90f6dbced9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * feat: Check if the MP header contains invalid character + [PR #3226 - @airween] * Use standard httpd logging format in error log [PR #3192 - @marcstern] * fix msc_regexec() != PCRE_ERROR_NOMATCH strict check From 04dff87623e45a36cc37c15ef148a1dfd2cfba2f Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 14 Aug 2024 10:59:56 +0200 Subject: [PATCH 440/477] Added PR #3193 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 90f6dbced9..2345822f31 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Removed useless code + [PR #3193 - @marcstern] * feat: Check if the MP header contains invalid character [PR #3226 - @airween] * Use standard httpd logging format in error log From 1680f5be9065fdd8aaefe96a8674c0c2c3f3e28c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 12:56:59 +0200 Subject: [PATCH 441/477] removed comment --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e6e58392d..18601e321f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,4 +63,3 @@ jobs: - name: Show mod_security2 audit log if: always() run: sudo cat /var/log/apache2/modsec_audit.log - # For non-regression tests: /home/runner/work/ModSecurity/ModSecurity/tests/regression/server_root/logs/audit/audit.log From e5bbd89399fe98280ba4dafb4b2693a8f1a660e2 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 13:53:52 +0200 Subject: [PATCH 442/477] re-added some NULL check at run-time, with an error message on stderr --- apache2/apache2_config.c | 274 ++++++++++++++++++++++++++++++++++++++- apache2/re.c | 5 + apache2/re_operators.c | 27 ++++ 3 files changed, 305 insertions(+), 1 deletion(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 895c0b4252..0c79fa3f88 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -300,6 +300,13 @@ static void copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, assert(parent_ruleset != NULL); assert(child_ruleset != NULL); assert(exceptions_arr != NULL); + // Normally useless code, left to be safe for the moment + if (parent_ruleset == NULL || child_ruleset == NULL || exceptions_arr == NULL) { + if (parent_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, 0, mp, "copy_rules: parent_ruleset is NULL"); + if (child_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, mp, "copy_rules: child_ruleset is NULL"); + if (exceptions_arr == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, mp, "copy_rules: exceptions_arr is NULL"); + return; + } copy_rules_phase(mp, parent_ruleset->phase_request_headers, child_ruleset->phase_request_headers, exceptions_arr); @@ -1161,6 +1168,11 @@ static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_marker: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL); return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action); @@ -1172,6 +1184,11 @@ static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_cookiev0_separator: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strlen(p1) != 1) { @@ -1189,6 +1206,11 @@ static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_argument_separator: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strlen(p1) != 1) { @@ -1383,6 +1405,11 @@ static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_audit_log_dirmode: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "default") == 0) { @@ -1406,6 +1433,11 @@ static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_audit_log_filemode: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "default") == 0) { @@ -1491,6 +1523,11 @@ static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, { assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_component_signature: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */ @@ -1502,6 +1539,11 @@ static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_content_injection: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->content_injection_enabled = flag; return NULL; @@ -1666,7 +1708,12 @@ static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag) { assert(_dcfg != NULL); - directory_config *dcfg = (directory_config *)_dcfg; + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_disable_backend_compression: _dcfg is NULL"); + return NULL; + } + directory_config* dcfg = (directory_config*)_dcfg; dcfg->disable_backend_compression = flag; return NULL; } @@ -1737,6 +1784,11 @@ static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_stream_inbody_inspection: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->stream_inbody_inspection = flag; return NULL; @@ -1756,6 +1808,11 @@ static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_stream_outbody_inspection: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->stream_outbody_inspection = flag; return NULL; @@ -1776,6 +1833,11 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_perf_time: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -1874,6 +1936,11 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_conn_read_state_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -1925,6 +1992,11 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_conn_write_state_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -1966,6 +2038,11 @@ static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_inmemory_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -1985,6 +2062,11 @@ static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -2004,6 +2086,11 @@ static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_no_files_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -2023,6 +2110,11 @@ static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_json_depth_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -2061,6 +2153,11 @@ static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_access: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1; @@ -2088,6 +2185,11 @@ static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_intercept_on_error: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1; @@ -2104,6 +2206,11 @@ static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, const char *p1) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_encoding: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; /* ENH Validate encoding */ @@ -2118,6 +2225,11 @@ static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_access: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1; @@ -2135,6 +2247,11 @@ static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; @@ -2158,6 +2275,11 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_limit_action: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { @@ -2190,6 +2312,11 @@ static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_resquest_body_limit_action: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { @@ -2212,6 +2339,11 @@ static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(_p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_mime_type: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; char *p1 = apr_pstrdup(cmd->pool, _p1); @@ -2231,6 +2363,11 @@ static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, void *_dcfg) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_mime_types_clear: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->of_mime_types_cleared = 1; @@ -2258,6 +2395,11 @@ static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg, { assert(cmd != NULL); assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_id: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -2296,6 +2438,11 @@ static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg, { assert(cmd != NULL); assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_tag: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -2333,6 +2480,11 @@ static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_msg: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -2363,6 +2515,11 @@ static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_sever_conn_filters_engine: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) @@ -2391,6 +2548,11 @@ static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_engine: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) @@ -2421,6 +2583,11 @@ static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_remote_rules_fail: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strncasecmp(p1, "warn", 4) == 0) @@ -2447,6 +2614,11 @@ static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, assert(_dcfg != NULL); assert(p1 != NULL); char *error_msg = NULL; + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_remote_rules: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; #ifdef WITH_REMOTE_RULES int crypto = 0; @@ -2536,6 +2708,11 @@ static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1 static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) { assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_inheritance: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->rule_inheritance = flag; return NULL; @@ -2561,6 +2738,11 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_id: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception* re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); if (re == NULL) { @@ -2594,6 +2776,11 @@ static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_tag: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -2621,6 +2808,11 @@ static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_msg: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -2683,6 +2875,11 @@ static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_tmp_dir: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL; @@ -2696,6 +2893,11 @@ static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_dir: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL; @@ -2710,6 +2912,11 @@ static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_file_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "default") == 0) { @@ -2728,6 +2935,11 @@ static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_filemode: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "default") == 0) { @@ -2751,6 +2963,11 @@ static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_keep_files: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) { @@ -2774,6 +2991,11 @@ static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_save_tmp_files: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) @@ -2798,6 +3020,11 @@ static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_web_app_id: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; /* ENH enforce format (letters, digits, ., _, -) */ @@ -2811,6 +3038,11 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_sensor_id: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; /* ENH enforce format (letters, digits, ., _, -) */ @@ -2834,6 +3066,11 @@ static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const ch assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_xml_external_entity: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) { dcfg->xml_external_entity = 1; @@ -2862,6 +3099,11 @@ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_engine: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) { dcfg->hash_is_enabled = HASH_ENABLED; @@ -2890,6 +3132,11 @@ static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_param: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->crypto_param_name = p1; @@ -2913,6 +3160,11 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co assert(_dcfg != NULL); assert(_p1 != NULL); assert(_p2 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; char *p1 = NULL; @@ -2954,6 +3206,11 @@ static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); assert(p1 != NULL); assert(p2 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_pm: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); @@ -3047,6 +3304,11 @@ static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); assert(p1 != NULL); assert(p2 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_rx: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); @@ -3116,6 +3378,11 @@ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_httpBl_key: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->httpBlkey = p1; @@ -3285,6 +3552,11 @@ static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_cache_transformations: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; if (strcasecmp(p1, "on") == 0) diff --git a/apache2/re.c b/apache2/re.c index 47a390e0df..54d7db8d7b 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2385,6 +2385,11 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type, assert(ruleset != NULL); assert(args != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, ruleset->mp, NULL, "msre_rule_create: error_msg is NULL"); + return NULL; + } msre_rule *rule; char *my_error_msg; const char *argsp; diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 73b0d8fb49..b2f3cc7951 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -106,6 +106,11 @@ static int msre_op_nomatch_execute(modsec_rec *msr, msre_rule *rule, static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { assert(rule != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_ipmatch_param_init: error_msg is NULL"); + return -1; + } char *param = NULL; int res = 0; @@ -341,6 +346,11 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { assert(rule != NULL); assert(rule->ruleset != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_rsub_param_init: error_msg is NULL"); + return -1; + } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 ap_regex_t *regex; #else @@ -2576,6 +2586,11 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var * assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_endsWith_execute: error_msg is NULL"); + return -1; + } const char *match = NULL; const char *target; unsigned int match_length; @@ -3239,6 +3254,10 @@ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { assert(rule != NULL); assert(rule->ruleset != NULL); assert(error_msg != NULL); + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_verifyCPF_init: error_msg is NULL"); + return -1; + } const char *errptr = NULL; int erroffset; int options = 0; @@ -4122,6 +4141,10 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) assert(rule != NULL); assert(rule->ruleset != NULL); assert(error_msg != NULL); + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, ":msre_op_fuzzy_hash_init error_msg is NULL"); + return -1; + } #ifdef WITH_SSDEEP struct fuzzy_hash_param_data *param_data; struct fuzzy_hash_chunk *chunk, *t; @@ -4276,6 +4299,10 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { assert(rule != NULL); assert(rule->ruleset != NULL); assert(error_msg != NULL); + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_inspectFile_init: error_msg is NULL"); + return -1; + } char *filename = (char *)rule->op_param; *error_msg = NULL; From 22a6829690af1ee98814ba5ff64d5b3483ef7ac0 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 18:44:45 +0200 Subject: [PATCH 443/477] added more NULL checks at run-time --- apache2/re_operators.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b2f3cc7951..6e36300ce6 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -2659,6 +2659,11 @@ static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { assert(rule != NULL); assert(rule->ruleset != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_strmatch_param_init: error_msg is NULL"); + return -1; + } const apr_strmatch_pattern *compiled_pattern; char *processed = NULL; const char *pattern = rule->op_param; @@ -2691,6 +2696,11 @@ static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var * assert(rule != NULL); assert(var != NULL); assert(error_msg != NULL); + // Normally useless code, left to be safe for the moment + if (error_msg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_strmatch_execute: error_msg is NULL"); + return -1; + } apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; const char *target; unsigned int target_length; From 0066a679114fdc9edc55f52a3d1d5142ccc02739 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 19:00:25 +0200 Subject: [PATCH 444/477] added more NULL checks at run-time --- apache2/apache2_config.c | 36 ++++++++++++++++++++++++++++++++++++ apache2/msc_geo.c | 2 ++ 2 files changed, 38 insertions(+) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 0c79fa3f88..6fd5c74999 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -2781,6 +2781,10 @@ static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_tag: _dcfg is NULL"); return NULL; } + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_tag: p1 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); @@ -3165,6 +3169,10 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _dcfg is NULL"); return NULL; } + if (_p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _p1 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; char *p1 = NULL; @@ -3211,6 +3219,10 @@ static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_pm: _dcfg is NULL"); return NULL; } + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_pm: p1 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); const char *_p2 = apr_pstrdup(cmd->pool, p2); @@ -3383,6 +3395,10 @@ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_httpBl_key: _dcfg is NULL"); return NULL; } + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_httpBl_key: p1 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->httpBlkey = p1; @@ -3397,6 +3413,11 @@ static const char *cmd_pcre_match_limit(cmd_parms *cmd, { assert(cmd != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_pcre_match_limit: p1 is NULL"); + return NULL; + } long val; if (cmd->server->is_virtual) { @@ -3418,6 +3439,11 @@ static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd, { assert(cmd != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_pcre_match_limit_recursion: p1 is NULL"); + return NULL; + } long val; if (cmd->server->is_virtual) { @@ -3442,6 +3468,16 @@ static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, { assert(cmd != NULL); assert(p1 != NULL); + assert(_dcfg != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_geo_lookup_db: _dcfg is NULL"); + return NULL; + } + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_geo_lookup_db: p1 is NULL"); + return NULL; + } const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); char *error_msg; directory_config *dcfg = (directory_config *)_dcfg; diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index e77e4f5056..6f60b00321 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -12,6 +12,7 @@ * directly using the email address security@modsecurity.org. */ +#include <assert.h> #include "msc_geo.h" @@ -244,6 +245,7 @@ static int field_length(const char *field, int maxlen) */ int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg) { + assert(dcfg != NULL); *error_msg = NULL; if ((dcfg->geo == NULL) || (dcfg->geo == NOT_SET_P)) { From 4b391834ecc91dcb0ea93448edf1ad2508bb2b6e Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 19:09:15 +0200 Subject: [PATCH 445/477] added more NULL checks at run-time --- apache2/apache2_config.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 6fd5c74999..54540bd9eb 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -3141,6 +3141,10 @@ static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_param: _dcfg is NULL"); return NULL; } + if (p1 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_param: p1 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; dcfg->crypto_param_name = p1; @@ -3173,6 +3177,10 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _p1 is NULL"); return NULL; } + if (_p2 == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _p2 is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; char *p1 = NULL; @@ -3533,6 +3541,11 @@ static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(p1 != NULL); assert(p2 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_unicode_map: _dcfg is NULL"); + return NULL; + } const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); char *error_msg; long val = 0; From 4edeca70e4716f7c232cbd17a4dcfd5db78283af Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 14 Aug 2024 19:12:03 +0200 Subject: [PATCH 446/477] Added "::error" in error message --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18601e321f..7594cae8de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: # '|| :' handles the case grep doesn't match, otherwise the script exits with 1 (error) errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) || : if [[ -z "${errors}" ]]; then exit 0; fi - echo "Found errors/warnings in error.log" + echo "::error Found errors/warnings in error.log" echo "${errors}" exit 1 - name: Show httpd error log From 60d07a5547ff18065f127699caac4010ac63c884 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 16 Aug 2024 09:23:11 +0200 Subject: [PATCH 447/477] added one more NULL check at run-time --- apache2/apache2_config.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 54540bd9eb..7642765387 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -2134,6 +2134,11 @@ static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg, assert(cmd != NULL); assert(_dcfg != NULL); assert(p1 != NULL); + // Normally useless code, left to be safe for the moment + if (_dcfg == NULL) { + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_arguments_limit: _dcfg is NULL"); + return NULL; + } directory_config *dcfg = (directory_config *)_dcfg; long int limit; From 7f4e416fc4cc061fa76e0555f698043d352aa90a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Sun, 18 Aug 2024 22:59:22 +0200 Subject: [PATCH 448/477] Added PR #3202 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 2345822f31..a16bb50769 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Fixed assert() usage + [PR #3202 - @marcstern] * Removed useless code [PR #3193 - @marcstern] * feat: Check if the MP header contains invalid character From 046d3eb3ec42d8f27d42eaa0a433f7b6d5db4b07 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 19 Aug 2024 14:19:05 +0200 Subject: [PATCH 449/477] Fixed two error messages --- apache2/re.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 6b2753e0d5..be6a9187a4 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -333,14 +333,8 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if (match == 1) { rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { - if (msr) { - msr_log(msr, 9, "Error parsing rule targets to replace variable"); - } -#if !defined(MSC_TEST) - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to replace variable"); - } -#endif + if (my_error_msg) my_error_msg = apr_psprintf(ruleset->mp, "Error parsing rule targets to replace variable: %s", my_error_msg); + else my_error_msg = apr_psprintf(ruleset->mp, "Error parsing rule targets to replace variable"); goto end; } if (msr) { @@ -354,14 +348,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r var_appended = 1; } else { - if (msr) { - msr_log(msr, 9, "Cannot find variable to replace"); - } -#if !defined(MSC_TEST) - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Cannot find variable to replace"); - } -#endif + my_error_msg = apr_psprintf(ruleset->mp, "Cannot find variable to replace"); goto end; } } @@ -445,14 +432,7 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r if (match == 0 ) { rc = msre_parse_targets(ruleset, p, rule->targets, &my_error_msg); if (rc < 0) { - if (msr) { - msr_log(msr, 9, "Error parsing rule targets to append variable"); - } -#if !defined(MSC_TEST) - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Error parsing rule targets to append variable"); - } -#endif + my_error_msg = apr_psprintf(ruleset->mp, "Error parsing rule targets to append variable"); goto end; } var_appended = 1; From d996f04e3acefb6ddbaedaf28d30fdd27a806946 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Mon, 19 Aug 2024 16:47:09 +0200 Subject: [PATCH 450/477] Add trailing `::` sequence Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7594cae8de..f0582c8782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,7 +54,7 @@ jobs: # '|| :' handles the case grep doesn't match, otherwise the script exits with 1 (error) errors=$(grep -E ':(?error|warn)[]]' /var/log/apache2/error.log) || : if [[ -z "${errors}" ]]; then exit 0; fi - echo "::error Found errors/warnings in error.log" + echo "::error::Found errors/warnings in error.log" echo "${errors}" exit 1 - name: Show httpd error log From 6e384d13ab6c53933b7285de83ccfbd35483e036 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 20 Aug 2024 15:27:44 +0200 Subject: [PATCH 451/477] Added PR #3190 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index a16bb50769..16ab463ee7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * CI improvement: First check syntax & always display error/audit logs + [PR #3190 - @marcstern] * Fixed assert() usage [PR #3202 - @marcstern] * Removed useless code From 207525e19475a65474c263cbf3943f1972a5a524 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Mon, 26 Aug 2024 16:38:30 +0200 Subject: [PATCH 452/477] Added PR #3191 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 16ab463ee7..8ef7385947 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Memory leaks + enhanced logging + [PR #3191 - @marcstern] * CI improvement: First check syntax & always display error/audit logs [PR #3190 - @marcstern] * Fixed assert() usage From 6be2ee534a8b50f518f7856b7508d56dc94ceb42 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 26 Aug 2024 17:17:36 +0200 Subject: [PATCH 453/477] Fixed ap_log_perror() usage Replaces #3236 --- apache2/apache2_config.c | 136 +++++++++++++++++++-------------------- apache2/modsecurity.c | 8 +-- apache2/re.c | 2 +- apache2/re_operators.c | 16 ++--- 4 files changed, 81 insertions(+), 81 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index aca6d79af6..ca2189399a 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -302,9 +302,9 @@ static void copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, assert(exceptions_arr != NULL); // Normally useless code, left to be safe for the moment if (parent_ruleset == NULL || child_ruleset == NULL || exceptions_arr == NULL) { - if (parent_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, 0, mp, "copy_rules: parent_ruleset is NULL"); - if (child_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, mp, "copy_rules: child_ruleset is NULL"); - if (exceptions_arr == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, 0, mp, "copy_rules: exceptions_arr is NULL"); + if (parent_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, mp, "copy_rules: parent_ruleset is NULL"); + if (child_ruleset == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, mp, "copy_rules: child_ruleset is NULL"); + if (exceptions_arr == NULL) ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, mp, "copy_rules: exceptions_arr is NULL"); return; } @@ -1170,7 +1170,7 @@ static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_marker: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_marker: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1186,7 +1186,7 @@ static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_cookiev0_separator: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_cookiev0_separator: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1208,7 +1208,7 @@ static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_argument_separator: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_argument_separator: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1407,7 +1407,7 @@ static const char *cmd_audit_log_dirmode(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_audit_log_dirmode: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_audit_log_dirmode: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1435,7 +1435,7 @@ static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_audit_log_filemode: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_audit_log_filemode: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1525,7 +1525,7 @@ static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_component_signature: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_component_signature: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1541,7 +1541,7 @@ static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_content_injection: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_content_injection: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1710,7 +1710,7 @@ static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_disable_backend_compression: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_disable_backend_compression: _dcfg is NULL"); return NULL; } directory_config* dcfg = (directory_config*)_dcfg; @@ -1786,7 +1786,7 @@ static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_stream_inbody_inspection: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_stream_inbody_inspection: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1810,7 +1810,7 @@ static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, in assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_stream_outbody_inspection: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_stream_outbody_inspection: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1835,7 +1835,7 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_perf_time: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_perf_time: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1938,7 +1938,7 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_conn_read_state_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_conn_read_state_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -1994,7 +1994,7 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_conn_write_state_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_conn_write_state_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2040,7 +2040,7 @@ static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_inmemory_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_body_inmemory_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2064,7 +2064,7 @@ static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_body_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2088,7 +2088,7 @@ static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_no_files_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_body_no_files_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2112,7 +2112,7 @@ static const char *cmd_request_body_json_depth_limit(cmd_parms *cmd, void *_dcfg assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_json_depth_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_body_json_depth_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2136,7 +2136,7 @@ static const char *cmd_arguments_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_arguments_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_arguments_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2160,7 +2160,7 @@ static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_body_access: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_body_access: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2192,7 +2192,7 @@ static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_intercept_on_error: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_intercept_on_error: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2213,7 +2213,7 @@ static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_request_encoding: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_request_encoding: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2232,7 +2232,7 @@ static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_access: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_response_body_access: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2254,7 +2254,7 @@ static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_response_body_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2282,7 +2282,7 @@ static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_limit_action: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_response_body_limit_action: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2319,7 +2319,7 @@ static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_resquest_body_limit_action: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_resquest_body_limit_action: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2346,7 +2346,7 @@ static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, assert(_p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_mime_type: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_response_body_mime_type: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2370,7 +2370,7 @@ static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_response_body_mime_types_clear: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_response_body_mime_types_clear: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2402,7 +2402,7 @@ static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_id: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_update_target_by_id: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2445,7 +2445,7 @@ static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_tag: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_update_target_by_tag: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2487,7 +2487,7 @@ static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_update_target_by_msg: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_update_target_by_msg: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2522,7 +2522,7 @@ static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_sever_conn_filters_engine: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_sever_conn_filters_engine: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2555,7 +2555,7 @@ static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_engine: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_engine: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2590,7 +2590,7 @@ static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_remote_rules_fail: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_remote_rules_fail: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2621,7 +2621,7 @@ static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, char *error_msg = NULL; // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_remote_rules: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_remote_rules: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2715,7 +2715,7 @@ static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_inheritance: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_inheritance: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2745,7 +2745,7 @@ static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_id: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_remove_by_id: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2783,11 +2783,11 @@ static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_tag: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_remove_by_tag: _dcfg is NULL"); return NULL; } if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_tag: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_remove_by_tag: p1 is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2819,7 +2819,7 @@ static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_rule_remove_by_msg: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_rule_remove_by_msg: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2886,7 +2886,7 @@ static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_tmp_dir: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_tmp_dir: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2904,7 +2904,7 @@ static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_dir: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_upload_dir: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2923,7 +2923,7 @@ static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_file_limit: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_upload_file_limit: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2946,7 +2946,7 @@ static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_filemode: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_upload_filemode: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -2974,7 +2974,7 @@ static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_keep_files: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_upload_keep_files: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3002,7 +3002,7 @@ static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_upload_save_tmp_files: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_upload_save_tmp_files: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3031,7 +3031,7 @@ static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_web_app_id: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_web_app_id: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3049,7 +3049,7 @@ static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_sensor_id: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_sensor_id: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3077,7 +3077,7 @@ static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const ch assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_xml_external_entity: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_xml_external_entity: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3110,7 +3110,7 @@ static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_engine: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_engine: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3143,11 +3143,11 @@ static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_param: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_param: _dcfg is NULL"); return NULL; } if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_param: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_param: p1 is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3175,15 +3175,15 @@ static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, co assert(_p2 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_key: _dcfg is NULL"); return NULL; } if (_p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_key: _p1 is NULL"); return NULL; } if (_p2 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_key: _p2 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_key: _p2 is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3229,11 +3229,11 @@ static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, assert(p2 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_pm: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_method_pm: _dcfg is NULL"); return NULL; } if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_pm: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_method_pm: p1 is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3331,7 +3331,7 @@ static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, assert(p2 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_hash_method_rx: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_hash_method_rx: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3405,11 +3405,11 @@ static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_httpBl_key: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_httpBl_key: _dcfg is NULL"); return NULL; } if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_httpBl_key: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_httpBl_key: p1 is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; @@ -3428,7 +3428,7 @@ static const char *cmd_pcre_match_limit(cmd_parms *cmd, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_pcre_match_limit: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_pcre_match_limit: p1 is NULL"); return NULL; } long val; @@ -3454,7 +3454,7 @@ static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_pcre_match_limit_recursion: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_pcre_match_limit_recursion: p1 is NULL"); return NULL; } long val; @@ -3484,11 +3484,11 @@ static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, assert(_dcfg != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_geo_lookup_db: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_geo_lookup_db: _dcfg is NULL"); return NULL; } if (p1 == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_geo_lookup_db: p1 is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_geo_lookup_db: p1 is NULL"); return NULL; } const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); @@ -3548,7 +3548,7 @@ static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg, assert(p2 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_unicode_map: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_unicode_map: _dcfg is NULL"); return NULL; } const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); @@ -3608,7 +3608,7 @@ static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); // Normally useless code, left to be safe for the moment if (_dcfg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, NULL, "cmd_cache_transformations: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_cache_transformations: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index d407cf7288..55150afe23 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -131,7 +131,7 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { // get platform temp dir rc = apr_temp_dir_get(&temp_dir, mp); if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, "ModSecurity: Could not get temp dir"); + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, "ModSecurity: Could not get temp dir"); return -1; } @@ -140,7 +140,7 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { rc = apr_file_mktemp(&lock_name, path, 0, mp); if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create temporary file for global lock"); + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, " ModSecurity: Could not create temporary file for global lock"); return -1; } // below func always return APR_SUCCESS @@ -148,7 +148,7 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { rc = apr_global_mutex_create(lock, filename, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not create global mutex"); + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, " ModSecurity: Could not create global mutex"); return -1; } #if !defined(MSC_TEST) @@ -159,7 +159,7 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { rc = unixd_set_global_mutex_perms(*lock); #endif if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, NULL, " ModSecurity: Could not set permissions on global mutex"); + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, " ModSecurity: Could not set permissions on global mutex"); return -1; } #endif /* SET_MUTEX_PERMS */ diff --git a/apache2/re.c b/apache2/re.c index 3b3fea6059..82eba8f23b 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -2338,7 +2338,7 @@ msre_rule *msre_rule_create(msre_ruleset *ruleset, int type, assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, ruleset->mp, NULL, "msre_rule_create: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, ruleset->mp, "msre_rule_create: error_msg is NULL"); return NULL; } msre_rule *rule; diff --git a/apache2/re_operators.c b/apache2/re_operators.c index f5fc1a2f28..ca61c7adc8 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -108,7 +108,7 @@ static int msre_op_ipmatch_param_init(msre_rule *rule, char **error_msg) { assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_ipmatch_param_init: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_ipmatch_param_init: error_msg is NULL"); return -1; } char *param = NULL; @@ -348,7 +348,7 @@ static int msre_op_rsub_param_init(msre_rule *rule, char **error_msg) { assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_rsub_param_init: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_rsub_param_init: error_msg is NULL"); return -1; } #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0 @@ -2572,7 +2572,7 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var * assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_endsWith_execute: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_endsWith_execute: error_msg is NULL"); return -1; } const char *match = NULL; @@ -2645,7 +2645,7 @@ static int msre_op_strmatch_param_init(msre_rule *rule, char **error_msg) { assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_strmatch_param_init: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_strmatch_param_init: error_msg is NULL"); return -1; } const apr_strmatch_pattern *compiled_pattern; @@ -2682,7 +2682,7 @@ static int msre_op_strmatch_execute(modsec_rec *msr, msre_rule *rule, msre_var * assert(error_msg != NULL); // Normally useless code, left to be safe for the moment if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_strmatch_execute: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_strmatch_execute: error_msg is NULL"); return -1; } apr_strmatch_pattern *compiled_pattern = (apr_strmatch_pattern *)rule->op_param_data; @@ -3249,7 +3249,7 @@ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { assert(rule->ruleset != NULL); assert(error_msg != NULL); if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_verifyCPF_init: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_verifyCPF_init: error_msg is NULL"); return -1; } const char *errptr = NULL; @@ -4136,7 +4136,7 @@ static int msre_op_fuzzy_hash_init(msre_rule *rule, char **error_msg) assert(rule->ruleset != NULL); assert(error_msg != NULL); if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, ":msre_op_fuzzy_hash_init error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_fuzzy_hash_init error_msg is NULL"); return -1; } #ifdef WITH_SSDEEP @@ -4294,7 +4294,7 @@ static int msre_op_inspectFile_init(msre_rule *rule, char **error_msg) { assert(rule->ruleset != NULL); assert(error_msg != NULL); if (error_msg == NULL) { - ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, NULL, "msre_op_inspectFile_init: error_msg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, rule->ruleset->mp, "msre_op_inspectFile_init: error_msg is NULL"); return -1; } char *filename = (char *)rule->op_param; From d55495e1dcc5c6f5ad4427bae17979bf749caa2b Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Mon, 26 Aug 2024 17:59:11 +0200 Subject: [PATCH 454/477] Added PR #3241 --- CHANGES | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGES b/CHANGES index 8ef7385947..4b74b827b5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ DD mmm YYYY - 2.9.8 (to be released) ------------------- + * Fixed ap_log_perror() usage + [PR #3241 - @marcstern] * Memory leaks + enhanced logging [PR #3191 - @marcstern] * CI improvement: First check syntax & always display error/audit logs From 25d73b71c811cfab96ee7b487281efcdf7c288dc Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Mon, 2 Sep 2024 22:21:08 +0200 Subject: [PATCH 455/477] Finalize CHANGES --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4b74b827b5..8ee2508415 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -DD mmm YYYY - 2.9.8 (to be released) +03 Sep 2024 - 2.9.8 ------------------- * Fixed ap_log_perror() usage From c9fe84ea2cb849e287ac40c2203da9e1c5bcee96 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 3 Sep 2024 07:42:20 +0200 Subject: [PATCH 456/477] Typo fixes --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 8ee2508415..8a35b67524 100644 --- a/CHANGES +++ b/CHANGES @@ -37,7 +37,7 @@ [Issue #3154 - @marcstern] * Missing null byte + optimization [Issue #3153 - @marcstern] - * fix: remove usage of insecure tmpnam + * fix: remove usage of insecure tmpname [Issue #3149 - @fzipi] * docs: update copyright [Issue #3148 - @fzipi] @@ -47,7 +47,7 @@ [Issue #3120 - @marcstern] * Fix possible segfault in collection_unpack [Issue #3099 - @twouters] - * fix: Replace obsolote macros + * fix: Replace obsolete macros [Issue #3094 - @airween] * chore: update bug-report-for-version-2-x.md [Issue #3087 - @fzipi] From ad0161118d0ec36b1bd7537ef8f4d889d89c1c35 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 3 Sep 2024 14:40:55 +0200 Subject: [PATCH 457/477] Change release version to v2.9.8 --- apache2/msc_release.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_release.h b/apache2/msc_release.h index bc6f959970..5c4dbc96d2 100644 --- a/apache2/msc_release.h +++ b/apache2/msc_release.h @@ -38,7 +38,7 @@ #define MODSEC_VERSION_MAJOR "2" #define MODSEC_VERSION_MINOR "9" -#define MODSEC_VERSION_MAINT "7" +#define MODSEC_VERSION_MAINT "8" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From cddd9a7eb5585a9b3be1f9bdcadcace8f60f5808 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 3 Sep 2024 21:49:43 +0200 Subject: [PATCH 458/477] Fix build error if -Werror=format-security is presented --- apache2/re.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/re.c b/apache2/re.c index 82eba8f23b..0a8b0724d3 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -472,8 +472,8 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r end: if (my_error_msg) { - if (msr) msr_log(msr, 9, my_error_msg); - else ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, my_error_msg); + if (msr) msr_log(msr, 9, "%s", my_error_msg); + else ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, "%s", my_error_msg); } if (target_list != NULL) free(target_list); if (replace != NULL) free(replace); From 38e812d1970bac8434b6206b41f7b8109db245c5 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Tue, 3 Sep 2024 21:50:22 +0200 Subject: [PATCH 459/477] Add -Werror=format-security CFLAG for all build case --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85e944f438..5e625415a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: - name: autogen.sh run: ./autogen.sh - name: configure ${{ matrix.configure.label }} - run: ./configure --enable-assertions ${{ matrix.configure.opt }} + run: ./configure --enable-assertions ${{ matrix.configure.opt }} 'CFLAGS=-Werror=format-security' - uses: ammaraskar/gcc-problem-matcher@master - name: make run: make -j `nproc` From b52201010d4fb450ac36cd96c352f0f8f153f1b5 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 12 Sep 2024 12:18:25 +0200 Subject: [PATCH 460/477] msr_global_mutex_lock: Handle errors from apr_global_mutex_lock --- apache2/modsecurity.c | 18 ++++++++++++++++++ apache2/modsecurity.h | 1 + apache2/msc_geo.c | 6 +----- apache2/msc_logging.c | 33 ++++----------------------------- apache2/persist_dbm.c | 32 ++++++++------------------------ 5 files changed, 32 insertions(+), 58 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 55150afe23..7594bdc25f 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -166,6 +166,24 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { #endif /* MSC_TEST */ return APR_SUCCESS; } + +/** + * handle errors from apr_global_mutex_lock + */ +int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* fct) { + assert(msr); + assert(msr->modsecurity); // lock is msr->modsecurity->..._lock + assert(msr->mp); + if (!lock) { + msr_log(msr, 1, "%s: Global mutex was not created", fct); + return -1; + } + + int rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", get_apr_error(msr->mp, rc)); + return rc; +} + /** * Initialise the modsecurity engine. This function must be invoked * after configuration processing is complete as Apache needs to know the diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index d1aa1d8346..4a3ef54273 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -707,6 +707,7 @@ struct msc_parm { /* Reusable functions */ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp); +int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* fct); /* Engine functions */ diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index 6f60b00321..f644737cdf 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -325,11 +325,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx). %lu", targetip, ipnum, ipnum); } - ret = apr_global_mutex_lock(msr->modsecurity->geo_lock); - if (ret != APR_SUCCESS) { - msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, ret)); - } + msr_global_mutex_lock(msr, msr->modsecurity->geo_lock, "Geo lookup"); for (level = 31; level >= 0; level--) { /* Read the record */ diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 46c0882620..8fd7e8ee70 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -757,14 +757,7 @@ void sec_audit_logger_json(modsec_rec *msr) { /* Lock the mutex, but only if we are using serial format. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - if (!msr->modsecurity->auditlog_lock) msr_log(msr, 1, "Audit log: Global mutex was not created"); - else { - rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", - get_apr_error(msr->mp, rc)); - } - } + msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); } /** @@ -1471,15 +1464,8 @@ void sec_audit_logger_json(modsec_rec *msr) { * as it does not need an index file. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - /* Unlock the mutex we used to serialise access to the audit log file. */ - rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to unlock global mutex '%s': %s", - apr_global_mutex_lockfile(msr->modsecurity->auditlog_lock), - get_apr_error(msr->mp, rc)); - } - + msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); return; } @@ -1650,11 +1636,7 @@ void sec_audit_logger_native(modsec_rec *msr) { /* Lock the mutex, but only if we are using serial format. */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { - rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", - get_apr_error(msr->mp, rc)); - } + msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); } @@ -2253,15 +2235,8 @@ void sec_audit_logger_native(modsec_rec *msr) { */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { sec_auditlog_write(msr, "\n", 1); - /* Unlock the mutex we used to serialise access to the audit log file. */ - rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "Audit log: Failed to unlock global mutex '%s': %s", - apr_global_mutex_lockfile(msr->modsecurity->auditlog_lock), - get_apr_error(msr->mp, rc)); - } - + msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); return; } diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index c685e1de3b..b1a2f17e83 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -125,12 +125,8 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (existing_dbm == NULL) { #ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } + rc = msr_global_mutex_lock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); + if (rc != APR_SUCCESS) goto cleanup; #endif rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK, CREATEMODE, msr->mp); @@ -222,12 +218,8 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (apr_table_get(col, "KEY") == NULL) { if (existing_dbm == NULL) { #ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_retrieve_ex: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto cleanup; - } + rc = msr_global_mutex_lock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); + if (rc != APR_SUCCESS) goto cleanup; #endif rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, CREATEMODE, msr->mp); @@ -408,12 +400,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { #ifdef GLOBAL_COLLECTION_LOCK /* Need to lock to pull in the stored data again and apply deltas. */ - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collection_store: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } + int ret = msr_global_mutex_lock(msr, msr->modsecurity->dbm_lock, "collection_store"); + if (ret != APR_SUCCESS) goto error; #endif /* Delete IS_NEW on store. */ @@ -684,12 +672,8 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { } #ifdef GLOBAL_COLLECTION_LOCK - rc = apr_global_mutex_lock(msr->modsecurity->dbm_lock); - if (rc != APR_SUCCESS) { - msr_log(msr, 1, "collections_remove_stale: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, rc)); - goto error; - } + rc = msr_global_mutex_lock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale"); + if (rc != APR_SUCCESS) goto error; #endif rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK, From 449c080e63b17558cb609aa9cec323227bd24a0f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 12 Sep 2024 13:01:44 +0200 Subject: [PATCH 461/477] Same for global_mutex_unlock --- apache2/modsecurity.c | 16 ++++++++++++++++ apache2/modsecurity.h | 1 + apache2/msc_geo.c | 32 ++++---------------------------- apache2/persist_dbm.c | 26 +++++++++++++------------- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 7594bdc25f..9439c44771 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -183,6 +183,22 @@ int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", get_apr_error(msr->mp, rc)); return rc; } +/** + * handle errors from apr_global_mutex_unlock + */ +int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const char* fct) { + assert(msr); + assert(msr->modsecurity); // lock is msr->modsecurity->..._lock + assert(msr->mp); + if (!lock) { + msr_log(msr, 1, "%s: Global mutex was not created", fct); + return -1; + } + + int rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); + if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", get_apr_error(msr->mp, rc)); + return rc; +} /** * Initialise the modsecurity engine. This function must be invoked diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 4a3ef54273..a1751000b8 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -708,6 +708,7 @@ struct msc_parm { /* Reusable functions */ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp); int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* fct); +int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const char* fct); /* Engine functions */ diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index f644737cdf..7d3a8e4021 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -357,13 +357,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro if (rec_val == geo->ctry_offset) { *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\").", log_escape(msr->mp, target)); msr_log(msr, 4, "%s", *error_msg); - - ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock); - if (ret != APR_SUCCESS) { - msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, ret)); - } - + msr_global_mutex_unlock(msr, msr->modsecurity->geo_lock, "Geo Lookup"); return 0; } @@ -373,13 +367,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro if ((country <= 0) || (country > GEO_COUNTRY_LAST)) { *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country); msr_log(msr, 4, "%s", *error_msg); - - ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock); - if (ret != APR_SUCCESS) { - msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, ret)); - } - + msr_global_mutex_unlock(msr, msr->modsecurity->geo_lock, "Geo Lookup"); return 0; } @@ -404,13 +392,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro if ((country <= 0) || (country > GEO_COUNTRY_LAST)) { *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country); msr_log(msr, 4, "%s", *error_msg); - - ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock); - if (ret != APR_SUCCESS) { - msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, ret)); - } - + msr_global_mutex_unlock(msr, msr->modsecurity->geo_lock, "Geo Lookup"); return 0; } if (msr->txcfg->debuglog_level >= 9) { @@ -499,13 +481,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro } *error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded.", log_escape(msr->mp, target)); - - ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock); - if (ret != APR_SUCCESS) { - msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s", - get_apr_error(msr->mp, ret)); - } - + msr_global_mutex_unlock(msr, msr->modsecurity->geo_lock, "Geo Lookup"); return 1; } diff --git a/apache2/persist_dbm.c b/apache2/persist_dbm.c index b1a2f17e83..ba8475cc59 100644 --- a/apache2/persist_dbm.c +++ b/apache2/persist_dbm.c @@ -133,7 +133,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (rc != APR_SUCCESS) { dbm = NULL; #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif goto cleanup; } @@ -169,7 +169,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (existing_dbm == NULL) { apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif dbm = NULL; } @@ -228,7 +228,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); dbm = NULL; #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif goto cleanup; } @@ -253,7 +253,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if (existing_dbm == NULL) { apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif dbm = NULL; } @@ -318,7 +318,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif } @@ -329,7 +329,7 @@ static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec if ((existing_dbm == NULL) && dbm) { apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex"); #endif } @@ -461,7 +461,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store"); #endif msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); @@ -544,7 +544,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { if (dbm != NULL) { #ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store"); #else apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); @@ -607,7 +607,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { if (dbm != NULL) { #ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store"); #else apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); @@ -619,7 +619,7 @@ int collection_store(modsec_rec *msr, apr_table_t *col) { #ifdef GLOBAL_COLLECTION_LOCK apr_sdbm_close(dbm); - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store"); #else apr_sdbm_unlock(dbm); apr_sdbm_close(dbm); @@ -680,7 +680,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { CREATEMODE, msr->mp); if (rc != APR_SUCCESS) { #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale"); #endif msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc)); @@ -783,7 +783,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale"); #endif return 1; @@ -792,7 +792,7 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) { if (dbm) { apr_sdbm_close(dbm); #ifdef GLOBAL_COLLECTION_LOCK - apr_global_mutex_unlock(msr->modsecurity->dbm_lock); + msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale"); #endif } From b850c74b12017153e8fdc94796228c9ff974725f Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 12 Sep 2024 14:07:55 +0200 Subject: [PATCH 462/477] We should have get the warning at lock time, so ignore it at unlock time --- apache2/modsecurity.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 9439c44771..e31c3407da 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -196,7 +196,8 @@ int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const cha } int rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); - if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", get_apr_error(msr->mp, rc)); + // We should have get the warning at lock time, so ignore it here + // if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", get_apr_error(msr->mp, rc)); return rc; } From bd54f01cd3e93eac32efb771764dec9b7539fbeb Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 20 Sep 2024 12:51:03 +0200 Subject: [PATCH 463/477] Added CHANGES --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 8a35b67524..7bc8cbd270 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +(to be released) - 2.9.x +------------------------ + + * handle errors from apr_global_mutex_lock + [PR #3257 - @marcstern] + 03 Sep 2024 - 2.9.8 ------------------- From 9ba1caa2fabb8374fcd64ef4b496d1170f84e03a Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Wed, 25 Sep 2024 13:57:05 +0200 Subject: [PATCH 464/477] Missing #include <time.h> --- apache2/re_variables.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 6d0f2c1515..266ed6895f 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -12,6 +12,7 @@ * directly using the email address security@modsecurity.org. */ +#include <time.h> #include "http_core.h" #include "modsecurity.h" From 339d6df2a566bc3856b6b2effd77333d46d56ada Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 27 Sep 2024 09:26:58 +0200 Subject: [PATCH 465/477] Updated comment Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/modsecurity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index e31c3407da..bb4608322a 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -196,7 +196,7 @@ int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const cha } int rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); - // We should have get the warning at lock time, so ignore it here + // We should have been warnend during lock acquisition already, so don't log the same warning here // if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", get_apr_error(msr->mp, rc)); return rc; } From 95dc5944d4d2371446f08b8376b321a34881a14c Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Fri, 27 Sep 2024 09:27:29 +0200 Subject: [PATCH 466/477] Updated log message Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/modsecurity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index bb4608322a..e41bba9f4a 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -175,7 +175,7 @@ int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* assert(msr->modsecurity); // lock is msr->modsecurity->..._lock assert(msr->mp); if (!lock) { - msr_log(msr, 1, "%s: Global mutex was not created", fct); + msr_log(msr, 1, "%s: Global mutex not initialised", fct); return -1; } From b8e8e30730c17ebf8eabcdeebe030e6859bddb37 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 30 Sep 2024 13:12:38 +0200 Subject: [PATCH 467/477] Fixed parameters/functions names --- apache2/modsecurity.c | 4 ++-- apache2/msc_logging.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index e31c3407da..89cab90a5f 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -179,7 +179,7 @@ int msr_global_mutex_lock(modsec_rec* msr, apr_global_mutex_t* lock, const char* return -1; } - int rc = apr_global_mutex_lock(msr->modsecurity->auditlog_lock); + int rc = apr_global_mutex_lock(lock); if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to lock global mutex: %s", get_apr_error(msr->mp, rc)); return rc; } @@ -195,7 +195,7 @@ int msr_global_mutex_unlock(modsec_rec* msr, apr_global_mutex_t* lock, const cha return -1; } - int rc = apr_global_mutex_unlock(msr->modsecurity->auditlog_lock); + int rc = apr_global_mutex_unlock(lock); // We should have get the warning at lock time, so ignore it here // if (rc != APR_SUCCESS) msr_log(msr, 1, "Audit log: Failed to unlock global mutex: %s", get_apr_error(msr->mp, rc)); return rc; diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 8fd7e8ee70..39588b10fa 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1465,7 +1465,7 @@ void sec_audit_logger_json(modsec_rec *msr) { */ if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { /* Unlock the mutex we used to serialise access to the audit log file. */ - msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); + msr_global_mutex_unlock(msr, msr->modsecurity->auditlog_lock, "Audit log"); return; } @@ -2236,7 +2236,7 @@ void sec_audit_logger_native(modsec_rec *msr) { if (msr->txcfg->auditlog_type != AUDITLOG_CONCURRENT) { sec_auditlog_write(msr, "\n", 1); /* Unlock the mutex we used to serialise access to the audit log file. */ - msr_global_mutex_lock(msr, msr->modsecurity->auditlog_lock, "Audit log"); + msr_global_mutex_unlock(msr, msr->modsecurity->auditlog_lock, "Audit log"); return; } From c99d931f3cb1ad7ce0a319963428a8ccaf741646 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Mon, 30 Sep 2024 13:53:31 +0200 Subject: [PATCH 468/477] Initialize filename to NULL --- apache2/modsecurity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 89cab90a5f..5503188938 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -126,7 +126,7 @@ int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { apr_status_t rc; apr_file_t *lock_name; const char *temp_dir; - const char *filename; + const char *filename = NULL; // get platform temp dir rc = apr_temp_dir_get(&temp_dir, mp); From 149376377ecef9ecc36ee81d5b666fc0ac7e249b Mon Sep 17 00:00:00 2001 From: Rainer Jung <rainer.jung@kippdata.de> Date: Tue, 1 Oct 2024 13:58:22 +0200 Subject: [PATCH 469/477] Move id_log() to msc_util to fix unit tests; it is declared on msc_util.h already --- apache2/apache2_config.c | 10 ---------- apache2/msc_util.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index ca2189399a..da10b4bfe6 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -30,16 +30,6 @@ APLOG_USE_MODULE(security2); #endif -// Returns the rule id if existing, otherwise the file name & line number -const char* id_log(msre_rule* rule) { - assert(rule != NULL); - assert(rule->actionset != NULL); - assert(rule->ruleset != NULL); - const char* id = rule->actionset->id; - if (!id || id == NOT_SET_P || !*id) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); - return id; -} - /* -- Directory context creation and initialisation -- */ /** diff --git a/apache2/msc_util.c b/apache2/msc_util.c index bce5b24ffe..5b07392d44 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2849,3 +2849,13 @@ char* get_username(apr_pool_t* mp) { if (rc != APR_SUCCESS) return "apache"; return username; } + +// Returns the rule id if existing, otherwise the file name & line number +const char* id_log(msre_rule* rule) { + assert(rule != NULL); + assert(rule->actionset != NULL); + assert(rule->ruleset != NULL); + const char* id = rule->actionset->id; + if (!id || id == NOT_SET_P || !*id) id = apr_psprintf(rule->ruleset->mp, "%s (%d)", rule->filename, rule->line_num); + return id; +} From 63d5d92565fd115bf982aa7f0fb84be7dcb5cf20 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus <airween@gmail.com> Date: Wed, 2 Oct 2024 17:11:01 +0200 Subject: [PATCH 470/477] chore: add 'log' action to rule 200005 --- modsecurity.conf-recommended | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended index 11ffbbbdfd..e120daef88 100644 --- a/modsecurity.conf-recommended +++ b/modsecurity.conf-recommended @@ -109,7 +109,7 @@ SecPcreMatchLimitRecursion 1000 # MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded. # SecRule TX:/^MSC_/ "!@streq 0" \ - "id:'200005',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + "id:'200005',phase:2,t:none,log,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" # -- Response body handling -------------------------------------------------- From 23e3cb491a4450c5ed96e658478d10f1361f2ee0 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 3 Oct 2024 12:42:23 +0200 Subject: [PATCH 471/477] Fix for #3255 We don't have to generate a temp name ourselves, it'll be done in apr_global_mutex_create(). We don't have to provide a filename, apr_global_mutex_create() generates one automatically. Moreover, under Unix & Windows, the preferred mechanism won't use a file at all. apr_file_mktemp() cannot be used as it creates the file (at least on FreeBSD). Discussion in Apache mailing list: https://lists.apache.org/thread/ykb26kg4lgcqnldvxwd9p6hv16fy4z9l --- apache2/modsecurity.c | 25 +------------------------ apache2/modsecurity.h | 2 -- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index 5503188938..e21f17766c 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -123,30 +123,7 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) { } int acquire_global_lock(apr_global_mutex_t **lock, apr_pool_t *mp) { - apr_status_t rc; - apr_file_t *lock_name; - const char *temp_dir; - const char *filename = NULL; - - // get platform temp dir - rc = apr_temp_dir_get(&temp_dir, mp); - if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, "ModSecurity: Could not get temp dir"); - return -1; - } - - // use temp path template for lock files - char *path = apr_pstrcat(mp, temp_dir, GLOBAL_LOCK_TEMPLATE, NULL); - - rc = apr_file_mktemp(&lock_name, path, 0, mp); - if (rc != APR_SUCCESS) { - ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, " ModSecurity: Could not create temporary file for global lock"); - return -1; - } - // below func always return APR_SUCCESS - apr_file_name_get(&filename, lock_name); - - rc = apr_global_mutex_create(lock, filename, APR_LOCK_DEFAULT, mp); + apr_status_t rc = apr_global_mutex_create(lock, NULL, APR_LOCK_DEFAULT, mp); if (rc != APR_SUCCESS) { ap_log_perror(APLOG_MARK, APLOG_ERR, 0, mp, " ModSecurity: Could not create global mutex"); return -1; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index a1751000b8..b3976f9366 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -135,8 +135,6 @@ typedef struct msc_parm msc_parm; #define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!" -#define GLOBAL_LOCK_TEMPLATE "/modsec-lock-tmp.XXXXXX" - extern DSOLOCAL char *new_server_signature; extern DSOLOCAL char *real_server_signature; extern DSOLOCAL char *chroot_dir; From 36a4194f466c9bc471fda875b3d4a41e12513e18 Mon Sep 17 00:00:00 2001 From: Marc Stern <marc.stern@approach-cyber.com> Date: Thu, 3 Oct 2024 12:59:48 +0200 Subject: [PATCH 472/477] CHANGES --- CHANGES | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 7bc8cbd270..416d6fd399 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,9 @@ (to be released) - 2.9.x ------------------------ - * handle errors from apr_global_mutex_lock + * Fixed apr_global_mutex_create() usage (no filename) + [PR #3269 - @marcstern] +* handle errors from apr_global_mutex_lock [PR #3257 - @marcstern] 03 Sep 2024 - 2.9.8 From 4919814a5cf0e7911f71856ed872b0e73b659a0a Mon Sep 17 00:00:00 2001 From: Mark t480 <mark@t480.lenovo.com> Date: Fri, 4 Oct 2024 15:48:12 +0200 Subject: [PATCH 473/477] make rootpath and incpath consts so apr_filepath_root doesn't cause incompatible pointer type --- standalone/config.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/standalone/config.c b/standalone/config.c index 5b3d0b21d0..6133e7d7e8 100644 --- a/standalone/config.c +++ b/standalone/config.c @@ -1028,7 +1028,8 @@ const char *process_command_config(server_rec *s, ap_directive_t *newdir; int optional; char *err = NULL; - char *rootpath, *incpath; + const char *rootpath, *incpath; + char *configfilepath; int li; errmsg = populate_include_files(p, ptemp, ari, filename, 0); @@ -1108,13 +1109,13 @@ const char *process_command_config(server_rec *s, /* we allow APR_SUCCESS and APR_EINCOMPLETE */ if (APR_ERELATIVE == status) { - rootpath = apr_pstrdup(ptemp, parms->config_file->name); - li = strlen(rootpath) - 1; + configfilepath = apr_pstrdup(ptemp, parms->config_file->name); + li = strlen(configfilepath) - 1; - while(li >= 0 && rootpath[li] != '/' && rootpath[li] != '\\') - rootpath[li--] = 0; + while(li >= 0 && configfilepath[li] != '/' && configfilepath[li] != '\\') + configfilepath[li--] = 0; - w = apr_pstrcat(p, rootpath, w, NULL); + w = apr_pstrcat(p, configfilepath, w, NULL); } else if (APR_EBADPATH == status) { ap_cfg_closefile(parms->config_file); From 89ff91dae34f759f98723717345662fe13e04385 Mon Sep 17 00:00:00 2001 From: Marc Stern <sternmarc@hotmail.coms> Date: Thu, 17 Oct 2024 14:10:56 +0200 Subject: [PATCH 474/477] Fixed PCRE2 error message --- apache2/msc_pcre.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 693f02b684..b0fe70c9a1 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -77,6 +77,10 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, if (_erroffset != NULL) { *_erroffset = (int)error_offset; } + PCRE2_UCHAR buffer[256]; + // Get the error message from the error code + pcre2_get_error_message(error_number, buffer, sizeof(buffer)); + *_errptr = apr_pstrdup(pool, buffer); return NULL; } From ecab91a74e4d5d85071144b74202c45fbcae70b3 Mon Sep 17 00:00:00 2001 From: Marc Stern <sternmarc@hotmail.coms> Date: Thu, 17 Oct 2024 14:43:03 +0200 Subject: [PATCH 475/477] Add problematic pattern when DEBUG_CONF is defined --- apache2/msc_pcre.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index b0fe70c9a1..16f5efd5d4 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -80,7 +80,11 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options, PCRE2_UCHAR buffer[256]; // Get the error message from the error code pcre2_get_error_message(error_number, buffer, sizeof(buffer)); - *_errptr = apr_pstrdup(pool, buffer); +#ifdef DEBUG_CONF + * _errptr = apr_psprintf(pool, "%s - pattern = %s", buffer, pattern); +#else + * _errptr = apr_pstrdup(pool, buffer); +#endif return NULL; } From 907d61ad6d7970ca15b2e55e082e69f078df95b0 Mon Sep 17 00:00:00 2001 From: Marc Stern <sternmarc@hotmail.coms> Date: Tue, 22 Oct 2024 15:51:55 +0200 Subject: [PATCH 476/477] Incorrect utf8toUnicode transformation for 00xx Fix issue and restructure handling --- apache2/msc_util.c | 196 +++++++++------------------------------------ 1 file changed, 36 insertions(+), 160 deletions(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 5b07392d44..95cab9b94f 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -105,82 +105,44 @@ int swap_int32(int x) { */ char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed) { int unicode_len = 0, length = 0; - unsigned int d = 0, count = 0; + unsigned int d = 0; unsigned char c, *utf; char *rval, *data; unsigned int i, len, j; unsigned int bytes_left = input_len; unsigned char *unicode = NULL; + if (input == NULL) return NULL; + *changed = 0; /* RFC3629 states that UTF-8 are encoded using sequences of 1 to 4 octets. */ - /* Max size per character should fit in 4 bytes */ - len = input_len * 4 + 1; + /* Max size per character should fit in 4 bytes (%u01020304) */ + len = input_len * 10 + 1; data = rval = apr_palloc(mp, len); if (rval == NULL) return NULL; - - if (input == NULL) return NULL; - - for(i = 0; i < bytes_left;) { + for (i = 0; i < bytes_left;) { unicode_len = 0; d = 0; utf = (unsigned char *)&input[i]; - c = *utf; - /* If first byte begins with binary 0 it is single byte encoding */ + /* If first byte begins with binary 0 it may be single byte encoding */ if ((c & 0x80) == 0) { - /* single byte unicode (7 bit ASCII equivilent) has no validation */ - count++; - if(count <= len) { - if(c == 0) - *data = x2c(&c); - else - *data++ = c; + if (c == 0) { + unicode_len = 2; + d = utf[1]; } - } /* If first byte begins with binary 110 it is two byte encoding*/ else if ((c & 0xE0) == 0xC0) { /* check we have at least two bytes */ if (bytes_left < 2) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; /* check second byte starts with binary 10 */ - else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else if ((utf[1] & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; else { unicode_len = 2; - count+=6; - if(count <= len) { - /* compute character number */ - d = ((c & 0x1F) << 6) | (*(utf + 1) & 0x3F); - *data++ = '%'; - *data++ = 'u'; - unicode = apr_psprintf(mp, "%x", d); - length = strlen(unicode); - - switch(length) { - case 1: - *data++ = '0'; - *data++ = '0'; - *data++ = '0'; - break; - case 2: - *data++ = '0'; - *data++ = '0'; - break; - case 3: - *data++ = '0'; - break; - case 4: - case 5: - break; - } - - for(j=0; j<length; j++) { - *data++ = unicode[j]; - } - - *changed = 1; - } + /* compute character number */ + d = ((c & 0x1F) << 6) | (utf[1] & 0x3F); } } /* If first byte begins with binary 1110 it is three byte encoding */ @@ -188,142 +150,56 @@ char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int inp /* check we have at least three bytes */ if (bytes_left < 3) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; /* check second byte starts with binary 10 */ - else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else if ((utf[1] & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; /* check third byte starts with binary 10 */ else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; else { unicode_len = 3; - count+=6; - if(count <= len) { - /* compute character number */ - d = ((c & 0x0F) << 12) | ((*(utf + 1) & 0x3F) << 6) | (*(utf + 2) & 0x3F); - *data++ = '%'; - *data++ = 'u'; - unicode = apr_psprintf(mp, "%x", d); - length = strlen(unicode); - - switch(length) { - case 1: - *data++ = '0'; - *data++ = '0'; - *data++ = '0'; - break; - case 2: - *data++ = '0'; - *data++ = '0'; - break; - case 3: - *data++ = '0'; - break; - case 4: - case 5: - break; - } - - for(j=0; j<length; j++) { - *data++ = unicode[j]; - } - - *changed = 1; - - } + /* compute character number */ + d = ((c & 0x0F) << 12) | ((utf[1] & 0x3F) << 6) | (*(utf + 2) & 0x3F); } } /* If first byte begins with binary 11110 it is four byte encoding */ else if ((c & 0xF8) == 0xF0) { /* restrict characters to UTF-8 range (U+0000 - U+10FFFF)*/ - if (c >= 0xF5) { - *data++ = c; - } + if (c >= 0xF5) unicode_len = UNICODE_ERROR_RESTRICTED_CHARACTER; /* check we have at least four bytes */ - if (bytes_left < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; + else if (bytes_left < 4) unicode_len = UNICODE_ERROR_CHARACTERS_MISSING; /* check second byte starts with binary 10 */ - else if (((*(utf + 1)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; + else if ((utf[1] & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; /* check third byte starts with binary 10 */ else if (((*(utf + 2)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; /* check forth byte starts with binary 10 */ else if (((*(utf + 3)) & 0xC0) != 0x80) unicode_len = UNICODE_ERROR_INVALID_ENCODING; else { unicode_len = 4; - count+=7; - if(count <= len) { - /* compute character number */ - d = ((c & 0x07) << 18) | ((*(utf + 1) & 0x3F) << 12) | ((*(utf + 2) & 0x3F) << 6) | (*(utf + 3) & 0x3F); - *data++ = '%'; - *data++ = 'u'; - unicode = apr_psprintf(mp, "%x", d); - length = strlen(unicode); - - switch(length) { - case 1: - *data++ = '0'; - *data++ = '0'; - *data++ = '0'; - break; - case 2: - *data++ = '0'; - *data++ = '0'; - break; - case 3: - *data++ = '0'; - break; - case 4: - case 5: - break; - } - - for(j=0; j<length; j++) { - *data++ = unicode[j]; - } - - *changed = 1; - - } + /* compute character number */ + d = ((c & 0x07) << 18) | ((utf[1] & 0x3F) << 12) | ((*(utf + 2) & 0x3F) << 6) | (*(utf + 3) & 0x3F); } } - /* any other first byte is invalid (RFC 3629) */ - else { - count++; - if(count <= len) - *data++ = c; - } - /* invalid UTF-8 character number range (RFC 3629) */ - if ((d >= 0xD800) && (d <= 0xDFFF)) { - count++; - if(count <= len) - *data++ = c; - } - + if ((d >= 0xD800) && (d <= 0xDFFF)) unicode_len = UNICODE_ERROR_RESTRICTED_CHARACTER; /* check for overlong */ - if ((unicode_len == 4) && (d < 0x010000)) { - /* four byte could be represented with less bytes */ - count++; - if(count <= len) - *data++ = c; - } - else if ((unicode_len == 3) && (d < 0x0800)) { - /* three byte could be represented with less bytes */ - count++; - if(count <= len) - *data++ = c; - } - else if ((unicode_len == 2) && (d < 0x80)) { - /* two byte could be represented with less bytes */ - count++; - if(count <= len) - *data++ = c; - } + if ((unicode_len == 4) && (d < 0x010000)) unicode_len = UNICODE_ERROR_OVERLONG_CHARACTER; + /* three byte could be represented with less bytes */ + if ((unicode_len == 3) && (d < 0x0800)) unicode_len = UNICODE_ERROR_OVERLONG_CHARACTER; + /* two byte could be represented with less bytes */ + if ((unicode_len == 2) && (d < 0x80)) unicode_len = UNICODE_ERROR_OVERLONG_CHARACTER; - if(unicode_len > 0) { + if (unicode_len > 0) { i += unicode_len; - } else { + sprintf(data, "%%u%04x", d); + data += 6; + *changed = 1; + } + else { + /* any other first byte is invalid (RFC 3629), so assume it's an ASCII character */ + *data++ = c; i++; } } - *data ='\0'; - + *data = '\0'; return rval; } From 87dbae9bb2f4421b3ce39a6450a7d79fc2b486a6 Mon Sep 17 00:00:00 2001 From: Marc Stern <sternmarc@hotmail.coms> Date: Mon, 4 Nov 2024 13:53:28 +0100 Subject: [PATCH 477/477] assert(input != NULL); --- apache2/msc_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 95cab9b94f..fe13ab9984 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -112,7 +112,7 @@ char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int inp unsigned int bytes_left = input_len; unsigned char *unicode = NULL; - if (input == NULL) return NULL; + assert(input != NULL); *changed = 0; /* RFC3629 states that UTF-8 are encoded using sequences of 1 to 4 octets. */