From 04e4a6f9b8b435b07f6a788f462c3950a14fbd57 Mon Sep 17 00:00:00 2001 From: Allan Boll Date: Fri, 16 Jun 2017 16:56:38 -0700 Subject: [PATCH 001/470] 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 Date: Fri, 23 Jun 2017 16:18:54 -0300 Subject: [PATCH 002/470] 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 Date: Fri, 14 Jul 2017 10:37:58 -0300 Subject: [PATCH 003/470] 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 Date: Fri, 14 Jul 2017 13:22:46 -0300 Subject: [PATCH 004/470] 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 Date: Mon, 17 Jul 2017 08:43:20 -0300 Subject: [PATCH 005/470] 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 Date: Tue, 27 Jun 2017 10:01:49 -0300 Subject: [PATCH 006/470] 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 Date: Mon, 12 Jun 2017 11:55:47 +0100 Subject: [PATCH 007/470] Few missing headers, in the 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 #include +#else +#include +#include #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 #include +#include #if APR_HAVE_STDINT_H #include #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 +#if APR_HAVE_ARPA_INET_H +#include +#endif #include #include #include "modsecurity_config.h" From 2ab08a625eb8e6cfadd757708e742b0b2a2b18f9 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Thu, 28 Sep 2017 22:21:05 +0000 Subject: [PATCH 008/470] 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 Date: Mon, 24 Jul 2017 15:10:29 +0200 Subject: [PATCH 009/470] 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 Date: Fri, 29 Sep 2017 18:35:45 +0000 Subject: [PATCH 010/470] 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 Date: Wed, 4 Oct 2017 13:48:45 +0000 Subject: [PATCH 011/470] 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 Date: Wed, 4 Oct 2017 13:49:54 +0000 Subject: [PATCH 012/470] 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 Date: Thu, 29 Jun 2017 01:37:23 -0400 Subject: [PATCH 013/470] 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 Date: Wed, 4 Oct 2017 21:24:36 +0000 Subject: [PATCH 014/470] 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 Date: Tue, 4 Jul 2017 12:17:40 -0400 Subject: [PATCH 015/470] 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 Date: Thu, 5 Oct 2017 03:25:46 +0000 Subject: [PATCH 016/470] 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 Date: Tue, 6 Jun 2017 16:39:30 +0200 Subject: [PATCH 017/470] 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 Date: Thu, 5 Oct 2017 13:28:28 +0000 Subject: [PATCH 018/470] 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 Date: Thu, 5 Oct 2017 13:33:11 +0000 Subject: [PATCH 019/470] 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 Date: Wed, 23 Aug 2017 19:13:50 -0400 Subject: [PATCH 020/470] 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 Date: Thu, 5 Oct 2017 14:39:32 +0000 Subject: [PATCH 021/470] 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 Date: Thu, 5 Oct 2017 16:39:57 +0000 Subject: [PATCH 022/470] 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 Date: Thu, 5 Oct 2017 16:40:40 +0000 Subject: [PATCH 023/470] 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 Date: Fri, 18 Aug 2017 17:45:44 -0700 Subject: [PATCH 024/470] 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 Date: Tue, 22 Aug 2017 10:37:29 -0700 Subject: [PATCH 025/470] 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 Date: Tue, 22 Aug 2017 15:31:33 -0700 Subject: [PATCH 026/470] 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 Date: Tue, 22 Aug 2017 15:32:52 -0700 Subject: [PATCH 027/470] 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 Date: Tue, 22 Aug 2017 17:12:37 -0700 Subject: [PATCH 028/470] 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 Date: Tue, 29 Aug 2017 23:22:04 -0700 Subject: [PATCH 029/470] 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 Date: Thu, 5 Oct 2017 18:25:52 +0000 Subject: [PATCH 030/470] 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 Date: Thu, 5 Oct 2017 18:28:07 +0000 Subject: [PATCH 031/470] 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 Date: Tue, 30 May 2017 22:05:16 -0300 Subject: [PATCH 032/470] 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 Date: Wed, 28 Feb 2018 11:16:34 -0300 Subject: [PATCH 033/470] 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 Date: Wed, 28 Feb 2018 11:20:13 -0300 Subject: [PATCH 034/470] 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 Date: Tue, 20 Mar 2018 10:57:19 -0700 Subject: [PATCH 035/470] 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 Date: Tue, 20 Mar 2018 11:35:40 -0700 Subject: [PATCH 036/470] 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 Date: Tue, 8 May 2018 12:40:23 -0500 Subject: [PATCH 037/470] 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 Date: Thu, 10 May 2018 15:32:38 -0300 Subject: [PATCH 038/470] 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 Date: Sun, 25 Mar 2018 17:38:54 +0100 Subject: [PATCH 039/470] 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 Date: Thu, 10 May 2018 18:42:45 -0300 Subject: [PATCH 040/470] 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 Date: Wed, 23 May 2018 17:01:38 -0500 Subject: [PATCH 041/470] IIS: set overrideModeDefault to Allow so that individual websites can add 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 @@ - + From 71f650ad48c8b92ddf76817a86824b66a431a0d5 Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Mon, 28 May 2018 17:55:37 -0300 Subject: [PATCH 042/470] 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 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 Date: Thu, 7 Jun 2018 14:48:18 -0300 Subject: [PATCH 043/470] 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 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 Date: Tue, 4 Sep 2018 21:00:26 -0300 Subject: [PATCH 044/470] 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 Date: Tue, 4 Sep 2018 22:40:26 -0300 Subject: [PATCH 045/470] 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 Date: Wed, 5 Sep 2018 15:33:39 -0300 Subject: [PATCH 046/470] 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 Date: Mon, 6 Nov 2017 14:03:25 -0800 Subject: [PATCH 047/470] 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 Date: Wed, 23 May 2018 19:21:25 -0700 Subject: [PATCH 048/470] 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 Date: Wed, 5 Sep 2018 16:27:49 -0300 Subject: [PATCH 049/470] 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 Date: Wed, 5 Sep 2018 23:25:51 -0300 Subject: [PATCH 050/470] 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 Date: Wed, 10 Jan 2018 18:36:52 -0800 Subject: [PATCH 051/470] 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 Date: Thu, 6 Sep 2018 10:03:15 -0300 Subject: [PATCH 052/470] 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 Date: Wed, 6 Jun 2018 20:08:03 -0700 Subject: [PATCH 053/470] 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 Date: Thu, 6 Sep 2018 10:09:12 -0300 Subject: [PATCH 054/470] 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 Date: Sat, 28 Jul 2018 22:09:13 +0800 Subject: [PATCH 055/470] 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 +## 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 Date: Thu, 23 Aug 2018 09:56:16 +0800 Subject: [PATCH 056/470] 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 Date: Thu, 20 Sep 2018 16:43:08 -0400 Subject: [PATCH 057/470] 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 Date: Wed, 28 Feb 2018 12:34:32 -0600 Subject: [PATCH 058/470] 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 Date: Sat, 22 Sep 2018 20:21:23 -0400 Subject: [PATCH 059/470] 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 Date: Sat, 22 Sep 2018 20:40:30 -0400 Subject: [PATCH 060/470] 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 Date: Sat, 22 Sep 2018 20:51:27 -0400 Subject: [PATCH 061/470] 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 Date: Sat, 22 Sep 2018 18:33:12 -0400 Subject: [PATCH 062/470] 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 Date: Fri, 12 Oct 2018 21:27:50 -0400 Subject: [PATCH 063/470] 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 Date: Wed, 17 Oct 2018 09:21:02 -0300 Subject: [PATCH 064/470] 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 Date: Wed, 26 Sep 2018 17:23:17 -0700 Subject: [PATCH 065/470] 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 Date: Fri, 19 Oct 2018 19:50:05 -0400 Subject: [PATCH 066/470] 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 Date: Fri, 2 Nov 2018 19:01:36 -0400 Subject: [PATCH 067/470] 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 @@ - + From e97799c9bc5dbf614e317ac3269ce8e7fd6c0176 Mon Sep 17 00:00:00 2001 From: Allan Boll Date: Fri, 3 Nov 2017 16:04:00 -0700 Subject: [PATCH 068/470] 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 Date: Sun, 4 Nov 2018 13:06:37 -0500 Subject: [PATCH 069/470] 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 Date: Sun, 4 Nov 2018 21:20:10 -0500 Subject: [PATCH 070/470] 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 Date: Sun, 4 Nov 2018 22:04:34 -0500 Subject: [PATCH 071/470] 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 Date: Fri, 9 Nov 2018 17:57:31 -0500 Subject: [PATCH 072/470] 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 Date: Fri, 9 Nov 2018 18:06:56 -0500 Subject: [PATCH 073/470] 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 Date: Fri, 9 Nov 2018 18:10:59 -0500 Subject: [PATCH 074/470] 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 Date: Sun, 11 Nov 2018 15:33:29 -0500 Subject: [PATCH 075/470] 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 Date: Mon, 12 Nov 2018 15:45:47 -0500 Subject: [PATCH 076/470] 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 @@ - - + + - + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -267,6 +235,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -276,35 +281,11 @@ - - - - - - + - - - - - - - - - - - - - + - - - - - - - @@ -340,6 +321,7 @@ + @@ -428,24 +410,24 @@ - - - + + + + - - - - - + + + + + + - - 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 Date: Mon, 12 Nov 2018 15:54:36 -0500 Subject: [PATCH 077/470] 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 Date: Mon, 12 Nov 2018 19:54:18 -0500 Subject: [PATCH 078/470] 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 Date: Tue, 13 Nov 2018 20:03:41 -0500 Subject: [PATCH 079/470] 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 Date: Fri, 16 Jun 2017 17:42:24 -0700 Subject: [PATCH 080/470] 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 Date: Fri, 23 Nov 2018 22:33:01 -0300 Subject: [PATCH 081/470] 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 Date: Mon, 26 Nov 2018 10:48:49 -0300 Subject: [PATCH 082/470] 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 Date: Mon, 20 Nov 2017 12:17:42 -0800 Subject: [PATCH 083/470] 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 Date: Fri, 30 Nov 2018 10:27:18 -0300 Subject: [PATCH 084/470] 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 Date: Tue, 4 Dec 2018 11:44:40 -0500 Subject: [PATCH 085/470] 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 Date: Mon, 3 Dec 2018 09:15:49 -0300 Subject: [PATCH 086/470] 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 Date: Mon, 10 Dec 2018 15:16:04 -0300 Subject: [PATCH 087/470] 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 Date: Sun, 9 Dec 2018 20:26:40 +0000 Subject: [PATCH 088/470] 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 Date: Mon, 10 Dec 2018 15:41:28 -0300 Subject: [PATCH 089/470] 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" Date: Thu, 15 Nov 2018 12:41:57 +0100 Subject: [PATCH 090/470] 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 Date: Mon, 10 Dec 2018 16:55:48 -0300 Subject: [PATCH 091/470] 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 Date: Fri, 14 Dec 2018 23:53:05 -0300 Subject: [PATCH 092/470] 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 Date: Tue, 12 Mar 2019 16:29:43 +0100 Subject: [PATCH 093/470] 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 Date: Fri, 17 May 2019 15:19:09 +0900 Subject: [PATCH 094/470] 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 Date: Mon, 27 May 2019 10:33:56 -0300 Subject: [PATCH 095/470] 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 Date: Wed, 15 May 2019 01:31:43 +0200 Subject: [PATCH 096/470] 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 Date: Mon, 27 May 2019 14:34:08 -0300 Subject: [PATCH 097/470] 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 Date: Wed, 26 Jun 2019 09:17:46 +0200 Subject: [PATCH 098/470] 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 Date: Wed, 26 Jun 2019 13:03:35 -0300 Subject: [PATCH 099/470] 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 Date: Wed, 10 Jul 2019 14:41:32 -0300 Subject: [PATCH 100/470] 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 Date: Wed, 23 Oct 2019 15:01:10 +0200 Subject: [PATCH 101/470] 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 Date: Mon, 13 Jan 2020 16:36:09 -0800 Subject: [PATCH 102/470] 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 --- 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 Date: Tue, 19 Mar 2019 13:10:53 -0500 Subject: [PATCH 103/470] 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 Date: Tue, 19 Mar 2019 13:40:50 -0500 Subject: [PATCH 104/470] 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 Date: Thu, 14 Jan 2021 14:27:14 -0300 Subject: [PATCH 105/470] 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 Date: Wed, 15 May 2019 01:50:20 +0200 Subject: [PATCH 106/470] 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 Date: Fri, 15 Jan 2021 15:15:11 -0300 Subject: [PATCH 107/470] 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 Date: Wed, 17 Mar 2021 12:45:17 -0300 Subject: [PATCH 108/470] 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 Date: Mon, 14 Jun 2021 19:09:06 -0300 Subject: [PATCH 109/470] 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: --> - + @@ -129,12 +129,15 @@ - + + + - + - + @@ -315,104 +319,189 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -526,8 +616,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 Date: Tue, 1 Jun 2021 21:24:56 -0300 Subject: [PATCH 110/470] 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 111/470] 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 Date: Mon, 13 Sep 2021 16:30:50 -0600 Subject: [PATCH 112/470] 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 Date: Thu, 18 Nov 2021 17:35:40 -0800 Subject: [PATCH 113/470] 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 Date: Mon, 22 Nov 2021 11:22:12 -0800 Subject: [PATCH 114/470] 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: --> - + From df4bffcdc8960464022beb5f7cb1bc70706b2ae1 Mon Sep 17 00:00:00 2001 From: Martin Vierula Date: Mon, 6 Dec 2021 14:27:04 -0800 Subject: [PATCH 115/470] 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 Date: Tue, 21 Dec 2021 06:30:28 -0800 Subject: [PATCH 116/470] 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 Date: Wed, 22 Dec 2021 10:37:03 -0800 Subject: [PATCH 117/470] 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 Date: Wed, 29 Dec 2021 06:46:25 -0800 Subject: [PATCH 118/470] 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 Date: Tue, 19 Apr 2022 10:07:36 -0700 Subject: [PATCH 119/470] 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 Date: Tue, 3 May 2022 12:34:03 -0700 Subject: [PATCH 120/470] 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 Date: Fri, 27 May 2022 11:05:37 -0700 Subject: [PATCH 121/470] 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 Date: Thu, 14 Apr 2022 16:27:49 +0200 Subject: [PATCH 122/470] 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 Date: Wed, 1 Jun 2022 07:19:10 -0700 Subject: [PATCH 123/470] 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 Date: Wed, 8 Jun 2022 15:36:36 -0700 Subject: [PATCH 124/470] 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 Date: Wed, 8 Jun 2022 15:55:25 -0700 Subject: [PATCH 125/470] 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 Date: Thu, 4 Aug 2022 12:40:32 +0300 Subject: [PATCH 126/470] 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 Date: Sat, 20 Aug 2022 15:24:37 -0700 Subject: [PATCH 127/470] 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 Date: Fri, 26 Aug 2022 11:35:43 -0700 Subject: [PATCH 128/470] 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 Date: Fri, 26 Aug 2022 11:52:13 -0700 Subject: [PATCH 129/470] 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 Date: Tue, 6 Sep 2022 05:29:38 -0700 Subject: [PATCH 130/470] 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 Date: Wed, 7 Sep 2022 11:09:47 -0700 Subject: [PATCH 131/470] 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 Date: Wed, 7 Sep 2022 11:43:54 -0700 Subject: [PATCH 132/470] 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 Date: Wed, 7 Sep 2022 13:36:13 -0700 Subject: [PATCH 133/470] 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: --> - + From 849cd7e8484bb5dcbc351a7a4c4060c4274fe840 Mon Sep 17 00:00:00 2001 From: Martin Vierula Date: Fri, 14 Oct 2022 08:56:01 -0700 Subject: [PATCH 134/470] 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 Date: Sun, 16 Oct 2022 18:09:37 +1100 Subject: [PATCH 135/470] 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 Date: Tue, 8 Nov 2022 08:06:39 -0800 Subject: [PATCH 136/470] 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 : "")); 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 : "")); @@ -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 Date: Tue, 8 Nov 2022 13:04:27 -0800 Subject: [PATCH 137/470] 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 /* for getpid() */ #endif +#ifdef WITH_PCRE2 +#define PCRE2_CODE_UNIT_WIDTH 8 +#include +#else #include +#endif #include #include #include @@ -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 Date: Fri, 11 Nov 2022 14:00:20 -0800 Subject: [PATCH 138/470] 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 Date: Mon, 14 Nov 2022 11:48:21 -0800 Subject: [PATCH 139/470] 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 Date: Tue, 15 Nov 2022 17:31:18 +0200 Subject: [PATCH 140/470] 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 #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 #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 #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 Date: Tue, 15 Nov 2022 14:22:03 -0800 Subject: [PATCH 141/470] 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 Date: Wed, 16 Nov 2022 08:39:22 -0800 Subject: [PATCH 142/470] 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 Date: Sun, 20 Nov 2022 10:39:04 -0800 Subject: [PATCH 143/470] 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 Date: Wed, 23 Nov 2022 14:28:00 -0800 Subject: [PATCH 144/470] 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 Date: Wed, 7 Dec 2022 07:47:42 -0800 Subject: [PATCH 145/470] 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 Date: Mon, 12 Dec 2022 02:26:13 -0800 Subject: [PATCH 146/470] 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 Date: Mon, 12 Dec 2022 02:41:16 -0800 Subject: [PATCH 147/470] 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 Date: Wed, 14 Dec 2022 07:01:23 -0800 Subject: [PATCH 148/470] 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 Date: Fri, 16 Dec 2022 08:37:56 -0800 Subject: [PATCH 149/470] 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 Date: Wed, 21 Dec 2022 07:07:14 -0800 Subject: [PATCH 150/470] 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 Date: Wed, 4 Jan 2023 06:56:54 -0800 Subject: [PATCH 151/470] 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 Date: Wed, 4 Jan 2023 08:00:49 -0800 Subject: [PATCH 152/470] 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 Date: Wed, 4 Jan 2023 11:34:11 -0800 Subject: [PATCH 153/470] 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 Date: Wed, 4 Jan 2023 13:15:13 -0800 Subject: [PATCH 154/470] 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: --> - + From 916bded59014e15c57221d177fad4d45c8f4454f Mon Sep 17 00:00:00 2001 From: Martin Vierula Date: Thu, 19 Jan 2023 12:20:13 -0800 Subject: [PATCH 155/470] 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 Date: Tue, 14 Mar 2023 11:36:22 +0100 Subject: [PATCH 156/470] 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 --- 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 Date: Mon, 20 Mar 2023 10:49:44 -0700 Subject: [PATCH 157/470] 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 Date: Mon, 17 Jul 2023 17:32:10 +0200 Subject: [PATCH 158/470] 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 Date: Tue, 6 Jun 2023 13:50:07 -0700 Subject: [PATCH 159/470] 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 Date: Fri, 11 Aug 2023 16:34:04 +0200 Subject: [PATCH 160/470] 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 Date: Fri, 11 Aug 2023 16:44:18 +0200 Subject: [PATCH 161/470] 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 Date: Fri, 11 Aug 2023 17:17:59 +0200 Subject: [PATCH 162/470] 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 Date: Fri, 11 Aug 2023 17:19:08 +0200 Subject: [PATCH 163/470] 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 Date: Fri, 11 Aug 2023 17:22:24 +0200 Subject: [PATCH 164/470] 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 Date: Fri, 11 Aug 2023 17:41:04 +0200 Subject: [PATCH 165/470] 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 Date: Mon, 14 Aug 2023 16:57:21 +0200 Subject: [PATCH 166/470] 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 Date: Wed, 16 Aug 2023 08:25:50 +0200 Subject: [PATCH 167/470] 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 Date: Wed, 16 Aug 2023 08:28:12 +0200 Subject: [PATCH 168/470] 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 Date: Wed, 16 Aug 2023 08:50:09 +0200 Subject: [PATCH 169/470] 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 Date: Wed, 16 Aug 2023 16:54:55 +0200 Subject: [PATCH 170/470] 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 Date: Fri, 18 Aug 2023 16:47:00 +0200 Subject: [PATCH 171/470] 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 Date: Fri, 18 Aug 2023 16:48:25 +0200 Subject: [PATCH 172/470] 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 Date: Fri, 18 Aug 2023 16:54:19 +0200 Subject: [PATCH 173/470] 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 Date: Fri, 18 Aug 2023 17:16:18 +0200 Subject: [PATCH 174/470] 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 Date: Mon, 21 Aug 2023 09:33:27 +0200 Subject: [PATCH 175/470] 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 Date: Mon, 21 Aug 2023 09:39:42 +0200 Subject: [PATCH 176/470] 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 Date: Mon, 21 Aug 2023 10:01:46 +0200 Subject: [PATCH 177/470] 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 Date: Mon, 21 Aug 2023 10:30:36 +0200 Subject: [PATCH 178/470] 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 Date: Thu, 24 Aug 2023 15:01:14 -0700 Subject: [PATCH 179/470] 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 Date: Mon, 11 Sep 2023 08:07:49 -0700 Subject: [PATCH 180/470] 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 Date: Mon, 25 Sep 2023 16:00:17 +0200 Subject: [PATCH 181/470] 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 Date: Mon, 25 Sep 2023 16:15:19 +0200 Subject: [PATCH 182/470] 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 Date: Tue, 3 Oct 2023 16:50:12 +0200 Subject: [PATCH 183/470] 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 Date: Thu, 5 Oct 2023 14:48:24 +0200 Subject: [PATCH 184/470] 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 Date: Thu, 12 Oct 2023 07:55:56 -0700 Subject: [PATCH 185/470] 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 Date: Mon, 16 Oct 2023 12:45:36 -0700 Subject: [PATCH 186/470] 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 Date: Tue, 17 Oct 2023 14:06:56 +0200 Subject: [PATCH 187/470] 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 Date: Tue, 17 Oct 2023 06:37:08 -0700 Subject: [PATCH 188/470] 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 Date: Thu, 26 Oct 2023 09:22:22 +0200 Subject: [PATCH 189/470] 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 Date: Thu, 26 Oct 2023 14:21:32 +0200 Subject: [PATCH 190/470] 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 Date: Thu, 26 Oct 2023 15:00:10 +0200 Subject: [PATCH 191/470] 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 Date: Thu, 26 Oct 2023 15:55:57 +0200 Subject: [PATCH 192/470] 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 Date: Tue, 31 Oct 2023 12:55:07 +0100 Subject: [PATCH 193/470] 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 Date: Tue, 31 Oct 2023 13:01:19 +0100 Subject: [PATCH 194/470] 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 Date: Thu, 2 Nov 2023 13:21:39 +0100 Subject: [PATCH 195/470] 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 Date: Thu, 2 Nov 2023 13:30:16 +0100 Subject: [PATCH 196/470] 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 Date: Sat, 27 Jan 2024 17:09:43 +0100 Subject: [PATCH 197/470] 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 Date: Sun, 28 Jan 2024 09:40:40 +0100 Subject: [PATCH 198/470] 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 @@ - - + + From 35e97b51459ab95d845e72ef55428b662bba0ee9 Mon Sep 17 00:00:00 2001 From: Marc Stern Date: Thu, 1 Feb 2024 11:48:21 +0100 Subject: [PATCH 199/470] 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 Date: Thu, 1 Feb 2024 12:18:08 +0100 Subject: [PATCH 200/470] ; 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 Date: Fri, 2 Feb 2024 13:05:10 +0100 Subject: [PATCH 201/470] 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 Date: Mon, 5 Feb 2024 10:36:04 +0100 Subject: [PATCH 202/470] 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 Date: Tue, 6 Feb 2024 09:54:07 +0100 Subject: [PATCH 203/470] 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 Date: Wed, 7 Feb 2024 12:04:50 +0100 Subject: [PATCH 204/470] 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 Date: Wed, 7 Feb 2024 22:37:16 +0100 Subject: [PATCH 205/470] 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 Date: Wed, 7 Feb 2024 22:40:39 +0100 Subject: [PATCH 206/470] 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 Date: Wed, 7 Feb 2024 23:01:07 +0100 Subject: [PATCH 207/470] 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 Date: Wed, 7 Feb 2024 23:02:10 +0100 Subject: [PATCH 208/470] 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 Date: Wed, 7 Feb 2024 23:02:37 +0100 Subject: [PATCH 209/470] 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 Date: Wed, 7 Feb 2024 23:03:23 +0100 Subject: [PATCH 210/470] 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 Date: Wed, 7 Feb 2024 23:03:48 +0100 Subject: [PATCH 211/470] 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 Date: Wed, 7 Feb 2024 23:04:14 +0100 Subject: [PATCH 212/470] Revert "Detailed error message when writing collections" From c3688dd8c4cff56b0ad680255a88b23ee41b8a9d Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 7 Feb 2024 23:04:47 +0100 Subject: [PATCH 213/470] 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 Date: Wed, 7 Feb 2024 23:05:28 +0100 Subject: [PATCH 214/470] 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 Date: Wed, 7 Feb 2024 23:06:16 +0100 Subject: [PATCH 215/470] 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 Date: Wed, 7 Feb 2024 23:06:42 +0100 Subject: [PATCH 216/470] 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 Date: Wed, 7 Feb 2024 23:07:14 +0100 Subject: [PATCH 217/470] 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 Date: Wed, 7 Feb 2024 23:08:06 +0100 Subject: [PATCH 218/470] 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 Date: Wed, 7 Feb 2024 23:08:46 +0100 Subject: [PATCH 219/470] 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 Date: Wed, 7 Feb 2024 23:09:05 +0100 Subject: [PATCH 220/470] 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 Date: Wed, 7 Feb 2024 23:09:34 +0100 Subject: [PATCH 221/470] 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 Date: Wed, 7 Feb 2024 23:09:59 +0100 Subject: [PATCH 222/470] 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 Date: Wed, 7 Feb 2024 23:10:22 +0100 Subject: [PATCH 223/470] 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 Date: Thu, 8 Feb 2024 00:00:25 +0100 Subject: [PATCH 224/470] 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 Date: Thu, 8 Feb 2024 00:05:00 +0100 Subject: [PATCH 225/470] 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 Date: Thu, 8 Feb 2024 00:07:20 +0100 Subject: [PATCH 226/470] 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 Date: Thu, 8 Feb 2024 00:10:25 +0100 Subject: [PATCH 227/470] 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 Date: Thu, 8 Feb 2024 00:14:10 +0100 Subject: [PATCH 228/470] 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 Date: Thu, 8 Feb 2024 00:39:57 +0100 Subject: [PATCH 229/470] 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 Date: Thu, 8 Feb 2024 00:46:53 +0100 Subject: [PATCH 230/470] 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 Date: Thu, 8 Feb 2024 00:53:06 +0100 Subject: [PATCH 231/470] 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 Date: Thu, 8 Feb 2024 01:01:41 +0100 Subject: [PATCH 232/470] 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 Date: Thu, 8 Feb 2024 23:53:30 +0100 Subject: [PATCH 233/470] 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 + + + SecDataDir /var/cache/modsecurity + Include /etc/apache2/modsecurity.conf + 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 Date: Tue, 20 Feb 2024 13:15:52 +0100 Subject: [PATCH 234/470] 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 #include #include 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 Date: Wed, 21 Feb 2024 17:43:21 +0100 Subject: [PATCH 235/470] 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 Date: Sun, 25 Feb 2024 20:28:12 +0100 Subject: [PATCH 236/470] 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 . # # 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 . # 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 or send patches to # . +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 . 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 ], - [ +AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ #include ]], + [[ #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 Date: Sun, 25 Feb 2024 20:34:50 +0100 Subject: [PATCH 237/470] 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 Date: Fri, 1 Mar 2024 10:57:03 +0100 Subject: [PATCH 238/470] 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 Date: Sun, 3 Mar 2024 16:20:07 +0100 Subject: [PATCH 239/470] 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 Date: Thu, 4 Apr 2024 15:45:55 +0200 Subject: [PATCH 240/470] 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 Date: Thu, 4 Apr 2024 16:01:51 +0200 Subject: [PATCH 241/470] 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 Date: Fri, 5 Apr 2024 18:17:25 +0200 Subject: [PATCH 242/470] 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 Date: Fri, 5 Apr 2024 18:21:02 +0200 Subject: [PATCH 243/470] 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 Date: Mon, 8 Apr 2024 11:01:29 +0200 Subject: [PATCH 244/470] 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 Date: Wed, 10 Apr 2024 14:04:34 +0200 Subject: [PATCH 245/470] 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 Date: Wed, 10 Apr 2024 17:10:03 +0200 Subject: [PATCH 246/470] 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 Date: Thu, 11 Apr 2024 13:42:37 +0200 Subject: [PATCH 247/470] 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 Date: Fri, 12 Apr 2024 16:28:45 +0200 Subject: [PATCH 248/470] 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 ]], - [[ - #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 ]], + [[ + #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 Date: Fri, 12 Apr 2024 18:04:16 +0200 Subject: [PATCH 249/470] 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 ]], - [[ - #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 ]], + [[ + #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 Date: Tue, 16 Apr 2024 13:28:37 +0200 Subject: [PATCH 250/470] 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 Date: Tue, 16 Apr 2024 17:59:43 +0200 Subject: [PATCH 251/470] 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 Date: Tue, 16 Apr 2024 18:02:06 +0200 Subject: [PATCH 252/470] 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 Date: Tue, 16 Apr 2024 18:09:00 +0200 Subject: [PATCH 253/470] (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 Date: Fri, 26 Apr 2024 17:22:16 +0200 Subject: [PATCH 254/470] 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 Date: Fri, 10 May 2024 17:26:23 +0200 Subject: [PATCH 255/470] 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 Date: Thu, 16 May 2024 15:52:31 +0200 Subject: [PATCH 256/470] 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 Date: Thu, 16 May 2024 16:55:31 +0200 Subject: [PATCH 257/470] 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;ivalue_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 : "")); - 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 : "")); + 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 : "")); + char *pattern = apr_pstrdup(msr->mp, log_escape(msr->mp, regex->pattern ? regex->pattern : "")); /* 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 : ""); + char *match_escaped = log_escape(msr->mp, match ? 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; jmp, 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 Date: Thu, 16 May 2024 16:56:46 +0200 Subject: [PATCH 258/470] 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 Date: Thu, 23 May 2024 09:40:09 -0300 Subject: [PATCH 259/470] docs: update README Signed-off-by: Felipe Zipitria --- 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 Date: Tue, 28 May 2024 15:41:38 +0200 Subject: [PATCH 260/470] 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 Date: Tue, 28 May 2024 16:19:29 +0200 Subject: [PATCH 261/470] 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 Date: Tue, 28 May 2024 16:25:26 +0200 Subject: [PATCH 262/470] 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 Date: Wed, 29 May 2024 11:38:10 +0200 Subject: [PATCH 263/470] 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 Date: Wed, 29 May 2024 14:26:27 -0300 Subject: [PATCH 264/470] chore: add gitignore file Signed-off-by: Felipe Zipitria --- .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 Date: Thu, 23 May 2024 10:40:46 -0300 Subject: [PATCH 265/470] fix: remove unsafe tmpnam usage Signed-off-by: Felipe Zipitria --- 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 Date: Wed, 29 May 2024 09:07:14 -0300 Subject: [PATCH 266/470] refactor: add acquire mutex function Signed-off-by: Felipe Zipitria --- 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 Date: Wed, 29 May 2024 14:18:55 -0300 Subject: [PATCH 267/470] fix: add error logging Signed-off-by: Felipe Zipitria --- 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 Date: Thu, 30 May 2024 09:32:50 -0300 Subject: [PATCH 268/470] feat: consolidate into acquire_global_lock and export prototype Signed-off-by: Felipe Zipitria --- 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 Date: Thu, 30 May 2024 09:45:02 -0300 Subject: [PATCH 269/470] chore: add PR template Signed-off-by: Felipe Zipitria --- .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 @@ + + + +## what + + + +## why + + + +## references + + From bcd50bec840ab9bbac184358c2902256dc716a3d Mon Sep 17 00:00:00 2001 From: Marc Stern Date: Wed, 12 Jun 2024 14:51:51 +0200 Subject: [PATCH 270/470] 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 Date: Sat, 20 Jul 2024 18:45:14 +0200 Subject: [PATCH 271/470] 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 Date: Sat, 20 Jul 2024 18:53:30 +0200 Subject: [PATCH 272/470] 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 Date: Mon, 22 Jul 2024 15:23:51 +0200 Subject: [PATCH 273/470] 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 Date: Mon, 22 Jul 2024 15:29:45 +0200 Subject: [PATCH 274/470] 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 + +SecAuditLog /var/log/apache2/modsec_audit.log From 243d9c978ace342a10cb73a6a000e535ae31d378 Mon Sep 17 00:00:00 2001 From: Marc Stern Date: Mon, 22 Jul 2024 15:57:15 +0200 Subject: [PATCH 275/470] 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 Date: Mon, 22 Jul 2024 15:59:28 +0200 Subject: [PATCH 276/470] 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 Date: Mon, 22 Jul 2024 16:24:56 +0200 Subject: [PATCH 277/470] 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 Date: Mon, 22 Jul 2024 16:53:58 +0200 Subject: [PATCH 278/470] 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 Date: Mon, 22 Jul 2024 17:08:16 +0200 Subject: [PATCH 279/470] 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 Date: Thu, 25 Jul 2024 08:39:44 +0200 Subject: [PATCH 280/470] 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 Date: Thu, 25 Jul 2024 08:55:26 +0200 Subject: [PATCH 281/470] 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 Date: Thu, 25 Jul 2024 09:30:48 +0200 Subject: [PATCH 282/470] 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 Date: Thu, 25 Jul 2024 20:52:55 +0200 Subject: [PATCH 283/470] 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 Date: Wed, 31 Jul 2024 09:38:20 +0200 Subject: [PATCH 284/470] 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 Date: Wed, 31 Jul 2024 11:17:36 +0200 Subject: [PATCH 285/470] 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 Date: Fri, 2 Aug 2024 11:19:34 +0200 Subject: [PATCH 286/470] 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 Date: Fri, 2 Aug 2024 11:28:07 +0200 Subject: [PATCH 287/470] 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 Date: Fri, 2 Aug 2024 11:43:09 +0200 Subject: [PATCH 288/470] 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 Date: Fri, 2 Aug 2024 12:11:16 +0200 Subject: [PATCH 289/470] 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 Date: Sat, 3 Aug 2024 16:22:45 +0200 Subject: [PATCH 290/470] 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 Date: Wed, 7 Aug 2024 09:42:40 +0200 Subject: [PATCH 291/470] 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 Date: Wed, 7 Aug 2024 13:45:09 +0200 Subject: [PATCH 292/470] 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 Date: Wed, 7 Aug 2024 17:01:20 +0200 Subject: [PATCH 293/470] # 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 Date: Thu, 8 Aug 2024 16:16:14 +0200 Subject: [PATCH 294/470] 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 Date: Mon, 12 Aug 2024 17:06:35 +0200 Subject: [PATCH 295/470] 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 Date: Tue, 13 Aug 2024 11:07:18 +0200 Subject: [PATCH 296/470] 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 Date: Tue, 13 Aug 2024 11:07:44 +0200 Subject: [PATCH 297/470] 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 Date: Tue, 13 Aug 2024 19:35:17 +0200 Subject: [PATCH 298/470] 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 Date: Wed, 14 Aug 2024 09:32:08 +0200 Subject: [PATCH 299/470] 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 Date: Wed, 14 Aug 2024 10:59:56 +0200 Subject: [PATCH 300/470] 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 Date: Wed, 14 Aug 2024 12:56:59 +0200 Subject: [PATCH 301/470] 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 Date: Wed, 14 Aug 2024 13:53:52 +0200 Subject: [PATCH 302/470] 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 Date: Wed, 14 Aug 2024 18:44:45 +0200 Subject: [PATCH 303/470] 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 Date: Wed, 14 Aug 2024 19:00:25 +0200 Subject: [PATCH 304/470] 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 #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 Date: Wed, 14 Aug 2024 19:09:15 +0200 Subject: [PATCH 305/470] 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 Date: Wed, 14 Aug 2024 19:12:03 +0200 Subject: [PATCH 306/470] 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 Date: Fri, 16 Aug 2024 09:23:11 +0200 Subject: [PATCH 307/470] 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 Date: Sun, 18 Aug 2024 22:59:22 +0200 Subject: [PATCH 308/470] 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 Date: Mon, 19 Aug 2024 14:19:05 +0200 Subject: [PATCH 309/470] 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 Date: Mon, 19 Aug 2024 16:47:09 +0200 Subject: [PATCH 310/470] 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 Date: Tue, 20 Aug 2024 15:27:44 +0200 Subject: [PATCH 311/470] 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 Date: Mon, 26 Aug 2024 16:38:30 +0200 Subject: [PATCH 312/470] 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 Date: Mon, 26 Aug 2024 17:17:36 +0200 Subject: [PATCH 313/470] 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 Date: Mon, 26 Aug 2024 17:59:11 +0200 Subject: [PATCH 314/470] 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 Date: Mon, 2 Sep 2024 22:21:08 +0200 Subject: [PATCH 315/470] 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 Date: Tue, 3 Sep 2024 07:42:20 +0200 Subject: [PATCH 316/470] 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 Date: Tue, 3 Sep 2024 14:40:55 +0200 Subject: [PATCH 317/470] 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 Date: Tue, 3 Sep 2024 21:49:43 +0200 Subject: [PATCH 318/470] 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 Date: Tue, 3 Sep 2024 21:50:22 +0200 Subject: [PATCH 319/470] 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 Date: Thu, 12 Sep 2024 12:18:25 +0200 Subject: [PATCH 320/470] 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 Date: Thu, 12 Sep 2024 13:01:44 +0200 Subject: [PATCH 321/470] 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 Date: Thu, 12 Sep 2024 14:07:55 +0200 Subject: [PATCH 322/470] 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 Date: Fri, 20 Sep 2024 12:51:03 +0200 Subject: [PATCH 323/470] 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 Date: Wed, 25 Sep 2024 13:57:05 +0200 Subject: [PATCH 324/470] Missing #include --- 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 #include "http_core.h" #include "modsecurity.h" From 339d6df2a566bc3856b6b2effd77333d46d56ada Mon Sep 17 00:00:00 2001 From: Marc Stern Date: Fri, 27 Sep 2024 09:26:58 +0200 Subject: [PATCH 325/470] 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 Date: Fri, 27 Sep 2024 09:27:29 +0200 Subject: [PATCH 326/470] 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 Date: Mon, 30 Sep 2024 13:12:38 +0200 Subject: [PATCH 327/470] 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 Date: Mon, 30 Sep 2024 13:53:31 +0200 Subject: [PATCH 328/470] 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 Date: Tue, 1 Oct 2024 13:58:22 +0200 Subject: [PATCH 329/470] 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 Date: Wed, 2 Oct 2024 17:11:01 +0200 Subject: [PATCH 330/470] 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 Date: Thu, 3 Oct 2024 12:42:23 +0200 Subject: [PATCH 331/470] 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 Date: Thu, 3 Oct 2024 12:59:48 +0200 Subject: [PATCH 332/470] 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 Date: Fri, 4 Oct 2024 15:48:12 +0200 Subject: [PATCH 333/470] 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 Date: Thu, 17 Oct 2024 14:10:56 +0200 Subject: [PATCH 334/470] 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 Date: Thu, 17 Oct 2024 14:43:03 +0200 Subject: [PATCH 335/470] 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 Date: Tue, 22 Oct 2024 15:51:55 +0200 Subject: [PATCH 336/470] 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= 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= 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 Date: Mon, 4 Nov 2024 13:53:28 +0100 Subject: [PATCH 337/470] 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. */ From 0c8cc6e2cf88ba2da48dffe29807521c36ed8ce1 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 30 Sep 2024 18:53:19 +0200 Subject: [PATCH 338/470] Finish XMLArgs processing --- apache2/apache2_config.c | 40 +++++++ apache2/modsecurity.h | 5 + apache2/msc_xml.c | 231 +++++++++++++++++++++++++++++++++++---- apache2/msc_xml.h | 21 ++++ apache2/re_actions.c | 30 +++++ 5 files changed, 306 insertions(+), 21 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index da10b4bfe6..1739af280b 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -166,6 +166,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) /* xml external entity */ dcfg->xml_external_entity = NOT_SET; + dcfg->parse_xml_into_args = NOT_SET; return dcfg; } @@ -640,6 +641,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) /* xml external entity */ merged->xml_external_entity = (child->xml_external_entity == NOT_SET ? parent->xml_external_entity : child->xml_external_entity); + merged->parse_xml_into_args = (child->parse_xml_into_args == NOT_SET + ? parent->parse_xml_into_args : child->parse_xml_into_args); return merged; } @@ -773,6 +776,7 @@ void init_directory_config(directory_config *dcfg) /* xml external entity */ if (dcfg->xml_external_entity == NOT_SET) dcfg->xml_external_entity = 0; + if (dcfg->parse_xml_into_args == NOT_SET) dcfg->parse_xml_into_args = 0; } @@ -3698,6 +3702,34 @@ static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, return NULL; } +/** +* \brief Add SecParseXMLIntoArgs configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_parse_xml_into_args(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, "cmd_hash_engine: _dcfg is NULL"); + return NULL; + } + directory_config *dcfg = (directory_config *)_dcfg; + if (strcasecmp(p1, "on") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_ON; } + else if (strcasecmp(p1, "off") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_OFF; } + else if (strcasecmp(p1, "onlyargs") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_ONLYARGS; } + else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecParseXMLIntoArgs: %s", p1); + + return NULL; +} /* -- Configuration directives definitions -- */ @@ -4466,5 +4498,13 @@ const command_rec module_directives[] = { "Set Hash parameter" ), + AP_INIT_TAKE1 ( + "SecParseXMLintoArgs", + cmd_parse_xml_into_args, + NULL, + CMD_SCOPE_ANY, + "On, Off or OnlyArgs" + ), + { NULL } }; diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index b3976f9366..13334674b5 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -243,6 +243,10 @@ extern DSOLOCAL int *unicode_map_table; #define RULE_EXCEPTION_REMOVE_MSG 4 #define RULE_EXCEPTION_REMOVE_TAG 5 +#define MSC_XML_ARGS_OFF 0 +#define MSC_XML_ARGS_ON 1 +#define MSC_XML_ARGS_ONLYARGS 2 + #define NBSP 160 struct rule_exception { @@ -643,6 +647,7 @@ struct directory_config { /* xml */ int xml_external_entity; + int parse_xml_into_args; /* This will be used whenever ModSecurity will be ready * to ask the server for newer rules. diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 2b6681639e..68297e072e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -14,6 +14,108 @@ #include "msc_xml.h" +static void msc_xml_on_start_elementns( + void *ctx, + const xmlChar *localname, + const xmlChar *prefix, + const xmlChar *URI, + int nb_namespaces, + const xmlChar **namespaces, + int nb_attributes, + int nb_defaulted, + const xmlChar **attributes +) { + + // get the length of XML tag (localname) + size_t taglen = strlen((const char *)localname); + modsec_rec * msr = (modsec_rec *)ctx; + msc_xml_parser_state * xml_parser_state = msr->xml->xml_parser_state; + + // pathlen contains the concatenated strings of tags with '.' + // eg xml.root.level1.leaf + xml_parser_state->pathlen += (taglen + 1); + char *newpath = apr_pstrcat(msr->mp, xml_parser_state->currpath, ".", (char *)localname, NULL); + xml_parser_state->currpath = newpath; + + int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); + *new_stack_item = 0; + xml_parser_state->depth++; + + // if there is an item before the current one we set that has a child + if (xml_parser_state->depth > 1) { + int *parent_stack_item = &((int *)xml_parser_state->has_child_stack->elts)[xml_parser_state->has_child_stack->nelts - 2]; + *parent_stack_item = 1; + } + +} + +static void msc_xml_on_end_elementns( + void* ctx, + const xmlChar* localname, + const xmlChar* prefix, + const xmlChar* URI +) { + + size_t taglen = strlen((const char *)localname); + modsec_rec * msr = (modsec_rec *)ctx; + msc_xml_parser_state * xml_parser_state = msr->xml->xml_parser_state; + + // if the node is a leaf we add it as argument + // get the top item from the stack which tells this info + int * top_stack_item = apr_array_pop(xml_parser_state->has_child_stack); + if (*top_stack_item == 0) { + + 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 (XML): name \"%s\", value \"%s\"", + log_escape_ex(msr->mp, xml_parser_state->currpath, strlen(xml_parser_state->currpath)), + log_escape_ex(msr->mp, xml_parser_state->currval, strlen(xml_parser_state->currval))); + } + msr->msc_reqbody_error = 1; + msr->xml->xml_error = apr_psprintf(msr->mp, "More than %ld XML keys", msr->txcfg->arguments_limit); + xmlStopParser((xmlParserCtxtPtr)msr->xml->parsing_ctx_arg); + } + else { + + msc_arg * arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg)); + + arg->name = xml_parser_state->currpath; + arg->name_len = strlen(arg->name); + arg->value = xml_parser_state->currval; + arg->value_len = strlen(xml_parser_state->currval); + arg->value_origin_len = arg->value_len; + //arg->value_origin_offset = value-base_offset; + arg->origin = "XML"; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Adding XML argument '%s' with value '%s'", + xml_parser_state->currpath, xml_parser_state->currval); + } + + apr_table_addn(msr->arguments, + log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg); + } // end else + } // end top_stack_item == 0 + + // decrease the length of current path length - +1 because of the '\0' + xml_parser_state->pathlen -= (taglen + 1); + + // -1 need because we don't need the '.' + char * newpath = apr_pstrndup(msr->mp, xml_parser_state->currpath, xml_parser_state->pathlen - 1); + xml_parser_state->currpath = newpath; + + xml_parser_state->depth--; +} + +static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) { + + modsec_rec * msr = (modsec_rec *)ctx; + msc_xml_parser_state * xml_parser_state = msr->xml->xml_parser_state; + + xml_parser_state->currval = apr_pstrndup(msr->mp, (const char *)ch, len); +} + + static xmlParserInputBufferPtr xml_unload_external_entity(const char *URI, xmlCharEncoding enc) { return NULL; @@ -37,6 +139,33 @@ int xml_init(modsec_rec *msr, char **error_msg) { entity = xmlParserInputBufferCreateFilenameDefault(xml_unload_external_entity); } + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + + msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp, sizeof(xmlSAXHandler)); + memset(msr->xml->sax_handler, 0, sizeof(xmlSAXHandler)); + if (msr->xml->sax_handler == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to create SAX handler."); + return -1; + } + + msr->xml->sax_handler->initialized = XML_SAX2_MAGIC; + msr->xml->sax_handler->startElementNs = msc_xml_on_start_elementns; + msr->xml->sax_handler->endElementNs = msc_xml_on_end_elementns; + msr->xml->sax_handler->characters = msc_xml_on_characters; + + // set the parser state struct + msr->xml->xml_parser_state = apr_pcalloc(msr->mp, sizeof(msc_xml_parser_state)); + msr->xml->xml_parser_state->depth = 0; + msr->xml->xml_parser_state->pathlen = 4; // "xml\0" + msr->xml->xml_parser_state->currpath = apr_pstrdup(msr->mp, "xml"); + msr->xml->xml_parser_state->currval = NULL; + msr->xml->xml_parser_state->currpathbufflen = 4; + // initialize the stack with item of 10 + // this will store the information about nodes + // 10 is just an initial value, it can be automatically incremented + msr->xml->xml_parser_state->has_child_stack = apr_array_make(msr->mp, 10, sizeof(int)); + } + return 1; } @@ -68,7 +197,7 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char * enable us to pass it the first chunk of data so that * it can attempt to auto-detect the encoding. */ - if (msr->xml->parsing_ctx == NULL) { + if (msr->xml->parsing_ctx == NULL && msr->xml->parsing_ctx_arg == NULL) { /* First invocation. */ @@ -86,18 +215,50 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char */ - msr->xml->parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL, buf, size, "body.xml"); - if (msr->xml->parsing_ctx == NULL) { - *error_msg = apr_psprintf(msr->mp, "XML: Failed to create parsing context."); - return -1; + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { + msr->xml->parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL, buf, size, "body.xml"); + if (msr->xml->parsing_ctx == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to create parsing context."); + return -1; + } + } + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + msr->xml->parsing_ctx_arg = xmlCreatePushParserCtxt( + msr->xml->sax_handler, + msr, + buf, + size, + NULL); + if (msr->xml->parsing_ctx_arg == NULL) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed to create parsing context for ARGS."); + return -1; + } } } else { /* Not a first invocation. */ + msr_log(msr, 4, "XML: Continue parsing."); + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { + xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0); + if (msr->xml->parsing_ctx->wellFormed != 1) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + return -1; + } + } - xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0); - if (msr->xml->parsing_ctx->wellFormed != 1) { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + if (xmlParseChunk(msr->xml->parsing_ctx_arg, buf, size, 0) != 0) { + if (msr->xml->xml_error) { + *error_msg = msr->xml->xml_error; + } + else { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document for ARGS."); + } + return -1; + } + } + if (msr->xml->xml_error) { + *error_msg = msr->xml->xml_error; return -1; } } @@ -114,23 +275,42 @@ int xml_complete(modsec_rec *msr, char **error_msg) { *error_msg = NULL; /* Only if we have a context, meaning we've done some work. */ - if (msr->xml->parsing_ctx != NULL) { - /* This is how we signalise the end of parsing to libxml. */ - xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1); + if (msr->xml->parsing_ctx != NULL || msr->xml->parsing_ctx_arg != NULL) { + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { + /* This is how we signalise the end of parsing to libxml. */ + xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1); - /* Preserve the results for our reference. */ - msr->xml->well_formed = msr->xml->parsing_ctx->wellFormed; - msr->xml->doc = msr->xml->parsing_ctx->myDoc; + /* Preserve the results for our reference. */ + msr->xml->well_formed = msr->xml->parsing_ctx->wellFormed; + msr->xml->doc = msr->xml->parsing_ctx->myDoc; - /* Clean up everything else. */ - xmlFreeParserCtxt(msr->xml->parsing_ctx); - msr->xml->parsing_ctx = NULL; - msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed); + /* Clean up everything else. */ + xmlFreeParserCtxt(msr->xml->parsing_ctx); + msr->xml->parsing_ctx = NULL; + msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed); - if (msr->xml->well_formed != 1) { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); - return -1; + if (msr->xml->well_formed != 1) { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + return -1; + } + } + + if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + if (xmlParseChunk(msr->xml->parsing_ctx_arg, NULL, 0, 1) != 0) { + if (msr->xml->xml_error) { + *error_msg = msr->xml->xml_error; + } + else { + *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document for ARGS."); + } + xmlFreeParserCtxt(msr->xml->parsing_ctx_arg); + msr->xml->parsing_ctx_arg = NULL; + return -1; + } + xmlFreeParserCtxt(msr->xml->parsing_ctx_arg); + msr->xml->parsing_ctx_arg = NULL; } + } return 1; @@ -152,6 +332,15 @@ apr_status_t xml_cleanup(modsec_rec *msr) { xmlFreeParserCtxt(msr->xml->parsing_ctx); msr->xml->parsing_ctx = NULL; } + if (msr->xml->parsing_ctx_arg != NULL) { + + if (msr->xml->parsing_ctx_arg->myDoc) { + xmlFreeDoc(msr->xml->parsing_ctx_arg->myDoc); + } + + xmlFreeParserCtxt(msr->xml->parsing_ctx_arg); + msr->xml->parsing_ctx_arg = NULL; + } if (msr->xml->doc != NULL) { xmlFreeDoc(msr->xml->doc); msr->xml->doc = NULL; diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h index f239068672..86910c4379 100644 --- a/apache2/msc_xml.h +++ b/apache2/msc_xml.h @@ -20,15 +20,36 @@ typedef struct xml_data xml_data; #include "modsecurity.h" #include #include +#include /* Structures */ +struct msc_xml_parser_state { + apr_array_header_t * has_child_stack; + unsigned int depth; + unsigned int pathlen; + char * currpath; + char * currval; + size_t currpathbufflen; + apr_pool_t * mp; +}; + +typedef struct msc_xml_parser_state msc_xml_parser_state; + struct xml_data { xmlSAXHandler *sax_handler; xmlParserCtxtPtr parsing_ctx; xmlDocPtr doc; unsigned int well_formed; + + /* error reporting and XML array flag */ + char *xml_error; + + /* another parser context for arguments */ + xmlParserCtxtPtr parsing_ctx_arg; + /* parser state for SAX parser */ + msc_xml_parser_state *xml_parser_state; }; /* Functions */ diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 510d6988d4..ef5d83104d 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1022,6 +1022,13 @@ static char *msre_action_ctl_validate(msre_engine *engine, apr_pool_t *mp, msre_ if (strcasecmp(value, "on") == 0) return NULL; if (strcasecmp(value, "off") == 0) return NULL; return apr_psprintf(mp, "Invalid setting for ctl name HashEngine: %s", value); + } + else + if (strcasecmp(name, "parseXMLintoArgs") == 0) { + if (strcasecmp(value, "on") == 0) return NULL; + if (strcasecmp(value, "off") == 0) return NULL; + if (strcasecmp(value, "onlyargs") == 0) return NULL; + return apr_psprintf(mp, "Invalid setting for ctl name parseXMLintoArgs: %s", value); } else { return apr_psprintf(mp, "Invalid ctl name setting: %s", name); } @@ -1377,6 +1384,29 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, return -1; } apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); + return 1; + } else + if (strcasecmp(name, "parseXMLintoArgs") == 0) { + + if (strcasecmp(value, "on") == 0) { + msr->txcfg->parse_xml_into_args = MSC_XML_ARGS_ON; + msr->usercfg->parse_xml_into_args = MSC_XML_ARGS_ON; + } + else + if (strcasecmp(value, "off") == 0) { + msr->txcfg->parse_xml_into_args = MSC_XML_ARGS_OFF; + msr->usercfg->parse_xml_into_args = MSC_XML_ARGS_OFF; + } + else + if (strcasecmp(value, "onlyargs") == 0) { + msr->txcfg->parse_xml_into_args = MSC_XML_ARGS_ONLYARGS; + msr->usercfg->parse_xml_into_args = MSC_XML_ARGS_ONLYARGS; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Ctl: Set parseXmlIntoArgs to %s.", value); + } + return 1; } From 1953e372170394d042d0291b545c8b46b0bf05f2 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 20 Apr 2025 21:44:47 +0200 Subject: [PATCH 339/470] Add nullptr check conditions --- apache2/msc_xml.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 68297e072e..a51737f3bd 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -238,7 +238,8 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char /* Not a first invocation. */ msr_log(msr, 4, "XML: Continue parsing."); - if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { + if (msr->xml->parsing_ctx != NULL && + msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0); if (msr->xml->parsing_ctx->wellFormed != 1) { *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); @@ -246,7 +247,8 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char } } - if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + if (msr->xml->parsing_ctx_arg != NULL && + msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { if (xmlParseChunk(msr->xml->parsing_ctx_arg, buf, size, 0) != 0) { if (msr->xml->xml_error) { *error_msg = msr->xml->xml_error; @@ -276,7 +278,8 @@ int xml_complete(modsec_rec *msr, char **error_msg) { /* Only if we have a context, meaning we've done some work. */ if (msr->xml->parsing_ctx != NULL || msr->xml->parsing_ctx_arg != NULL) { - if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { + if (msr->xml->parsing_ctx != NULL && + msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { /* This is how we signalise the end of parsing to libxml. */ xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1); @@ -295,7 +298,8 @@ int xml_complete(modsec_rec *msr, char **error_msg) { } } - if (msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { + if (msr->xml->parsing_ctx_arg != NULL && + msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_OFF) { if (xmlParseChunk(msr->xml->parsing_ctx_arg, NULL, 0, 1) != 0) { if (msr->xml->xml_error) { *error_msg = msr->xml->xml_error; From c24ad689beb433b8bfdf3a1f05d3fc77d272c76d Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:01:07 +0200 Subject: [PATCH 340/470] Remove unnecessary comment. 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/msc_xml.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index a51737f3bd..324e835b1e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -84,7 +84,6 @@ static void msc_xml_on_end_elementns( arg->value = xml_parser_state->currval; arg->value_len = strlen(xml_parser_state->currval); arg->value_origin_len = arg->value_len; - //arg->value_origin_offset = value-base_offset; arg->origin = "XML"; if (msr->txcfg->debuglog_level >= 9) { From 78ca32f280d1d290428eb10a0246553b15e22993 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:02:07 +0200 Subject: [PATCH 341/470] Format comment 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/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 324e835b1e..d3d420ab0e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -99,7 +99,7 @@ static void msc_xml_on_end_elementns( // decrease the length of current path length - +1 because of the '\0' xml_parser_state->pathlen -= (taglen + 1); - // -1 need because we don't need the '.' + // -1 is needed because we don't need the last '.' char * newpath = apr_pstrndup(msr->mp, xml_parser_state->currpath, xml_parser_state->pathlen - 1); xml_parser_state->currpath = newpath; From 055aec7bf634ec13a22944d8531136ea63730709 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:08:02 +0200 Subject: [PATCH 342/470] Comment clarification 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/msc_xml.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h index 86910c4379..3d23c60db9 100644 --- a/apache2/msc_xml.h +++ b/apache2/msc_xml.h @@ -46,7 +46,7 @@ struct xml_data { /* error reporting and XML array flag */ char *xml_error; - /* another parser context for arguments */ + /* additional parser context for arguments */ xmlParserCtxtPtr parsing_ctx_arg; /* parser state for SAX parser */ msc_xml_parser_state *xml_parser_state; From 3829d65792e412fdce913f8550d242375ad83614 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:08:40 +0200 Subject: [PATCH 343/470] Debug message clarification Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- 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 1739af280b..19d04f989a 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -3719,7 +3719,7 @@ static const char *cmd_parse_xml_into_args(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, "cmd_hash_engine: _dcfg is NULL"); + ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_parse_xml_into_args: _dcfg is NULL"); return NULL; } directory_config *dcfg = (directory_config *)_dcfg; From 321c554965270a2cae536f7fe8fe8c2887124d14 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:25:05 +0200 Subject: [PATCH 344/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index d3d420ab0e..4c64b5d9f0 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -304,7 +304,7 @@ int xml_complete(modsec_rec *msr, char **error_msg) { *error_msg = msr->xml->xml_error; } else { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document for ARGS."); + *error_msg = apr_psprintf(msr->mp, "XML: Failed to parse document for ARGS."); } xmlFreeParserCtxt(msr->xml->parsing_ctx_arg); msr->xml->parsing_ctx_arg = NULL; From c3ab480979ca44b083474ccac3f4c4bd5c004ee9 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:31:43 +0200 Subject: [PATCH 345/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 4c64b5d9f0..a24f5b77f6 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -241,7 +241,7 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0); if (msr->xml->parsing_ctx->wellFormed != 1) { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + *error_msg = apr_psprintf(msr->mp, "XML: Failed to parse document."); return -1; } } From c19f90195cd84eca3d4b5dc6299e42c3ffbd5a90 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:32:25 +0200 Subject: [PATCH 346/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- 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 ef5d83104d..cf28b3f6a5 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1024,7 +1024,7 @@ static char *msre_action_ctl_validate(msre_engine *engine, apr_pool_t *mp, msre_ return apr_psprintf(mp, "Invalid setting for ctl name HashEngine: %s", value); } else - if (strcasecmp(name, "parseXMLintoArgs") == 0) { + if (strcasecmp(name, "parseXmlIntoArgs") == 0) { if (strcasecmp(value, "on") == 0) return NULL; if (strcasecmp(value, "off") == 0) return NULL; if (strcasecmp(value, "onlyargs") == 0) return NULL; From bfe8047c04079382d9f65c2fabe5ebb4989c2824 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:32:55 +0200 Subject: [PATCH 347/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- 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 cf28b3f6a5..59150d57e9 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1028,7 +1028,7 @@ static char *msre_action_ctl_validate(msre_engine *engine, apr_pool_t *mp, msre_ if (strcasecmp(value, "on") == 0) return NULL; if (strcasecmp(value, "off") == 0) return NULL; if (strcasecmp(value, "onlyargs") == 0) return NULL; - return apr_psprintf(mp, "Invalid setting for ctl name parseXMLintoArgs: %s", value); + return apr_psprintf(mp, "Invalid setting for ctl name parseXmlIntoArgs: %s", value); } else { return apr_psprintf(mp, "Invalid ctl name setting: %s", name); } From 21d71bb603c60562d48e86c604524527244bd768 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:33:12 +0200 Subject: [PATCH 348/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- 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 59150d57e9..a028e42a81 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1386,7 +1386,7 @@ static apr_status_t msre_action_ctl_execute(modsec_rec *msr, apr_pool_t *mptmp, apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re); return 1; } else - if (strcasecmp(name, "parseXMLintoArgs") == 0) { + if (strcasecmp(name, "parseXmlIntoArgs") == 0) { if (strcasecmp(value, "on") == 0) { msr->txcfg->parse_xml_into_args = MSC_XML_ARGS_ON; From f1ecdb1cf722227888b8ebc74926951c7f9acb8f Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:35:44 +0200 Subject: [PATCH 349/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index a24f5b77f6..7e0077bc3f 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -253,7 +253,7 @@ int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char *error_msg = msr->xml->xml_error; } else { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document for ARGS."); + *error_msg = apr_psprintf(msr->mp, "XML: Failed to parse document for ARGS."); } return -1; } From b5188237f4d24560320077c00dcfab2e99a72ac0 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:36:32 +0200 Subject: [PATCH 350/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 7e0077bc3f..26c811ec6b 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -279,7 +279,7 @@ int xml_complete(modsec_rec *msr, char **error_msg) { if (msr->xml->parsing_ctx != NULL || msr->xml->parsing_ctx_arg != NULL) { if (msr->xml->parsing_ctx != NULL && msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) { - /* This is how we signalise the end of parsing to libxml. */ + /* This is how we signal the end of parsing to libxml. */ xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1); /* Preserve the results for our reference. */ From ed24e70c5829f344b853a25e4643a076bf2e9f41 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 26 Apr 2025 20:37:00 +0200 Subject: [PATCH 351/470] Typo fix. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 26c811ec6b..1e415bd17e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -292,7 +292,7 @@ int xml_complete(modsec_rec *msr, char **error_msg) { msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed); if (msr->xml->well_formed != 1) { - *error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document."); + *error_msg = apr_psprintf(msr->mp, "XML: Failed to parse document."); return -1; } } From c11bd6c6f29768990b38e265929056af181b8e7d Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 27 Apr 2025 11:25:59 +0200 Subject: [PATCH 352/470] Fix retval logic explanation --- apache2/apache2_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 19d04f989a..8e9d50d5e1 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -3709,8 +3709,8 @@ static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, * \param _dcfg Pointer to directory configuration * \param p1 Pointer to configuration option * -* \retval NULL On failure -* \retval apr_psprintf On Success +* \retval NULL On Success +* \retval apr_psprintf On error */ static const char *cmd_parse_xml_into_args(cmd_parms *cmd, void *_dcfg, const char *p1) { From bd451080245f1bfd600feb978256b76e36d151f7 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 27 Apr 2025 11:28:18 +0200 Subject: [PATCH 353/470] Fix error message explanation. Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 1e415bd17e..23cc364ea8 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -72,7 +72,7 @@ static void msc_xml_on_end_elementns( log_escape_ex(msr->mp, xml_parser_state->currval, strlen(xml_parser_state->currval))); } msr->msc_reqbody_error = 1; - msr->xml->xml_error = apr_psprintf(msr->mp, "More than %ld XML keys", msr->txcfg->arguments_limit); + msr->xml->xml_error = apr_psprintf(msr->mp, "More than %ld ARGS (GET + XML)", msr->txcfg->arguments_limit); xmlStopParser((xmlParserCtxtPtr)msr->xml->parsing_ctx_arg); } else { From 4c043a0889188dcc8b79b54973a50aa42c8f8e6e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Apr 2025 21:05:18 +0200 Subject: [PATCH 354/470] Change directive format to strict camel case --- apache2/apache2_config.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index 8e9d50d5e1..a831e375ee 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -3703,7 +3703,7 @@ static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, } /** -* \brief Add SecParseXMLIntoArgs configuration option +* \brief Add SecParseXmlIntoArgs configuration option * * \param cmd Pointer to configuration data * \param _dcfg Pointer to directory configuration @@ -3726,7 +3726,7 @@ static const char *cmd_parse_xml_into_args(cmd_parms *cmd, void *_dcfg, const ch if (strcasecmp(p1, "on") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_ON; } else if (strcasecmp(p1, "off") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_OFF; } else if (strcasecmp(p1, "onlyargs") == 0) { dcfg->parse_xml_into_args = MSC_XML_ARGS_ONLYARGS; } - else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecParseXMLIntoArgs: %s", p1); + else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecParseXmlIntoArgs: %s", p1); return NULL; } @@ -4499,7 +4499,7 @@ const command_rec module_directives[] = { ), AP_INIT_TAKE1 ( - "SecParseXMLintoArgs", + "SecParseXmlIntoArgs", cmd_parse_xml_into_args, NULL, CMD_SCOPE_ANY, From 19b7e98fb6f27d98baf7a4061d4cdabe708fb1b2 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Apr 2025 21:12:32 +0200 Subject: [PATCH 355/470] Change node value's parsing to concatenate instead of duplicate it every time --- apache2/msc_xml.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 23cc364ea8..4413b17af6 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -40,6 +40,10 @@ static void msc_xml_on_start_elementns( int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); *new_stack_item = 0; xml_parser_state->depth++; + // set null to the current value + // this is necessary because if there is any text between the tags (new line, etc) + // it will be added to the current value + xml_parser_state->currval = NULL; // if there is an item before the current one we set that has a child if (xml_parser_state->depth > 1) { @@ -104,6 +108,7 @@ static void msc_xml_on_end_elementns( xml_parser_state->currpath = newpath; xml_parser_state->depth--; + xml_parser_state->currval = NULL; } static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) { @@ -111,7 +116,19 @@ static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) { modsec_rec * msr = (modsec_rec *)ctx; msc_xml_parser_state * xml_parser_state = msr->xml->xml_parser_state; - xml_parser_state->currval = apr_pstrndup(msr->mp, (const char *)ch, len); + // libxml2 SAX parser will call this function multiple times + // during the parsing of a single node, if the value has multibyte + // characters, so we need to concatenate the values + xml_parser_state->currval = apr_pstrcat(msr->mp, + ((xml_parser_state->currval != NULL) ? xml_parser_state->currval : ""), + apr_pstrndup(msr->mp, (const char *)ch, len), + NULL); + // check if the memory allocation was successful + if (xml_parser_state->currval == NULL) { + msr->xml->xml_error = apr_psprintf(msr->mp, "Failed to allocate memory for XML value."); + xmlStopParser((xmlParserCtxtPtr)msr->xml->parsing_ctx_arg); + } + } From 87cbf9ea2e66c0e7a5336fc9118c9b83d8c9504e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 30 Apr 2025 08:50:55 +0200 Subject: [PATCH 356/470] Update explanation Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 4413b17af6..8b0fa766e4 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -40,7 +40,7 @@ static void msc_xml_on_start_elementns( int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); *new_stack_item = 0; xml_parser_state->depth++; - // set null to the current value + // set the current value to null // this is necessary because if there is any text between the tags (new line, etc) // it will be added to the current value xml_parser_state->currval = NULL; From bc500582a2658341262e6ba0f6de721d50667f28 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 10:13:29 +0200 Subject: [PATCH 357/470] fix: add msc_fullinfo() to check JIT compilation --- apache2/re_operators.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index ca61c7adc8..33d01b0648 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -725,6 +725,10 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_JIT #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -831,6 +835,10 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -1002,6 +1010,10 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_JIT #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -1100,6 +1112,10 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -2991,6 +3007,10 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -3330,6 +3350,10 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -3655,6 +3679,10 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 rc = regex->jit_compile_rc; + if (rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); + jit = (jit > 0) ? 1 : 0; + } #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif From d26a1d0d2c1a9f97b8f5d8948498510e4e267361 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 11:12:58 +0200 Subject: [PATCH 358/470] chore: remove unnecessary @LIBXML2_CFLAGS@ from linker flags --- apache2/Makefile.am | 9 --------- 1 file changed, 9 deletions(-) diff --git a/apache2/Makefile.am b/apache2/Makefile.am index 9af9633a30..50246829bd 100644 --- a/apache2/Makefile.am +++ b/apache2/Makefile.am @@ -57,7 +57,6 @@ mod_security2_la_CPPFLAGS = @APR_CPPFLAGS@ \ mod_security2_la_LIBADD = @APR_LDADD@ \ @APU_LDADD@ \ @CURL_LDADD@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDADD@ \ @LUA_LDADD@ \ @PCRE_LDADD@ \ @@ -70,7 +69,6 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -85,7 +83,6 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -100,7 +97,6 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -115,7 +111,6 @@ mod_security2_la_LDFLAGS = -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -130,7 +125,6 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -145,7 +139,6 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -160,7 +153,6 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ @@ -175,7 +167,6 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ @APU_LDFLAGS@ \ @APXS_LDFLAGS@ \ @CURL_LDFLAGS@ \ - @LIBXML2_CFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ From eaba30f1c75cc3eb91478e614bf6e5f27fc65fa0 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 11:44:42 +0200 Subject: [PATCH 359/470] fix: add PCRE2 capability to standalone module --- standalone/regex.c | 399 +++++++++++++++++++++++++++------------------ 1 file changed, 237 insertions(+), 162 deletions(-) diff --git a/standalone/regex.c b/standalone/regex.c index 495a18eb97..b70c031dcc 100644 --- a/standalone/regex.c +++ b/standalone/regex.c @@ -1,162 +1,237 @@ -/* -* 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 - -#include "http_core.h" -#include "http_request.h" - -#include "modsecurity.h" -#include "apache2.h" -#include "http_main.h" -#include "http_connection.h" - -#include "apr_optional.h" -#include "mod_log_config.h" - -#include "msc_logging.h" -#include "msc_util.h" - -#include "ap_mpm.h" -#include "scoreboard.h" - -#include "apr_version.h" - -#include "apr_lib.h" -#include "ap_config.h" -#include "http_config.h" - - -static apr_status_t regex_cleanup(void *preg) -{ - ap_regfree((ap_regex_t *) preg); - return APR_SUCCESS; -} - -AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, - int cflags) -{ - ap_regex_t *preg = apr_palloc(p, sizeof *preg); - - if (ap_regcomp(preg, pattern, cflags)) { - return NULL; - } - - apr_pool_cleanup_register(p, (void *) preg, regex_cleanup, - apr_pool_cleanup_null); - - return preg; -} - -AP_DECLARE(void) ap_regfree(ap_regex_t *preg) -{ -(pcre_free)(preg->re_pcre); -} - -AP_DECLARE(int) ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags) -{ -const char *errorptr; -int erroffset; -int options = 0; -int nsub = 0; - -if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS; -if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE; - -preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL); -preg->re_erroffset = erroffset; - -if (preg->re_pcre == NULL) return AP_REG_INVARG; - -pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &nsub); -preg->re_nsub = nsub; -return 0; -} - -#ifndef POSIX_MALLOC_THRESHOLD -#define POSIX_MALLOC_THRESHOLD (10) -#endif - -AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string, - apr_size_t nmatch, ap_regmatch_t pmatch[], - int eflags) -{ -int rc; -int options = 0; -int *ovector = NULL; -int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; -int allocated_ovector = 0; - -if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL; -if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL; - -((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */ - -if (nmatch > 0) - { - if (nmatch <= POSIX_MALLOC_THRESHOLD) - { - ovector = &(small_ovector[0]); - } - else - { - ovector = (int *)malloc(sizeof(int) * nmatch * 3); - if (ovector == NULL) return AP_REG_ESPACE; - allocated_ovector = 1; - } - } - -rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string), - 0, options, ovector, nmatch * 3); - -if (rc == 0) rc = nmatch; /* All captured slots were filled in */ - -if (rc >= 0) - { - apr_size_t i; - for (i = 0; i < (apr_size_t)rc; i++) - { - pmatch[i].rm_so = ovector[i*2]; - pmatch[i].rm_eo = ovector[i*2+1]; - } - if (allocated_ovector) free(ovector); - for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; - return 0; - } - -else - { - if (allocated_ovector) free(ovector); - switch(rc) - { - case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH; - case PCRE_ERROR_NULL: return AP_REG_INVARG; - case PCRE_ERROR_BADOPTION: return AP_REG_INVARG; - case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG; - case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT; - case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE; -#ifdef PCRE_ERROR_MATCHLIMIT - case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE; -#endif -#ifdef PCRE_ERROR_BADUTF8 - case PCRE_ERROR_BADUTF8: return AP_REG_INVARG; -#endif -#ifdef PCRE_ERROR_BADUTF8_OFFSET - case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG; -#endif - default: return AP_REG_ASSERT; - } - } -} - +/* +* 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 + +#include "http_core.h" +#include "http_request.h" + +#include "modsecurity.h" +#include "apache2.h" +#include "http_main.h" +#include "http_connection.h" + +#include "apr_optional.h" +#include "mod_log_config.h" + +#include "msc_logging.h" +#include "msc_util.h" + +#include "ap_mpm.h" +#include "scoreboard.h" + +#include "apr_version.h" + +#include "apr_lib.h" +#include "ap_config.h" +#include "http_config.h" + + +static apr_status_t regex_cleanup(void *preg) +{ + ap_regfree((ap_regex_t *) preg); + return APR_SUCCESS; +} + +AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, + int cflags) +{ + ap_regex_t *preg = apr_palloc(p, sizeof *preg); + + if (ap_regcomp(preg, pattern, cflags)) { + return NULL; + } + + apr_pool_cleanup_register(p, (void *) preg, regex_cleanup, + apr_pool_cleanup_null); + + return preg; +} + +AP_DECLARE(void) ap_regfree(ap_regex_t *preg) +{ +#ifdef WITH_PCRE2 +(pcre2_code_free)(preg->re_pcre); +#else +(pcre_free)(preg->re_pcre); +#endif +} + +AP_DECLARE(int) ap_regcomp(ap_regex_t *preg, const char *pattern, int cflags) +{ +const char *errorptr; +int erroffset; +int options = 0; +int nsub = 0; + +#ifdef WITH_PCRE2 +if ((cflags & AP_REG_ICASE) != 0) options |= PCRE2_CASELESS; +if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE2_MULTILINE; +int error_number = 0; +PCRE2_SIZE error_offset = 0; +PCRE2_SPTR pcre2_pattern = (PCRE2_SPTR)pattern; + +preg->re_pcre = pcre2_compile(pcre2_pattern, PCRE2_ZERO_TERMINATED, + options, &error_number, &error_offset, NULL); +preg->re_erroffset = error_offset; + +if (preg->re_pcre == NULL) return AP_REG_INVARG; + +pcre2_pattern_info((const pcre2_code *)preg->re_pcre, PCRE2_INFO_CAPTURECOUNT, &nsub); +preg->re_nsub = nsub; + +#else +if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS; +if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE; + +preg->re_pcre = pcre_compile(pattern, options, &errorptr, &erroffset, NULL); +preg->re_erroffset = erroffset; + +if (preg->re_pcre == NULL) return AP_REG_INVARG; + +pcre_fullinfo((const pcre *)preg->re_pcre, NULL, PCRE_INFO_CAPTURECOUNT, &nsub); +preg->re_nsub = nsub; +#endif // end of WITH_PCRE +return 0; +} + +#ifndef POSIX_MALLOC_THRESHOLD +#define POSIX_MALLOC_THRESHOLD (10) +#endif + +AP_DECLARE(int) ap_regexec(const ap_regex_t *preg, const char *string, + apr_size_t nmatch, ap_regmatch_t pmatch[], + int eflags) +{ +int rc; +int options = 0; +int *ovector = NULL; +int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; +int allocated_ovector = 0; + +#ifdef WITH_PCRE2 +if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE2_NOTBOL; +if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE2_NOTEOL; +#else +if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE_NOTBOL; +if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE_NOTEOL; +#endif + +((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */ + +if (nmatch > 0) + { + if (nmatch <= POSIX_MALLOC_THRESHOLD) + { + ovector = &(small_ovector[0]); + } + else + { + ovector = (int *)malloc(sizeof(int) * nmatch * 3); + if (ovector == NULL) return AP_REG_ESPACE; + allocated_ovector = 1; + } + } + +#ifdef WITH_PCRE2 +{ + PCRE2_SPTR pcre2_s; + int pcre2_ret; + pcre2_match_data *match_data; + PCRE2_SIZE *pcre2_ovector = NULL; + + pcre2_s = (PCRE2_SPTR)string; + match_data = pcre2_match_data_create_from_pattern(preg->re_pcre, NULL); + pcre2_match_context *match_context = pcre2_match_context_create(NULL); + + pcre2_ret = pcre2_match((const pcre2_code *)preg->re_pcre, pcre2_s, (int)strlen(string), + 0, (uint32_t)options, match_data, match_context); + + if (match_data != NULL) { + pcre2_ovector = pcre2_get_ovector_pointer(match_data); + if (pcre2_ovector != NULL) { + for (int i = 0; ((i < pcre2_ret) && ((i*2) <= nmatch * 3)); i++) { + if ((i*2) < nmatch * 3) { + ovector[2*i] = pcre2_ovector[2*i]; + ovector[2*i+1] = pcre2_ovector[2*i+1]; + } + } + } + pcre2_match_data_free(match_data); + pcre2_match_context_free(match_context); + } +} +#else +rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string), + 0, options, ovector, nmatch * 3); +#endif + +if (rc == 0) rc = nmatch; /* All captured slots were filled in */ + +if (rc >= 0) + { + apr_size_t i; + for (i = 0; i < (apr_size_t)rc; i++) + { + pmatch[i].rm_so = ovector[i*2]; + pmatch[i].rm_eo = ovector[i*2+1]; + } + if (allocated_ovector) free(ovector); + for (; i < nmatch; i++) pmatch[i].rm_so = pmatch[i].rm_eo = -1; + return 0; + } + +else + { + if (allocated_ovector) free(ovector); + switch(rc) + { +#ifdef WITH_PCRE2 + case PCRE2_ERROR_NOMATCH: return AP_REG_NOMATCH; + case PCRE2_ERROR_NULL: return AP_REG_INVARG; + case PCRE2_ERROR_BADOPTION: return AP_REG_INVARG; + case PCRE2_ERROR_BADMAGIC: return AP_REG_INVARG; + // case PCRE2_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT; not defined in PCRE2 + case PCRE2_ERROR_NOMEMORY: return AP_REG_ESPACE; +#ifdef PCRE2_ERROR_MATCHLIMIT + case PCRE2_ERROR_MATCHLIMIT: return AP_REG_ESPACE; +#endif +#ifdef PCRE2_ERROR_BADUTF8 + case PCRE2_ERROR_BADUTF8: return AP_REG_INVARG; +#endif +#ifdef PCRE2_ERROR_BADUTF8_OFFSET + case PCRE2_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG; +#endif +#else // with old PCRE + case PCRE_ERROR_NOMATCH: return AP_REG_NOMATCH; + case PCRE_ERROR_NULL: return AP_REG_INVARG; + case PCRE_ERROR_BADOPTION: return AP_REG_INVARG; + case PCRE_ERROR_BADMAGIC: return AP_REG_INVARG; + case PCRE_ERROR_UNKNOWN_NODE: return AP_REG_ASSERT; + case PCRE_ERROR_NOMEMORY: return AP_REG_ESPACE; +#ifdef PCRE_ERROR_MATCHLIMIT + case PCRE_ERROR_MATCHLIMIT: return AP_REG_ESPACE; +#endif +#ifdef PCRE_ERROR_BADUTF8 + case PCRE_ERROR_BADUTF8: return AP_REG_INVARG; +#endif +#ifdef PCRE_ERROR_BADUTF8_OFFSET + case PCRE_ERROR_BADUTF8_OFFSET: return AP_REG_INVARG; +#endif +#endif // end of WITH_PCRE + default: return AP_REG_ASSERT; + } + } +} + From 1549132fb54551d14c2494175d8c27329f36ba32 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 13:08:29 +0200 Subject: [PATCH 360/470] chore: refacorize setting of JIT related variables --- apache2/re_operators.c | 57 ++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 35 deletions(-) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 33d01b0648..b3a4305423 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -37,6 +37,21 @@ #include "libinjection/libinjection.h" +/** + * @brief Set the JIT compile return code and JIT compile status. + * \param regex regex structure + * \param rc return code of the JIT compile + * \param jit JIT compile status + * \return void + */ +static void msc_op_set_jitrc(msc_regex_t *regex, int *rc, int *jit) { + *rc = regex->jit_compile_rc; + if (*rc == 0) { + msc_fullinfo(regex, PCRE2_INFO_JITSIZE, jit); + *jit = (*jit > 0) ? 1 : 0; + } + return; +} /** * @@ -724,11 +739,7 @@ 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; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -834,11 +845,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 - rc = regex->jit_compile_rc; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -1009,11 +1016,7 @@ 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; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -1111,11 +1114,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 - rc = regex->jit_compile_rc; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -3006,11 +3005,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 - rc = regex->jit_compile_rc; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -3349,11 +3344,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 - rc = regex->jit_compile_rc; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif @@ -3678,11 +3669,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var #ifdef WITH_PCRE_JIT if (msr->txcfg->debuglog_level >= 4) { #ifdef WITH_PCRE2 - rc = regex->jit_compile_rc; - if (rc == 0) { - msc_fullinfo(regex, PCRE2_INFO_JITSIZE, &jit); - jit = (jit > 0) ? 1 : 0; - } + msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); #endif From 5f3537ec2137c1aec4ddb07c67a2577b6e3acf94 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 13:13:55 +0200 Subject: [PATCH 361/470] add copilation condition to avoid build error in case of old PCRE --- apache2/re_operators.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b3a4305423..dc1de84b94 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -37,6 +37,7 @@ #include "libinjection/libinjection.h" +#ifdef WITH_PCRE2 /** * @brief Set the JIT compile return code and JIT compile status. * \param regex regex structure @@ -52,6 +53,7 @@ static void msc_op_set_jitrc(msc_regex_t *regex, int *rc, int *jit) { } return; } +#endif /** * From 33d0f5069865c1e4d647ab7ce54bfeec0ee28d1f Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 13:21:29 +0200 Subject: [PATCH 362/470] Add all compilation conditions to the new function --- apache2/re_operators.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index dc1de84b94..3e50191ed4 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -37,6 +37,8 @@ #include "libinjection/libinjection.h" +#ifdef WITH_PCRE_STUDY +#ifdef WITH_PCRE_JIT #ifdef WITH_PCRE2 /** * @brief Set the JIT compile return code and JIT compile status. @@ -54,6 +56,8 @@ static void msc_op_set_jitrc(msc_regex_t *regex, int *rc, int *jit) { return; } #endif +#endif +#endif /** * From c2216b2616b124c58902b584fcf458ffbc4e2e06 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 13:34:56 +0200 Subject: [PATCH 363/470] fix: set 'rc' value for fill ovector correctly --- standalone/regex.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/standalone/regex.c b/standalone/regex.c index b70c031dcc..3a68a09442 100644 --- a/standalone/regex.c +++ b/standalone/regex.c @@ -171,6 +171,11 @@ if (nmatch > 0) pcre2_match_data_free(match_data); pcre2_match_context_free(match_context); } + /* + pcre2_match() returns one more than the highest numbered capturing pair + that has been set (for example, 1 if there are no captures) - see pcre2_match's manual + */ + rc = pcre2_ret - 1; } #else rc = pcre_exec((const pcre *)preg->re_pcre, NULL, string, (int)strlen(string), From e978a30102eb7cb9d8cc4960393ce86a734be4b1 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 20:36:51 +0200 Subject: [PATCH 364/470] Add comment to explain the if-else-endif statements --- standalone/regex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/standalone/regex.c b/standalone/regex.c index 3a68a09442..acd46a1593 100644 --- a/standalone/regex.c +++ b/standalone/regex.c @@ -91,7 +91,7 @@ if (preg->re_pcre == NULL) return AP_REG_INVARG; pcre2_pattern_info((const pcre2_code *)preg->re_pcre, PCRE2_INFO_CAPTURECOUNT, &nsub); preg->re_nsub = nsub; -#else +#else // otherwise use PCRE if ((cflags & AP_REG_ICASE) != 0) options |= PCRE_CASELESS; if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE_MULTILINE; From 302fce71e84796b589460e116a797a902474f310 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 10 May 2025 21:29:17 +0200 Subject: [PATCH 365/470] fix: 'make test' is able to run again --- tests/Makefile.am | 10 +++++++--- tests/msc_test.c | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8ffc3bb3db..130bdba398 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -40,16 +40,18 @@ msc_test_CFLAGS = @APR_CFLAGS@ \ @LUA_CFLAGS@ \ @MODSEC_EXTRA_CFLAGS@ \ @PCRE_CFLAGS@ \ + @PCRE2_CFLAGS@ \ @YAJL_CFLAGS@ \ @SSDEEP_CFLAGS@ - + msc_test_CPPFLAGS = -I$(top_srcdir)/apache2 \ @APR_CPPFLAGS@ \ @CURL_CPPFLAGS@ \ @LIBXML2_CFLAGS@ \ @LIBXML2_CPPFLAGS@ \ - @PCRE_CPPFLAGS@ - + @PCRE_CPPFLAGS@ \ + @PCRE2_CPPFLAGS@ + msc_test_LDADD = @APR_LDADD@ \ @APU_LDADD@ \ @CURL_LDADD@ \ @@ -57,6 +59,7 @@ msc_test_LDADD = @APR_LDADD@ \ @LIBXML2_LDADD@ \ @LUA_LDADD@ \ @PCRE_LDADD@ \ + @PCRE2_LDADD@ \ @YAJL_LDADD@ \ @SSDEEP_CFLAGS@ @@ -67,6 +70,7 @@ msc_test_LDFLAGS = @APR_LDFLAGS@ \ @LIBXML2_LDFLAGS@ \ @LUA_LDFLAGS@ \ @PCRE_LDFLAGS@ \ + @PCRE2_LDFLAGS@ \ @YAJL_LDFLAGS@ \ @SSDEEP_LDFLAGS@ diff --git a/tests/msc_test.c b/tests/msc_test.c index 7c794a5d98..bf278d0add 100644 --- a/tests/msc_test.c +++ b/tests/msc_test.c @@ -81,7 +81,7 @@ char DSOLOCAL *real_server_signature = NULL; int DSOLOCAL remote_rules_fail_action = REMOTE_RULES_ABORT_ON_FAIL; char DSOLOCAL *remote_rules_fail_message = NULL; module AP_MODULE_DECLARE_DATA security2_module = { - NULL, + STANDARD20_MODULE_STUFF, NULL, NULL, NULL, From 0710feb06c190a6c1121e4ae0ea995ff213e131c Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 11 May 2025 10:07:20 +0200 Subject: [PATCH 366/470] feat: add 'make test' to v2's workflow --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5e625415a1..d969335269 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,3 +74,39 @@ jobs: - name: Show mod_security2 audit log if: always() run: sudo cat /var/log/apache2/modsec_audit.log + + test-linux: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-22.04] + platform: [x32, x64] + compiler: [gcc, clang] + configure: + - {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: | + 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 apache2 apache2-bin apache2-data + - uses: actions/checkout@v2 + - name: autogen.sh + run: ./autogen.sh + - name: configure ${{ matrix.configure.label }} + run: ./configure ${{ matrix.configure.opt }} 'CFLAGS=-Werror=format-security' + - uses: ammaraskar/gcc-problem-matcher@master + - name: make + run: make -j `nproc` + - name: install module + run: sudo make install + - name: run tests + run: make test From 1514353b6bdffee63c80b0f2b5ee0f3f2fc7d414 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 11 May 2025 16:09:49 +0200 Subject: [PATCH 367/470] Add `--no-install-recommends` flag to avoid install "only" recommended packages 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> --- .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 d969335269..e4a056ef9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,7 +97,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 apache2 apache2-bin apache2-data + sudo apt-get install -y --no-install-recommends 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 From 652b942cfb709918cb90b4bf627aadc0d8380820 Mon Sep 17 00:00:00 2001 From: Xanadu Date: Thu, 8 May 2025 23:17:45 +0100 Subject: [PATCH 368/470] Add extra conditional compilation for err logging Restores the original format string for error logging for ModSecurity when compiled as a standalone module. Specifically, the format string has "[client %s]" back again: this is required for standalone modules as Apache is not present to implicitly log the client source IP address. --- apache2/apache2_util.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index f42436790f..f231147b74 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -284,12 +284,27 @@ 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 +/* Non-standalone modules use amended format string for logging */ +#if !(defined(VERSION_STANDALONE)) + #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "ModSecurity: %s%s [uri \"%s\"]%s", str1, hostname, log_escape(msr->mp, r->uri), unique_id); -#else + #else ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, "ModSecurity: %s%s [uri \"%s\"]%s", str1, hostname, log_escape(msr->mp, r->uri), unique_id); + #endif +/* Standalone module must use original format string for logging with explicit + * "[client %s]" to log client IP address (no Apache to implicitly add this) */ +#else + #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); + #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); + #endif #endif /* Add this message to the list. */ From 0c7dadc4c722cfc2d162eecf17067789bc64dd1c Mon Sep 17 00:00:00 2001 From: RedXanadu Date: Tue, 13 May 2025 16:33:15 +0100 Subject: [PATCH 369/470] Correct indentation --- apache2/apache2_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index f231147b74..faef43f0c5 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -302,8 +302,8 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * 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); + "[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); #endif #endif From d7b38f034e1c85fc73b5511274dfbf8c2ac360e9 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Thu, 15 May 2025 21:13:52 +0200 Subject: [PATCH 370/470] Refactor code and build system to use libpcre2 as the default --- .github/workflows/ci.yml | 40 +++++++++++++------------- apache2/apache2_config.c | 2 +- apache2/mod_security2.c | 4 +-- apache2/modsecurity.c | 2 +- apache2/msc_crypt.c | 20 ++++++------- apache2/msc_pcre.c | 8 +++--- apache2/msc_pcre.h | 4 +-- apache2/msc_status_engine.c | 2 +- apache2/re_operators.c | 56 ++++++++++++++++++------------------- apache2/re_variables.c | 4 +-- build/find_pcre.m4 | 25 ++++++++--------- build/find_pcre2.m4 | 18 ++++++------ mlogc/mlogc.c | 18 ++++++------ standalone/regex.c | 10 +++---- 14 files changed, 106 insertions(+), 107 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4a056ef9f..8ba565f099 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,16 +13,16 @@ jobs: platform: [x32, x64] compiler: [gcc, clang] configure: - - {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" } + - {label: "with pcre2, no study, no jit", opt: "--enable-pcre-study=no" } + - {label: "with pcre2, with study, no jit", opt: "--enable-pcre-study=yes" } + - {label: "with pcre2, no study, with jit", opt: "--enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre2, with study, with jit", opt: "--enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with pcre", opt: "--with-pcre --enable-pcre-study=no" } + - {label: "with pcre, with study, no jit", opt: "--with-pcre --enable-pcre-study=yes" } + - {label: "with pcre, no study, with jit", opt: "--with-pcre --enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre, with study, with jit", opt: "--with-pcre --enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with lua", opt: "--with-lua" } + - {label: "wo lua", opt: "--without-lua" } steps: - name: Setup Dependencies run: | @@ -83,16 +83,16 @@ jobs: platform: [x32, x64] compiler: [gcc, clang] configure: - - {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" } + - {label: "with pcre2, no study, no jit", opt: "--enable-pcre-study=no" } + - {label: "with pcre2, with study, no jit", opt: "--enable-pcre-study=yes" } + - {label: "with pcre2, no study, with jit", opt: "--enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre2, with study, with jit", opt: "--enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with pcre", opt: "--with-pcre --enable-pcre-study=no" } + - {label: "with pcre, with study, no jit", opt: "--with-pcre --enable-pcre-study=yes" } + - {label: "with pcre, no study, with jit", opt: "--with-pcre --enable-pcre-study=no --enable-pcre-jit" } + - {label: "with pcre, with study, with jit", opt: "--with-pcre --enable-pcre-study=yes --enable-pcre-jit" } + - {label: "with lua", opt: "--with-lua" } + - {label: "wo lua", opt: "--without-lua" } steps: - name: Setup Dependencies run: | diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index a831e375ee..7315b8c0a4 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -1343,7 +1343,7 @@ static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, assert(p1 != NULL); directory_config *dcfg = _dcfg; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE 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); diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 1850191eb7..0dcb6b3e75 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -116,7 +116,7 @@ static void version(apr_pool_t *mp, server_rec* s) { ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "ModSecurity: Loaded APR do not match with compiled!"); } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE pcre_vrs = apr_psprintf(mp,"%d.%d ", PCRE2_MAJOR, PCRE2_MINOR); pcre_loaded_vrs = pcre2_loaded_vrs_buffer; pcre2_config(PCRE2_CONFIG_VERSION, pcre2_loaded_vrs_buffer); @@ -126,7 +126,7 @@ static void version(apr_pool_t *mp, server_rec* s) { #endif ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE "ModSecurity: PCRE2 compiled version=\"%s\"; " #else "ModSecurity: PCRE compiled version=\"%s\"; " diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index e21f17766c..fb69d566d6 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -584,7 +584,7 @@ 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 +#ifndef WITH_PCRE if (rc == PCRE2_ERROR_NOMATCH) return 0; #else if (rc == PCRE_ERROR_NOMATCH) return 0; diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 4f73d15a7a..db99adca3d 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -388,7 +388,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -421,7 +421,7 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -451,7 +451,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -484,7 +484,7 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -514,7 +514,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -547,7 +547,7 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -577,7 +577,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -610,7 +610,7 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -640,7 +640,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -673,7 +673,7 @@ int do_hash_method(modsec_rec *msr, char *link, int type) { msr_log(msr, 4, "%s.", error_msg); return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ diff --git a/apache2/msc_pcre.c b/apache2/msc_pcre.c index 16f5efd5d4..edaac3ff8f 100644 --- a/apache2/msc_pcre.c +++ b/apache2/msc_pcre.c @@ -20,7 +20,7 @@ */ static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) { if (regex != NULL) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (regex->match_context != NULL) { pcre2_match_context_free(regex->match_context); regex->match_context = NULL; @@ -55,7 +55,7 @@ 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 +#ifndef WITH_PCRE { msc_regex_t *regex = NULL; PCRE2_SPTR pcre2_pattern; @@ -239,7 +239,7 @@ 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 +#ifndef WITH_PCRE { PCRE2_SPTR pcre2_s; int pcre2_ret; @@ -319,7 +319,7 @@ 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 +#ifndef WITH_PCRE return pcre2_pattern_info(regex->re, (uint32_t)what, where); #else return pcre_fullinfo(regex->re, regex->pe, what, where); diff --git a/apache2/msc_pcre.h b/apache2/msc_pcre.h index c0ab37b4ae..e693236e3d 100644 --- a/apache2/msc_pcre.h +++ b/apache2/msc_pcre.h @@ -17,7 +17,7 @@ typedef struct msc_regex_t msc_regex_t; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE #define PCRE2_CODE_UNIT_WIDTH 8 #include "pcre2.h" #else @@ -42,7 +42,7 @@ typedef struct msc_regex_t msc_regex_t; #include "modsecurity.h" struct msc_regex_t { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE pcre2_code *re; pcre2_match_context *match_context; #ifdef WITH_PCRE_JIT diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 4587641641..b593648cd9 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -349,7 +349,7 @@ 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 +#ifndef WITH_PCRE apr_snprintf(pcre, 7, "%d.%d", PCRE2_MAJOR, PCRE2_MINOR); pcre_loaded = ""; /* complete this if/when status reactivated */ #else diff --git a/apache2/re_operators.c b/apache2/re_operators.c index 3e50191ed4..b10cb586a7 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -39,7 +39,7 @@ #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE /** * @brief Set the JIT compile return code and JIT compile status. * \param regex regex structure @@ -730,7 +730,7 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { /* Compile pattern */ if(strstr(pattern,"%{") == NULL) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; @@ -744,7 +744,7 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - #ifdef WITH_PCRE2 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -834,7 +834,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v msr_log(msr, 6, "Escaping pattern [%s]",pattern); } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; @@ -850,7 +850,7 @@ 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 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -888,7 +888,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -922,7 +922,7 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v return -1; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -1007,7 +1007,7 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { /* Compile pattern */ if(strstr(pattern,"%{") == NULL) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE int options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else int options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; @@ -1021,7 +1021,7 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) { #ifdef WITH_PCRE_STUDY #ifdef WITH_PCRE_JIT - #ifdef WITH_PCRE2 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -1104,7 +1104,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c msr_log(msr, 6, "Expanded-macro pattern [%s]",pattern); } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY; #else options = PCRE_DOTALL | PCRE_DOLLAR_ENDONLY; @@ -1119,7 +1119,7 @@ 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 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -1171,7 +1171,7 @@ 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 +#ifndef WITH_PCRE rc = msc_fullinfo(regex, PCRE2_INFO_CAPTURECOUNT, &capcount); #else rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount); @@ -1187,7 +1187,7 @@ 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 +#ifndef WITH_PCRE if ((rc == PCRE2_ERROR_MATCHLIMIT) || (rc == PCRE2_ERROR_RECURSIONLIMIT)) { #else if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { @@ -1282,7 +1282,7 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c } } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */ #else if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ @@ -1752,7 +1752,7 @@ static int msre_op_gsbLookup_param_init(msre_rule *rule, char **error_msg) { *error_msg = NULL; /* Compile rule->op_param */ -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_MULTILINE; #else options = PCRE_DOTALL | PCRE_MULTILINE; @@ -1830,7 +1830,7 @@ static int msre_op_gsbLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var memcpy(data,var->value,var->value_len); -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_NOTEMPTY; #else options = PCRE_NOTEMPTY; @@ -2953,7 +2953,7 @@ static int msre_op_verifyCC_init(msre_rule *rule, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_MULTILINE; #else options = PCRE_DOTALL | PCRE_MULTILINE; @@ -3010,7 +3010,7 @@ 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 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -3050,7 +3050,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * } } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_NOTEMPTY; #else options = PCRE_NOTEMPTY; @@ -3058,7 +3058,7 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var * 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 +#ifndef WITH_PCRE if (rc == PCRE2_ERROR_NOMATCH) { #else if (rc == PCRE_ERROR_NOMATCH) { @@ -3280,7 +3280,7 @@ static int msre_op_verifyCPF_init(msre_rule *rule, char **error_msg) { *error_msg = NULL; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_MULTILINE; #else options = PCRE_DOTALL | PCRE_MULTILINE; @@ -3349,7 +3349,7 @@ 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 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -3388,7 +3388,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var } } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_NOTEMPTY; #else options = PCRE_NOTEMPTY; @@ -3396,7 +3396,7 @@ static int msre_op_verifyCPF_execute(modsec_rec *msr, msre_rule *rule, msre_var 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 +#ifndef WITH_PCRE if (rc == PCRE2_ERROR_NOMATCH) { #else if (rc == PCRE_ERROR_NOMATCH) { @@ -3603,7 +3603,7 @@ static int msre_op_verifySSN_init(msre_rule *rule, char **error_msg) { if (error_msg == NULL) return -1; *error_msg = NULL; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_MULTILINE; #else options = PCRE_DOTALL | PCRE_MULTILINE; @@ -3674,7 +3674,7 @@ 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 + #ifndef WITH_PCRE msc_op_set_jitrc(regex, &rc, &jit); #else rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit); @@ -3713,7 +3713,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var } } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_NOTEMPTY; #else options = PCRE_NOTEMPTY; @@ -3721,7 +3721,7 @@ static int msre_op_verifySSN_execute(modsec_rec *msr, msre_rule *rule, msre_var 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 +#ifndef WITH_PCRE if (rc == PCRE2_ERROR_NOMATCH) { #else if (rc == PCRE_ERROR_NOMATCH) { diff --git a/apache2/re_variables.c b/apache2/re_variables.c index 266ed6895f..c4c4b0d895 100644 --- a/apache2/re_variables.c +++ b/apache2/re_variables.c @@ -22,7 +22,7 @@ #include "libxml/xpathInternals.h" -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE #define PCRE_ERROR_NOMATCH PCRE2_ERROR_NOMATCH #endif /** @@ -80,7 +80,7 @@ static char *var_generic_list_validate(msre_ruleset *ruleset, msre_var *var) { pattern = apr_pstrmemdup(ruleset->mp, var->param + 1, strlen(var->param + 1) - 1); if (pattern == NULL) return FATAL_ERROR; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE options = PCRE2_DOTALL | PCRE2_CASELESS | PCRE2_DOLLAR_ENDONLY; #else options = PCRE_DOTALL | PCRE_CASELESS | PCRE_DOLLAR_ENDONLY; diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index bf297f67fc..6d217a7231 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -19,19 +19,17 @@ AC_ARG_WITH( pcre, [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"]) + [with_pcre="no"]) -if test "x${with_pcre2}" != "x" && test "x${with_pcre2}" != "xno"; then - AC_MSG_NOTICE([pcre2 specified; omitting check for pcre]) -else - AC_MSG_CHECKING([for libpcre config script]) +AS_CASE(["${with_pcre}"], + [no], [test_paths=], + [yes], [test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr"], + [test_paths="${with_pcre}"]) - 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 +if test "x${with_pcre}" = "x" || test "x${with_pcre}" = "xno"; then + AC_MSG_NOTICE([pcre not specified; omitting check for pcre]) +else + AC_MSG_CHECKING([for libpcre configig script]) for x in ${test_paths}; do dnl # Determine if the script was specified and use it directly @@ -87,7 +85,8 @@ else AC_MSG_NOTICE([*** pcre library not found.]) else AC_MSG_NOTICE([using pcre v${PCRE_VERSION}]) - ifelse([$1], , , $1) - fi + PCRE_CFLAGS="-DWITH_PCRE ${PCRE_CFLAGS}" + ifelse([$1], , , $1) + fi fi ]) diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 index f8786ce9f7..e9655af267 100644 --- a/build/find_pcre2.m4 +++ b/build/find_pcre2.m4 @@ -18,17 +18,17 @@ AC_DEFUN([CHECK_PCRE2], AC_ARG_WITH( pcre2, [AS_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])], - , with_pcre2=no) + [test_paths="${with_pcre2}"], + [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}"]) + [no], [test_paths=], + [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 - AC_MSG_NOTICE([pcre2 not specified; omitting check]) +if test "x${with_pcre}" != "x" || test "x${with_pcre}" != "xno"; then + AC_MSG_NOTICE([pcre specified; omitting check for pcre2]) else - AC_MSG_CHECKING([for libpcre2 config script]) for x in ${test_paths}; do @@ -86,8 +86,8 @@ else 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) + PCRE2_CFLAGS="${PCRE2_CFLAGS}" + ifelse([$1], , , $1) fi fi ]) diff --git a/mlogc/mlogc.c b/mlogc/mlogc.c index b1030ee45e..7a9edaa12b 100644 --- a/mlogc/mlogc.c +++ b/mlogc/mlogc.c @@ -28,7 +28,7 @@ #if APR_HAVE_UNISTD_H #include /* for getpid() */ #endif -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE #define PCRE2_CODE_UNIT_WIDTH 8 #include #else @@ -152,7 +152,7 @@ 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 +#ifndef WITH_PCRE static pcre2_code *logline_regex = NULL; static pcre2_code *requestline_regex = NULL; #else @@ -1218,7 +1218,7 @@ static void logc_init(void) int i, erroffset; /* cURL major, minor and patch version */ short cmaj, cmin, cpat = 0; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE int pcre2_errorcode = 0; PCRE2_SIZE pcre2_erroffset = 0; #endif @@ -1325,7 +1325,7 @@ 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 +#ifndef WITH_PCRE logline_regex = pcre2_compile(logline_pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &pcre2_errorcode, &pcre2_erroffset, NULL); #else @@ -1338,7 +1338,7 @@ static void logc_init(void) logc_shutdown(1); } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE requestline_regex = pcre2_compile(requestline_pattern, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &pcre2_errorcode, &pcre2_erroffset, NULL); #else @@ -1455,7 +1455,7 @@ 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 +#ifndef WITH_PCRE pcre2_match_data *pcre2_match_data = NULL; #endif int take_new = 1; @@ -1563,7 +1563,7 @@ static void * APR_THREAD_FUNC thread_worker(apr_thread_t *thread, void *data) num_requests++; } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE 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); @@ -2334,7 +2334,7 @@ static void usage(void) { * Version text. */ static void version(void) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE char pcre2_loaded_version_buffer[80] ={0}; char *pcre_loaded_version = pcre2_loaded_version_buffer; pcre2_config(PCRE2_CONFIG_VERSION, pcre_loaded_version); @@ -2346,7 +2346,7 @@ static void version(void) { "loaded=\"%s\"\n", APR_VERSION_STRING, apr_version_string()); fprintf(stderr, " PCRE: compiled=\"%d.%d\"; " -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE "loaded=\"%s\"\n", PCRE2_MAJOR, PCRE2_MINOR, pcre_loaded_version); #else "loaded=\"%s\"\n", PCRE_MAJOR, PCRE_MINOR, pcre_version()); diff --git a/standalone/regex.c b/standalone/regex.c index acd46a1593..cdc79059fe 100644 --- a/standalone/regex.c +++ b/standalone/regex.c @@ -61,7 +61,7 @@ AP_DECLARE(ap_regex_t *) ap_pregcomp(apr_pool_t *p, const char *pattern, AP_DECLARE(void) ap_regfree(ap_regex_t *preg) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE (pcre2_code_free)(preg->re_pcre); #else (pcre_free)(preg->re_pcre); @@ -75,7 +75,7 @@ int erroffset; int options = 0; int nsub = 0; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if ((cflags & AP_REG_ICASE) != 0) options |= PCRE2_CASELESS; if ((cflags & AP_REG_NEWLINE) != 0) options |= PCRE2_MULTILINE; int error_number = 0; @@ -120,7 +120,7 @@ int *ovector = NULL; int small_ovector[POSIX_MALLOC_THRESHOLD * 3]; int allocated_ovector = 0; -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE if ((eflags & AP_REG_NOTBOL) != 0) options |= PCRE2_NOTBOL; if ((eflags & AP_REG_NOTEOL) != 0) options |= PCRE2_NOTEOL; #else @@ -144,7 +144,7 @@ if (nmatch > 0) } } -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE { PCRE2_SPTR pcre2_s; int pcre2_ret; @@ -202,7 +202,7 @@ else if (allocated_ovector) free(ovector); switch(rc) { -#ifdef WITH_PCRE2 +#ifndef WITH_PCRE case PCRE2_ERROR_NOMATCH: return AP_REG_NOMATCH; case PCRE2_ERROR_NULL: return AP_REG_INVARG; case PCRE2_ERROR_BADOPTION: return AP_REG_INVARG; From 2ed32f20355863aef7647624963d02376e0a893b Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Thu, 15 May 2025 21:50:02 +0200 Subject: [PATCH 371/470] Fix option check condition --- build/find_pcre2.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4 index e9655af267..58cb79c442 100644 --- a/build/find_pcre2.m4 +++ b/build/find_pcre2.m4 @@ -26,7 +26,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_pcre}" != "x" || test "x${with_pcre}" != "xno"; then +if test "x${with_pcre}" != "x" && test "x${with_pcre}" != "xno"; then AC_MSG_NOTICE([pcre specified; omitting check for pcre2]) else AC_MSG_CHECKING([for libpcre2 config script]) From 854906de7c270958b455fc06e1f3c0b98d3c71ec Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Fri, 16 May 2025 09:40:10 +0200 Subject: [PATCH 372/470] Typo fix Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- build/find_pcre.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/find_pcre.m4 b/build/find_pcre.m4 index 6d217a7231..9b222f67fc 100644 --- a/build/find_pcre.m4 +++ b/build/find_pcre.m4 @@ -29,7 +29,7 @@ AS_CASE(["${with_pcre}"], if test "x${with_pcre}" = "x" || test "x${with_pcre}" = "xno"; then AC_MSG_NOTICE([pcre not specified; omitting check for pcre]) else - AC_MSG_CHECKING([for libpcre configig script]) + AC_MSG_CHECKING([for libpcre config script]) for x in ${test_paths}; do dnl # Determine if the script was specified and use it directly From 9d9a72734988bbd4f101cbea0d5df60eabcc1435 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 9 May 2025 12:42:34 +0100 Subject: [PATCH 373/470] Fix compiler warnings. Reported by GCC with flags: -Wall -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS Note, e.g. sprintf(digest, "%s%02x", digest, ...) is undefined behaviour because the destination and source variables overlap, and GCC warnings for this. acmp.c:258:13: warning: 'acmp_clone_node_no_state' defined but not used [-Wunused-function] apache2_config.c:806:9: warning: unused variable 'offset' [-Wunused-variable] apache2_config.c:1886:23: warning: unused variable 'dcfg' [-Wunused-variable] apache2_config.c:1942:23: warning: unused variable 'dcfg' [-Wunused-variable] apache2_config.c:2470:23: warning: unused variable 'dcfg' [-Wunused-variable] apache2_config.c:2538:23: warning: unused variable 'dcfg' [-Wunused-variable] apache2_util.c:226:11: warning: unused variable 'str' [-Wunused-variable] apache2_util.c:225:11: warning: unused variable 'saved' [-Wunused-variable] apache2_util.c:224:11: warning: unused variable 'parse_remote' [-Wunused-variable] apache2_util.c:223:11: warning: unused variable 'remote' [-Wunused-variable] msc_status_engine.c:216:17: warning: unused variable 'i' [-Wunused-variable] msc_status_engine.c:375:55: warning: the address of 'pcre' will always evaluate as 'true' [-Waddress] msc_crypt.c:67:17: warning: unused variable 'bytes' [-Wunused-variable] msc_crypt.c:1083:33: warning: variable 'enc' set but not used [-Wunused-but-set-variable] msc_crypt.c:1090:29: warning: variable 'enc' set but not used [-Wunused-but-set-variable] /usr/include/bits/stdio2.h:30:10: warning: '__sprintf_chk' argument 5 overlaps destination object 'digest' [-Wrestrict] msc_json.c:405:11: warning: unused variable 'json_data' [-Wunused-variable] msc_crypt.c:1097:79: warning: '%s' directive argument is null [-Wformat-overflow=] msc_logging.c:1144:20: warning: unused variable 'now' [-Wunused-variable] msc_remote_rules.c:729:19: warning: unused variable 'word' [-Wunused-variable] msc_remote_rules.c:727:17: warning: unused variable 'tmp' [-Wunused-variable] msc_remote_rules.c:805:1: warning: control reaches end of non-void function [-Wreturn-type] msc_tree.c:836:19: warning: unused variable 'ip' [-Wunused-variable] msc_xml.c:29:44: warning: variable 'entity' set but not used [-Wunused-but-set-variable] msc_util.c:2627:11: warning: unused variable 'start' [-Wunused-variable] msc_util.c:2626:17: warning: unused variable 'fd' [-Wunused-variable] msc_util.c:2624:18: warning: unused variable 'rc' [-Wunused-variable] msc_util.c:1077:19: warning: array subscript 1 is outside array bounds of 'unsigned char[1]' [-Warray-bounds=] --- apache2/acmp.c | 12 ------------ apache2/apache2_config.c | 5 ----- apache2/apache2_util.c | 4 ---- apache2/msc_crypt.c | 13 ++++--------- apache2/msc_geo.c | 1 - apache2/msc_json.c | 1 - apache2/msc_logging.c | 2 -- apache2/msc_remote_rules.c | 3 +-- apache2/msc_status_engine.c | 11 +++++------ apache2/msc_tree.c | 2 +- apache2/msc_util.c | 8 ++------ apache2/re.c | 12 +----------- 12 files changed, 14 insertions(+), 60 deletions(-) diff --git a/apache2/acmp.c b/apache2/acmp.c index 6e796b38db..3691dd12e5 100644 --- a/apache2/acmp.c +++ b/apache2/acmp.c @@ -251,18 +251,6 @@ static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) { } } -/** - * Copies values from one node to another, without child/sibling/fail pointers - * and without state variables. - */ -static void acmp_clone_node_no_state(acmp_node_t *from, acmp_node_t *to) { - memcpy(to, from, sizeof(acmp_node_t)); - to->child = NULL; - to->sibling = NULL; - to->fail = NULL; - to->hit_count = 0; -} - static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t letter) { acmp_btree_node_t *bnode = node->btree; for (;;) { diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c index a831e375ee..d969905de5 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -797,7 +797,6 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, int type_with_lua = 1; int type_rule; int rule_actionset; - int offset = 0; #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, @@ -1935,7 +1934,6 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, 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; long int limit; limit = strtol(p1, NULL, 10); @@ -1991,7 +1989,6 @@ static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, 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; long int limit; limit = strtol(p1, NULL, 10); @@ -2519,7 +2516,6 @@ static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, 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; if (strcasecmp(p1, "on") == 0) { @@ -2587,7 +2583,6 @@ static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char 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; if (strncasecmp(p1, "warn", 4) == 0) { diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index faef43f0c5..e13c64b905 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -215,10 +215,6 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * apr_size_t nbytes, nbytes_written; apr_file_t *debuglog_fd = NULL; int filter_debug_level = 0; - char *remote = NULL; - char *parse_remote = NULL; - char *saved = NULL; - char *str = NULL; char str1[1024] = ""; char str2[1256] = ""; diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 4f73d15a7a..92690b62c2 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -64,7 +64,6 @@ char *normalize_path(modsec_rec *msr, char *input) { if(uri->path) { char *Uri = NULL; - int bytes = 0; /*int i;*/ char *abs_link = NULL; char *filename = NULL; @@ -1079,22 +1078,18 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { if (ctype && encoding == NULL) { if (ctype && (p = m_strcasestr(ctype, "charset=") , p != NULL)) { p += 8 ; - if (encoding = apr_pstrndup(msr->mp, p, strcspn(p, " ;") ), encoding) { - xmlCharEncoding enc; - enc = xmlParseCharEncoding(encoding); - handler = xmlFindCharEncodingHandler(encoding); - } + encoding = apr_pstrndup(msr->mp, p, strcspn(p, " ;")); + handler = xmlFindCharEncodingHandler(encoding); } } else { if(encoding != NULL) { - xmlCharEncoding enc; - enc = xmlParseCharEncoding(encoding); handler = xmlFindCharEncodingHandler(encoding); } } if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_hashed_response_body: Detected encoding type [%s].", encoding); + msr_log(msr, 4, "inject_hashed_response_body: Detected encoding type [%s].", + encoding ? encoding : "(none)"); if (handler == NULL) handler = xmlFindCharEncodingHandler("UTF-8"); diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c index 7d3a8e4021..77f3403708 100644 --- a/apache2/msc_geo.c +++ b/apache2/msc_geo.c @@ -279,7 +279,6 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro apr_size_t nbytes; unsigned int rec_val = 0; apr_off_t seekto = 0; - apr_status_t ret; int rc; int country = 0; int level; diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 0656fc2588..950eb9b64d 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -402,7 +402,6 @@ 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; *error_msg = NULL; diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c index 39588b10fa..8c7667ef5b 100644 --- a/apache2/msc_logging.c +++ b/apache2/msc_logging.c @@ -1134,8 +1134,6 @@ void sec_audit_logger_json(modsec_rec *msr) { /* AUDITLOG_PART_TRAILER */ if (strchr(msr->txcfg->auditlog_parts, AUDITLOG_PART_TRAILER) != NULL) { - apr_time_t now = apr_time_now(); - /* Messages */ been_opened = 0; if (msr->alerts->nelts > 0) { diff --git a/apache2/msc_remote_rules.c b/apache2/msc_remote_rules.c index 37b8864842..a3cf688923 100644 --- a/apache2/msc_remote_rules.c +++ b/apache2/msc_remote_rules.c @@ -719,9 +719,7 @@ int msc_remote_add_rules_from_uri(cmd_parms *orig_parms, if (plain_text[len] == '\n') { const char *rule = NULL; - int tmp = len; char *cmd_name = NULL; - char *word = NULL; const command_rec *cmd; ap_directive_t *newdir; @@ -792,6 +790,7 @@ int msc_remote_add_rules_from_uri(cmd_parms *orig_parms, { msc_remote_clean_chunk(&downloaded_content); } + return 0; #else *error_msg = "SecRemoteRules was not enabled during ModSecurity " \ "compilation."; diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 4587641641..48c7d00147 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -164,7 +164,6 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) #ifdef DARWIN struct ifaddrs* ifaphead; struct ifaddrs* ifap; - int i = 0; if ( getifaddrs( &ifaphead ) != 0 ) { goto failed; @@ -213,7 +212,6 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) } if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 ) { - int i = 0; if (!ifr->ifr_addr.sa_data[0] && !ifr->ifr_addr.sa_data[1] && !ifr->ifr_addr.sa_data[2]) { continue; @@ -287,7 +285,7 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest) { unsigned char hex_digest[APR_SHA1_DIGESTSIZE]; - unsigned char *mac_address = NULL; + unsigned char *mac_address = NULL, *digptr; char *machine_name = NULL; int ret = 0; int i = 0; @@ -321,9 +319,10 @@ int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest) apr_sha1_update(&context, mac_address, strlen(mac_address)); apr_sha1_final(hex_digest, &context); - for (i = 0; i < APR_SHA1_DIGESTSIZE; i++) + for (i = 0, digptr = digest; i < APR_SHA1_DIGESTSIZE; i++) { - sprintf(digest, "%s%02x", digest, hex_digest[i]); + sprintf(digptr, "%02x", hex_digest[i]); + digptr += 2; } failed_set_machine_name: @@ -372,7 +371,7 @@ int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len) /* 6 represents: strlen("(null)") */ beacon_string_len = (modsec ? strlen(modsec) : 6) + (apache ? strlen(apache) : 6) + (apr ? strlen(apr) : 6) + - (apr_loaded ? strlen(apr_loaded) : 6) + (pcre ? strlen(pcre) : 6) + + (apr_loaded ? strlen(apr_loaded) : 6) + strlen(pcre) + (pcre_loaded ? strlen(pcre_loaded) : 6) + (lua ? strlen(lua) : 6) + (libxml ? strlen(libxml) : 6) + (APR_SHA1_DIGESTSIZE * 2); diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c index f8610b39e3..feabdd0e03 100644 --- a/apache2/msc_tree.c +++ b/apache2/msc_tree.c @@ -833,7 +833,7 @@ TreeNode *CPTIpMatch(modsec_rec *msr, unsigned char *ipdata, CPTTree *tree, int } TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) { - unsigned long ip, ret; + unsigned long ret; unsigned char netmask_v4 = NETMASK_32, netmask_v6 = NETMASK_128; char ip_strv4[NETMASK_32], ip_strv6[NETMASK_128]; struct in_addr addr4; diff --git a/apache2/msc_util.c b/apache2/msc_util.c index fe13ab9984..33f36e8140 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -104,13 +104,12 @@ int swap_int32(int x) { * \retval rval On Success */ char *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed) { - int unicode_len = 0, length = 0; + int unicode_len = 0; unsigned int d = 0; unsigned char c, *utf; char *rval, *data; - unsigned int i, len, j; + unsigned int i, len; unsigned int bytes_left = input_len; - unsigned char *unicode = NULL; assert(input != NULL); @@ -2497,10 +2496,7 @@ int ip_tree_from_uri(TreeRoot **rtree, char *uri, apr_pool_t *mp, char **error_msg) { TreeNode *tnode = NULL; - apr_status_t rc; int line = 0; - apr_file_t *fd; - char *start; int res; struct msc_curl_memory_buffer_t chunk; diff --git a/apache2/re.c b/apache2/re.c index 0a8b0724d3..d067c68419 100644 --- a/apache2/re.c +++ b/apache2/re.c @@ -205,10 +205,9 @@ char *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, assert(ruleset != NULL); assert(phase_arr != NULL); msre_rule **rules; - int i, j, mode; + int i, mode; char *err; - j = 0; mode = 0; rules = (msre_rule **)phase_arr->elts; for (i = 0; i < phase_arr->nelts; i++) { @@ -247,7 +246,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r char *my_error_msg = NULL, *target = NULL; char *p = NULL, *savedptr = NULL; unsigned int is_negated = 0, is_counting = 0; - int name_len = 0, value_len = 0; char *name = NULL, *value = NULL; char *opt = NULL, *param = NULL; char *target_list = NULL, *replace = NULL; @@ -297,10 +295,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r goto end; } - name_len = strlen(name); - - if (value != NULL) value_len = strlen(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++) { @@ -395,10 +389,6 @@ char *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *r goto end; } - name_len = strlen(name); - - if (value != NULL) value_len = strlen(value); - if (msr) { msr_log(msr, 9, "Trying to append variable name [%s] value [%s]", name, value); } From de1cf63d268b8a1c5698e64309ce67f0777d1a47 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 16 May 2025 09:58:55 +0100 Subject: [PATCH 374/470] Fix GCC warning in msc_headers_to_buffer(): In file included from /usr/include/stdio.h:970, from modsecurity.h:18, from msc_util.c:15: In function 'sprintf', inlined from 'msc_headers_to_buffer' at msc_util.c:2331:17: /usr/include/bits/stdio2.h:30:10: warning: '__sprintf_chk' argument 5 overlaps destination object 'buffer' [-Wrestrict] 30 | return __builtin___sprintf_chk (__s, __USE_FORTIFY_LEVEL - 1, | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | __glibc_objsize (__s), __fmt, | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | __va_arg_pack ()); | ~~~~~~~~~~~~~~~~~ msc_util.c: In function 'msc_headers_to_buffer': msc_util.c:2306:64: note: destination object referenced by 'restrict'-qualified argument 1 was declared here 2306 | int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer, | ~~~~~~^~~~~~ --- apache2/msc_util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apache2/msc_util.c b/apache2/msc_util.c index 33f36e8140..471a98a80b 100644 --- a/apache2/msc_util.c +++ b/apache2/msc_util.c @@ -2310,9 +2310,11 @@ int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer, int write_to_buffer = 0; int i = 0; const apr_table_entry_t *te = NULL; + char *ptr = NULL; if (buffer != NULL && buffer_length > 0) { write_to_buffer = 1; + ptr = buffer; } te = (apr_table_entry_t *)arr->elts; @@ -2328,7 +2330,9 @@ int msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer, goto not_enough_memory; } - sprintf(buffer, "%s%s: %s\n", buffer, key, value); + assert(ptr && ptr < buffer + buffer_length); + sprintf(ptr, "%s: %s\n", key, value); + ptr = buffer + headers_length; /* for the next entry. */ } } From 5aa6ce0aa23ce77f9931dcd1d3cb2ae2de3874ef Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 16 May 2025 10:36:30 +0100 Subject: [PATCH 375/470] Log error codes for global mutex failure modes. --- apache2/modsecurity.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c index fb69d566d6..29ec5167c6 100644 --- a/apache2/modsecurity.c +++ b/apache2/modsecurity.c @@ -125,7 +125,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_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"); + ap_log_perror(APLOG_MARK, APLOG_ERR, rc, mp, " ModSecurity: Could not create global mutex"); return -1; } #if !defined(MSC_TEST) @@ -136,7 +136,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, mp, " ModSecurity: Could not set permissions on global mutex"); + ap_log_perror(APLOG_MARK, APLOG_ERR, rc, mp, " ModSecurity: Could not set permissions on global mutex"); return -1; } #endif /* SET_MUTEX_PERMS */ From fdfc2d5b21610651b0cefceb397be2cfc7aac8bb Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 19 May 2025 10:53:50 +0200 Subject: [PATCH 376/470] fix: add ARGS to sanitize list only if it's not added yet --- apache2/modsecurity.h | 1 + apache2/msc_json.c | 1 + apache2/msc_parsers.c | 1 + apache2/re_actions.c | 3 ++- 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apache2/modsecurity.h b/apache2/modsecurity.h index 13334674b5..2894717031 100644 --- a/apache2/modsecurity.h +++ b/apache2/modsecurity.h @@ -693,6 +693,7 @@ struct msc_arg { unsigned int value_origin_offset; unsigned int value_origin_len; const char *origin; + unsigned int marked_for_sanitization; }; struct msc_string { diff --git a/apache2/msc_json.c b/apache2/msc_json.c index 950eb9b64d..cae7bf4f70 100644 --- a/apache2/msc_json.c +++ b/apache2/msc_json.c @@ -70,6 +70,7 @@ int json_add_argument(modsec_rec *msr, const char *value, unsigned length) return 0; } + arg->marked_for_sanitization = 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 9a84e2adf4..793549a5f6 100644 --- a/apache2/msc_parsers.c +++ b/apache2/msc_parsers.c @@ -350,6 +350,7 @@ void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) assert(msr != NULL); assert(arguments != NULL); assert(arg != NULL); + arg->marked_for_sanitization = 0; 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/re_actions.c b/apache2/re_actions.c index a028e42a81..4a922d27f9 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1527,8 +1527,9 @@ static apr_status_t msre_action_sanitizeMatched_execute(modsec_rec *msr, apr_poo for (i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; assert(arg != NULL); - if (strcasecmp(sargname, arg->name) == 0) { + if (arg->marked_for_sanitization == 0 && strcasecmp(sargname, arg->name) == 0) { apr_table_addn(msr->arguments_to_sanitize, arg->name, (void *)arg); + arg->marked_for_sanitization = 1; } } break; From cbbbaa6b0c4ca960d3f43b5d58a797be5af140ba Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 21 May 2025 14:36:15 +0200 Subject: [PATCH 377/470] docs: added changes --- CHANGES | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 416d6fd399..fa3fc05730 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,43 @@ -(to be released) - 2.9.x +(to be released) - 2.9.x ------------------------ + * chore: log error codes for global mutex failure modes. + [Issue #3387 - @airween] + * chore: refactor build system to use PCRE2 + [Issue #3383 - @airween] + * feat: add 'make test' to v2's workflow + [Issue #3379 - @airween] + * fix: 'make test' is able to run again + [Issue #3378 - @airween] + * fix: add PCRE2 capability to standalone module + [Issue #3377 - @airween] + * chore: remove unnecessary @LIBXML2_CFLAGS@ from linker flags + [Issue #3376 - @airween] + * fix: add msc_fullinfo() to check JIT compilation + [Issue #3375 - @airween] + * Fix error logging for standalone module + [Issue #3374 - @RedXanadu] + * Fix compiler warnings from GCC + [Issue #3372 - @notroj] + * feat: improved XMLArgs processing + [Issue #3358 - @airween] + * Incorrect utf8toUnicode transformation for 00xx + [Issue #3284 - @marcstern] + * Fixed PCRE2 error message + [Issue #3279 - @marcstern] + * make rootpath and incpath consts for apr_filepath_root + [Issue #3270 - @Marcool04] + * Fix apr_global_mutex_create() usage + [Issue #3269 - @marcstern] + * chore: add 'log' action to rule 200005 (v2/master) + [Issue #3267 - @airween] + * Move id_log() to msc_util to fix unit tests; it is declared on msc_ut… + [Issue #3265 - @rainerjung] + * Missing #include + [Issue #3262 - @marcstern] * Fixed apr_global_mutex_create() usage (no filename) [PR #3269 - @marcstern] -* handle errors from apr_global_mutex_lock + * handle errors from apr_global_mutex_lock [PR #3257 - @marcstern] 03 Sep 2024 - 2.9.8 From 9ab88d6206a140762f824a23f6a334e0224338b5 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 21 May 2025 21:10:34 +0200 Subject: [PATCH 378/470] chore: prepare v2.9.9 --- CHANGES | 6 ++++-- apache2/msc_release.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index fa3fc05730..493bf27651 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,8 @@ -(to be released) - 2.9.x ------------------------- +21 May 2025 - 2.9.9 +------------------- + * fix: Possible DoS vulnerability + [PR from private repo - @theseion, @fzipi, @airween; fixed CVE-2025-47947] * chore: log error codes for global mutex failure modes. [Issue #3387 - @airween] * chore: refactor build system to use PCRE2 diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 5c4dbc96d2..fb88a7cce3 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 "8" +#define MODSEC_VERSION_MAINT "9" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From 0fa2754a0e1a1ee899cb8bf37a3b090c12a80b97 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 21 May 2025 21:15:51 +0200 Subject: [PATCH 379/470] Fix change's title Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 493bf27651..45a674ce3f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,7 @@ 21 May 2025 - 2.9.9 ------------------- - * fix: Possible DoS vulnerability + * fix: DoS vulnerability [PR from private repo - @theseion, @fzipi, @airween; fixed CVE-2025-47947] * chore: log error codes for global mutex failure modes. [Issue #3387 - @airween] From 614c6e18a734bd31a483abc2fa2faf217dcb81c3 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sat, 24 May 2025 12:04:39 +0200 Subject: [PATCH 380/470] fix: add ARGS to sanitize list only if it's not added yet in case of sanitizeArg --- apache2/re_actions.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apache2/re_actions.c b/apache2/re_actions.c index 4a922d27f9..febc4759e1 100644 --- a/apache2/re_actions.c +++ b/apache2/re_actions.c @@ -1455,8 +1455,9 @@ static apr_status_t msre_action_sanitizeArg_execute(modsec_rec *msr, apr_pool_t for (i = 0; i < tarr->nelts; i++) { msc_arg *arg = (msc_arg *)telts[i].val; - if (strcasecmp(sargname, arg->name) == 0) { + if (arg->marked_for_sanitization == 0 && strcasecmp(sargname, arg->name) == 0) { apr_table_addn(msr->arguments_to_sanitize, arg->name, (void *)arg); + arg->marked_for_sanitization = 1; } } From 0a70b0e343b37c0a2666c17fd96db622277c11f0 Mon Sep 17 00:00:00 2001 From: Aleksandr Mezin Date: Tue, 27 May 2025 09:38:02 +0300 Subject: [PATCH 381/470] Fix resource leaks in `msc_status_engine_mac_address` `goto end` jumped over freeing/releasing resources for all platforms. For Linux, this caused a leak of open socket. For other platforms, it's just a memory leak. --- apache2/msc_status_engine.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index de28dee13c..0d7a0e913d 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -182,7 +182,7 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) (unsigned char)LLADDR(sdl)[3], (unsigned char)LLADDR(sdl)[4], (unsigned char)LLADDR(sdl)[5]); - goto end; + break; } } @@ -225,7 +225,7 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) (unsigned char)ifr->ifr_addr.sa_data[4], (unsigned char)ifr->ifr_addr.sa_data[5]); - goto end; + break; } } close( sock ); @@ -268,7 +268,7 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) (unsigned char)pAdapter->Address[3], (unsigned char)pAdapter->Address[4], (unsigned char)pAdapter->Address[5]); - goto end; + break; } pAdapter = pAdapter->Next; } @@ -276,7 +276,6 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) free(pAdapterInfo); #endif -end: return 0; failed: return -1; From 8a704871caf505c8c1678fdd0da4d679b4330f0b Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 2 Jun 2025 16:50:33 +0200 Subject: [PATCH 382/470] Preparing new release --- CHANGES | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGES b/CHANGES index 45a674ce3f..326e4c8e3d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +02 Jun 2025 - 2.9.10 +-------------------- + + * fix: DoS vulnerability + [PR from private repo - @theseion, @fzipi, @airween; fixed CVE-2025-48866] + 21 May 2025 - 2.9.9 ------------------- From 0923377d6d618e4cf6cc56ac67ce385bb60127e9 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 2 Jun 2025 16:59:37 +0200 Subject: [PATCH 383/470] Change release version to v2.9.10 --- 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 fb88a7cce3..b8fe075a10 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 "9" +#define MODSEC_VERSION_MAINT "10" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" From 7896784079204e60f73b5aec6ee27fbaeafa47b6 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 10 Jun 2025 10:51:31 +0200 Subject: [PATCH 384/470] chore: bump version in MSI installer.wxs --- iis/installer.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/installer.wxs b/iis/installer.wxs index 17ed02c047..03f9013f2c 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + From 8fd8f37a77582901c27dcbc9f9973e4b49ac4049 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 10 Jun 2025 15:07:21 +0200 Subject: [PATCH 385/470] Typo fix 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> --- iis/installer.wxs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/installer.wxs b/iis/installer.wxs index 03f9013f2c..d544cd45fb 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -9,7 +9,7 @@ - + From cfbdc30ef154c68c487996e7267026de3b53c685 Mon Sep 17 00:00:00 2001 From: Nic Grant Date: Wed, 11 Jun 2025 09:34:00 +0100 Subject: [PATCH 386/470] Fix memory leak when msre_op_validateSchema_execute exits normally (ValidateSchema) --- apache2/re_operators.c | 1 + 1 file changed, 1 insertion(+) diff --git a/apache2/re_operators.c b/apache2/re_operators.c index b10cb586a7..aa678c0ab5 100644 --- a/apache2/re_operators.c +++ b/apache2/re_operators.c @@ -2898,6 +2898,7 @@ static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre xmlSchemaFree(schema); xmlSchemaFreeValidCtxt(validCtx); + xmlSchemaFreeParserCtxt(parserCtx); return 0; } From ca99ccd23fd92c002a3901e890b4b6ea394f292b Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 24 Jun 2025 21:12:26 +0200 Subject: [PATCH 387/470] Fix unexpected behavior if the XML tag is empty --- apache2/msc_xml.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 8b0fa766e4..74945a0870 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -85,14 +85,14 @@ static void msc_xml_on_end_elementns( arg->name = xml_parser_state->currpath; arg->name_len = strlen(arg->name); - arg->value = xml_parser_state->currval; - arg->value_len = strlen(xml_parser_state->currval); + arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval; + arg->value_len = (xml_parser_state->currval == NULL) ? 0 : strlen(xml_parser_state->currval); arg->value_origin_len = arg->value_len; arg->origin = "XML"; if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Adding XML argument '%s' with value '%s'", - xml_parser_state->currpath, xml_parser_state->currval); + xml_parser_state->currpath, arg->value); } apr_table_addn(msr->arguments, From 89d3ad38c5a964f760af240e3ace3467bb729a64 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 24 Jun 2025 21:34:12 +0200 Subject: [PATCH 388/470] Introduced a new variable to hold currval length --- apache2/msc_xml.c | 11 +++++++++-- apache2/msc_xml.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 74945a0870..dfb622cd47 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -44,6 +44,7 @@ static void msc_xml_on_start_elementns( // this is necessary because if there is any text between the tags (new line, etc) // it will be added to the current value xml_parser_state->currval = NULL; + xml_parser_state->currpathbufflen = 0; // if there is an item before the current one we set that has a child if (xml_parser_state->depth > 1) { @@ -73,7 +74,11 @@ static void msc_xml_on_end_elementns( if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Skipping request argument, over limit (XML): name \"%s\", value \"%s\"", log_escape_ex(msr->mp, xml_parser_state->currpath, strlen(xml_parser_state->currpath)), - log_escape_ex(msr->mp, xml_parser_state->currval, strlen(xml_parser_state->currval))); + log_escape_ex(msr->mp, + (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval), + (xml_parser_state->currvalbufflen == 0 ? 1 : xml_parser_state->currvalbufflen) + ) + ); } msr->msc_reqbody_error = 1; msr->xml->xml_error = apr_psprintf(msr->mp, "More than %ld ARGS (GET + XML)", msr->txcfg->arguments_limit); @@ -86,7 +91,7 @@ static void msc_xml_on_end_elementns( arg->name = xml_parser_state->currpath; arg->name_len = strlen(arg->name); arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval; - arg->value_len = (xml_parser_state->currval == NULL) ? 0 : strlen(xml_parser_state->currval); + arg->value_len = (xml_parser_state->currvalbufflen == 0) ? 1 : xml_parser_state->currvalbufflen; arg->value_origin_len = arg->value_len; arg->origin = "XML"; @@ -123,6 +128,7 @@ static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) { ((xml_parser_state->currval != NULL) ? xml_parser_state->currval : ""), apr_pstrndup(msr->mp, (const char *)ch, len), NULL); + xml_parser_state->currvalbufflen += len; // check if the memory allocation was successful if (xml_parser_state->currval == NULL) { msr->xml->xml_error = apr_psprintf(msr->mp, "Failed to allocate memory for XML value."); @@ -175,6 +181,7 @@ int xml_init(modsec_rec *msr, char **error_msg) { msr->xml->xml_parser_state->pathlen = 4; // "xml\0" msr->xml->xml_parser_state->currpath = apr_pstrdup(msr->mp, "xml"); msr->xml->xml_parser_state->currval = NULL; + msr->xml->xml_parser_state->currvalbufflen = 0; msr->xml->xml_parser_state->currpathbufflen = 4; // initialize the stack with item of 10 // this will store the information about nodes diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h index 3d23c60db9..dd232fba4d 100644 --- a/apache2/msc_xml.h +++ b/apache2/msc_xml.h @@ -31,6 +31,7 @@ struct msc_xml_parser_state { char * currpath; char * currval; size_t currpathbufflen; + size_t currvalbufflen; apr_pool_t * mp; }; From f9e81f2c78188b486dee6d76fd274d06e15d0a71 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 24 Jun 2025 22:02:00 +0200 Subject: [PATCH 389/470] Leave strlen() if not necesseraly; use own length storage --- apache2/msc_xml.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index dfb622cd47..b964daad1d 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -36,6 +36,7 @@ static void msc_xml_on_start_elementns( xml_parser_state->pathlen += (taglen + 1); char *newpath = apr_pstrcat(msr->mp, xml_parser_state->currpath, ".", (char *)localname, NULL); xml_parser_state->currpath = newpath; + xml_parser_state->currpathbufflen += taglen; int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); *new_stack_item = 0; @@ -44,7 +45,7 @@ static void msc_xml_on_start_elementns( // this is necessary because if there is any text between the tags (new line, etc) // it will be added to the current value xml_parser_state->currval = NULL; - xml_parser_state->currpathbufflen = 0; + xml_parser_state->currvalbufflen = 0; // if there is an item before the current one we set that has a child if (xml_parser_state->depth > 1) { @@ -73,7 +74,7 @@ static void msc_xml_on_end_elementns( 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 (XML): name \"%s\", value \"%s\"", - log_escape_ex(msr->mp, xml_parser_state->currpath, strlen(xml_parser_state->currpath)), + log_escape_ex(msr->mp, xml_parser_state->currpath, xml_parser_state->currpathbufflen), log_escape_ex(msr->mp, (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval), (xml_parser_state->currvalbufflen == 0 ? 1 : xml_parser_state->currvalbufflen) @@ -89,7 +90,7 @@ static void msc_xml_on_end_elementns( msc_arg * arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg)); arg->name = xml_parser_state->currpath; - arg->name_len = strlen(arg->name); + arg->name_len = xml_parser_state->currpathbufflen; arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval; arg->value_len = (xml_parser_state->currvalbufflen == 0) ? 1 : xml_parser_state->currvalbufflen; arg->value_origin_len = arg->value_len; @@ -111,9 +112,11 @@ static void msc_xml_on_end_elementns( // -1 is needed because we don't need the last '.' char * newpath = apr_pstrndup(msr->mp, xml_parser_state->currpath, xml_parser_state->pathlen - 1); xml_parser_state->currpath = newpath; + xml_parser_state->currpathbufflen = xml_parser_state->pathlen - 2; // -2 because of the '\0' and the last '.' xml_parser_state->depth--; xml_parser_state->currval = NULL; + xml_parser_state->currvalbufflen = 0; } static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) { @@ -180,9 +183,9 @@ int xml_init(modsec_rec *msr, char **error_msg) { msr->xml->xml_parser_state->depth = 0; msr->xml->xml_parser_state->pathlen = 4; // "xml\0" msr->xml->xml_parser_state->currpath = apr_pstrdup(msr->mp, "xml"); + msr->xml->xml_parser_state->currpathbufflen = 3; // "xml" msr->xml->xml_parser_state->currval = NULL; msr->xml->xml_parser_state->currvalbufflen = 0; - msr->xml->xml_parser_state->currpathbufflen = 4; // initialize the stack with item of 10 // this will store the information about nodes // 10 is just an initial value, it can be automatically incremented From 8cb7fc82fecd182369bcffd93ab81f48d9c0a18c Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 24 Jun 2025 22:10:20 +0200 Subject: [PATCH 390/470] Set correct length of currpath --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index b964daad1d..8f4056f59e 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -112,7 +112,7 @@ static void msc_xml_on_end_elementns( // -1 is needed because we don't need the last '.' char * newpath = apr_pstrndup(msr->mp, xml_parser_state->currpath, xml_parser_state->pathlen - 1); xml_parser_state->currpath = newpath; - xml_parser_state->currpathbufflen = xml_parser_state->pathlen - 2; // -2 because of the '\0' and the last '.' + xml_parser_state->currpathbufflen = xml_parser_state->pathlen - 1; xml_parser_state->depth--; xml_parser_state->currval = NULL; From e56d62960eee41e4ed92c8acafe5cad80047601a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Thu, 26 Jun 2025 17:42:49 +0200 Subject: [PATCH 391/470] Set correct pathlen --- apache2/msc_xml.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 8f4056f59e..8df3280be6 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -36,7 +36,7 @@ static void msc_xml_on_start_elementns( xml_parser_state->pathlen += (taglen + 1); char *newpath = apr_pstrcat(msr->mp, xml_parser_state->currpath, ".", (char *)localname, NULL); xml_parser_state->currpath = newpath; - xml_parser_state->currpathbufflen += taglen; + xml_parser_state->currpathbufflen += taglen + 1; int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); *new_stack_item = 0; @@ -98,7 +98,7 @@ static void msc_xml_on_end_elementns( if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Adding XML argument '%s' with value '%s'", - xml_parser_state->currpath, arg->value); + arg->name, arg->value); } apr_table_addn(msr->arguments, From 8879413abf507b1921f6feb292ee91e0f0064b01 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Thu, 26 Jun 2025 21:50:54 +0200 Subject: [PATCH 392/470] Add comment to explain the behavior --- apache2/msc_xml.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 8df3280be6..1deac6fc4d 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -36,7 +36,7 @@ static void msc_xml_on_start_elementns( xml_parser_state->pathlen += (taglen + 1); char *newpath = apr_pstrcat(msr->mp, xml_parser_state->currpath, ".", (char *)localname, NULL); xml_parser_state->currpath = newpath; - xml_parser_state->currpathbufflen += taglen + 1; + xml_parser_state->currpathbufflen += taglen + 1; // +1 for the '.' character here too int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack); *new_stack_item = 0; From 5615addfb3432d5b1af1849c5e78e11812a8fe03 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 1 Jul 2025 21:55:51 +0200 Subject: [PATCH 393/470] Change release version to v2.9.11 --- CHANGES | 12 ++++++++++++ apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 326e4c8e3d..d2282ac9eb 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +01 Jul 2025 - 2.9.11 +-------------------- + + * fix: prevent segmentation fault if the XML node is empty + [PR from private repo - @theseion, @fzipi, @RedXanadu, @airween; fixed CVE-2025-52891] + * Plug memory leak when msre_op_validateSchema_execute() exits normally (validateSchema) + [Issue #3401 - @nic-prgs] + * chore: bump version in MSI installer.wxs + [Issue #3400 - @airween] + * Fix resource leaks in `msc_status_engine_mac_address` + [Issue #3391 - @amezin] + 02 Jun 2025 - 2.9.10 -------------------- diff --git a/apache2/msc_release.h b/apache2/msc_release.h index b8fe075a10..658e61595a 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 "10" +#define MODSEC_VERSION_MAINT "11" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" diff --git a/iis/installer.wxs b/iis/installer.wxs index d544cd45fb..bb9e4a4b82 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + From e12c0ef4cc7fdbc7dcee4bd5a62b76529406bb19 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 2 Jul 2025 21:37:21 +0200 Subject: [PATCH 394/470] Remove unvanted '\0' string terminator from arg value --- apache2/msc_xml.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c index 1deac6fc4d..4f0e07ca05 100644 --- a/apache2/msc_xml.c +++ b/apache2/msc_xml.c @@ -76,8 +76,8 @@ static void msc_xml_on_end_elementns( msr_log(msr, 4, "Skipping request argument, over limit (XML): name \"%s\", value \"%s\"", log_escape_ex(msr->mp, xml_parser_state->currpath, xml_parser_state->currpathbufflen), log_escape_ex(msr->mp, - (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval), - (xml_parser_state->currvalbufflen == 0 ? 1 : xml_parser_state->currvalbufflen) + (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 0) : xml_parser_state->currval), + xml_parser_state->currvalbufflen ) ); } @@ -91,8 +91,8 @@ static void msc_xml_on_end_elementns( arg->name = xml_parser_state->currpath; arg->name_len = xml_parser_state->currpathbufflen; - arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval; - arg->value_len = (xml_parser_state->currvalbufflen == 0) ? 1 : xml_parser_state->currvalbufflen; + arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 0) : xml_parser_state->currval; + arg->value_len = xml_parser_state->currvalbufflen; arg->value_origin_len = arg->value_len; arg->origin = "XML"; From 0cff9e9dee47c62740c673a7d02c4fc59c44ec9f Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 2 Jul 2025 22:03:46 +0200 Subject: [PATCH 395/470] Remove unnecessary condition --- apache2/msc_status_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apache2/msc_status_engine.c b/apache2/msc_status_engine.c index 0d7a0e913d..be4150bc23 100644 --- a/apache2/msc_status_engine.c +++ b/apache2/msc_status_engine.c @@ -173,7 +173,7 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac) for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next ) { struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr; if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER ) - && mac[0] && mac[1] && mac[2] && i < 6) { + && mac[0] && mac[1] && mac[2]) { apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x", (unsigned char)LLADDR(sdl)[0], From 158084c7ec82c08b2b0d0fc2f69c120ceb4329cb Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 27 Jul 2025 19:54:58 +0200 Subject: [PATCH 396/470] Fix startup errors, missing getopt() args --- tests/run-regression-tests.pl.in | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-regression-tests.pl.in b/tests/run-regression-tests.pl.in index 40e885f0eb..bf95343d58 100755 --- a/tests/run-regression-tests.pl.in +++ b/tests/run-regression-tests.pl.in @@ -11,7 +11,7 @@ use strict; use Time::HiRes qw(gettimeofday sleep); use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); -use File::Spec qw(rel2abs); +use File::Spec::Functions qw(rel2abs); use File::Basename qw(basename dirname); use FileHandle; use IPC::Open2 qw(open2); @@ -54,7 +54,7 @@ $SIG{TERM} = $SIG{INT} = \&handle_interrupt; my $platform = "apache"; my %opt; -getopts('A:E:D:C:T:H:a:p:dvh', \%opt); +getopts('A:E:D:C:T:H:S:a:p:dvh', \%opt); if ($opt{d}) { $Data::Dumper::Indent = 1; @@ -125,7 +125,7 @@ unless (defined $opt{S}) { LOGS_DIR => $FILES_DIR, SCRIPT_DIR => $SCRIPT_DIR, REGRESSION_DIR => $REG_DIR, - DIST_ROOT => File::Spec->rel2abs(dirname("$SCRIPT_DIR/../../..")), + DIST_ROOT => File::Spec->rel2abs(dirname("$SCRIPT_DIR/../..")), AUDIT_LOG => $opt{A}, DEBUG_LOG => $opt{D}, ERROR_LOG => $opt{E}, From 36876ff5fb9cbe08d7eac7ddb90a4363ececf1d4 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Sun, 27 Jul 2025 19:55:18 +0200 Subject: [PATCH 397/470] Fix load tests --- tests/modsecurity.conf-minimal | 240 ++++++++++++++++++ tests/regression/config/00-load-modsec.t | 2 +- .../server_root/conf/unicode.mapping | 96 +++++++ 3 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 tests/modsecurity.conf-minimal create mode 100644 tests/regression/server_root/conf/unicode.mapping diff --git a/tests/modsecurity.conf-minimal b/tests/modsecurity.conf-minimal new file mode 100644 index 0000000000..cddb0b762e --- /dev/null +++ b/tests/modsecurity.conf-minimal @@ -0,0 +1,240 @@ +# -- Rule engine initialization ---------------------------------------------- + +# Enable ModSecurity, attaching it to every transaction. Use detection +# only to start with, because that minimises the chances of post-installation +# disruption. +# +SecRuleEngine DetectionOnly + + +# -- Request body handling --------------------------------------------------- + +# Allow ModSecurity to access request bodies. If you don't, ModSecurity +# won't be able to see any POST parameters, which opens a large security +# hole for attackers to exploit. +# +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" \ + "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" \ + "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/[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 +# 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 +# to the size of data, with files excluded. You want to keep that value as +# low as practical. +# +SecRequestBodyLimit 13107200 +SecRequestBodyNoFilesLimit 131072 + +# Store up to 128 KB of request body data in memory. When the multipart +# parser reaches this limit, it will start using your hard disk for +# storage. That is slow, but unavoidable. +# +SecRequestBodyInMemoryLimit 131072 + +# What do do if the request body size is above our configured limit. +# Keep in mind that this setting will automatically be set to ProcessPartial +# when SecRuleEngine is set to DetectionOnly mode in order to minimize +# disruptions when initially deploying ModSecurity. +# +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) +# or log a high-severity alert (when deployed in detection-only mode). +# +SecRule REQBODY_ERROR "!@eq 0" \ +"id:'200002', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + +# By default be strict with what we accept in the multipart/form-data +# request body. If the rule below proves to be too strict for your +# environment consider changing it to detection-only. You are encouraged +# _not_ to remove it altogether. +# +SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ +"id:'200003',phase:2,t:none,log,deny,status:400, \ +msg:'Multipart request body failed strict validation: \ +PE %{REQBODY_PROCESSOR_ERROR}, \ +BQ %{MULTIPART_BOUNDARY_QUOTED}, \ +BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ +DB %{MULTIPART_DATA_BEFORE}, \ +DA %{MULTIPART_DATA_AFTER}, \ +HF %{MULTIPART_HEADER_FOLDING}, \ +LF %{MULTIPART_LF_LINE}, \ +SM %{MULTIPART_MISSING_SEMICOLON}, \ +IQ %{MULTIPART_INVALID_QUOTING}, \ +IP %{MULTIPART_INVALID_PART}, \ +IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ +FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + +# Did we see anything that might be a boundary? +# +SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ +"id:'200004',phase:2,t:none,log,deny,msg:'Multipart parser detected a possible unmatched boundary.'" + +# PCRE Tuning +# We want to avoid a potential RegEx DoS condition +# +SecPcreMatchLimit 1000 +SecPcreMatchLimitRecursion 1000 + +# Some internal errors will set flags in TX and we will need to look for these. +# All of these are prefixed with "MSC_". The following flags currently exist: +# +# MSC_PCRE_LIMITS_EXCEEDED: PCRE match limits were exceeded. +# +SecRule TX:/^MSC_/ "!@streq 0" \ + "id:'200005',phase:2,t:none,log,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + + +# -- Response body handling -------------------------------------------------- + +# Allow ModSecurity to access response bodies. +# You should have this directive enabled in order to identify errors +# and data leakage issues. +# +# Do keep in mind that enabling this directive does increases both +# memory consumption and response latency. +# +SecResponseBodyAccess On + +# Which response MIME types do you want to inspect? You should adjust the +# configuration below to catch documents but avoid static files +# (e.g., images and archives). +# +SecResponseBodyMimeType text/plain text/html text/xml + +# Buffer response bodies of up to 512 KB in length. +SecResponseBodyLimit 524288 + +# What happens when we encounter a response body larger than the configured +# limit? By default, we process what we have and let the rest through. +# That's somewhat less secure, but does not break any legitimate pages. +# +SecResponseBodyLimitAction ProcessPartial + + +# -- Filesystem configuration ------------------------------------------------ + +# The location where ModSecurity stores temporary files (for example, when +# it needs to handle a file upload that is larger than the configured limit). +# +# This default setting is chosen due to all systems have /tmp available however, +# this is less than ideal. It is recommended that you specify a location that's private. +# +SecTmpDir /tmp/ + +# The location where ModSecurity will keep its persistent data. This default setting +# is chosen due to all systems have /tmp available however, it +# too should be updated to a place that other users can't access. +# +SecDataDir /tmp/ + + +# -- File uploads handling configuration ------------------------------------- + +# The location where ModSecurity stores intercepted uploaded files. This +# 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/ + +# 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 +# will also need at least one file inspection rule. +# +#SecUploadKeepFiles RelevantOnly + +# Uploaded files are by default created with permissions that do not allow +# any other user to access them. You may need to relax that if you want to +# interface ModSecurity to an external program (e.g., an anti-virus). +# +#SecUploadFileMode 0600 + + +# -- Debug log configuration ------------------------------------------------- + +# 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 +#SecDebugLogLevel 3 + + +# -- Audit log configuration ------------------------------------------------- + +# Log the transactions that are marked by a rule, as well as those that +# trigger a server error (determined by a 5xx or 4xx, excluding 404, +# level response status codes). +# +SecAuditEngine RelevantOnly +SecAuditLogRelevantStatus "^(?:5|4(?!04))" + +# Log everything we know about a transaction. +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 /var/log/modsec_audit.log + +# Specify the path for concurrent audit logging. +#SecAuditLogStorageDir /opt/modsecurity/var/audit/ + + +# -- Miscellaneous ----------------------------------------------------------- + +# Use the most commonly used application/x-www-form-urlencoded parameter +# separator. There's probably only one application somewhere that uses +# something else so don't expect to change this value. +# +SecArgumentSeparator & + +# Settle on version 0 (zero) cookies, as that is what most applications +# use. Using an incorrect cookie version may open your installation to +# evasion attacks (against the rules that examine named cookies). +# +SecCookieFormat 0 + +# Specify your Unicode Code Point. +# This mapping is used by the t:urlDecodeUni transformation function +# to properly map encoded data to your language. Properly setting +# these directives helps to reduce false positives and negatives. +# +SecUnicodeMapFile unicode.mapping 20127 + +# Improve the quality of ModSecurity by sharing information about your +# current ModSecurity version and dependencies versions. +# The following information will be shared: ModSecurity version, +# Web Server version, APR version, PCRE version, Lua version, Libxml2 +# version, Anonymous unique id for host. +# 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 + diff --git a/tests/regression/config/00-load-modsec.t b/tests/regression/config/00-load-modsec.t index 222120da67..a5e3c6d89a 100644 --- a/tests/regression/config/00-load-modsec.t +++ b/tests/regression/config/00-load-modsec.t @@ -14,7 +14,7 @@ conf => sub { # Open the minimal conf file, substituting the # relative log paths with full paths. - open(C, "<$ENV{DIST_ROOT}/modsecurity.conf-minimal") or die "$!\n"; + open(C, "<$ENV{DIST_ROOT}/tests/modsecurity.conf-minimal") or die "$!\n"; (my $conf = join('', )) =~ s#Log logs/#Log $ENV{TEST_SERVER_ROOT}/logs/#g; close C; diff --git a/tests/regression/server_root/conf/unicode.mapping b/tests/regression/server_root/conf/unicode.mapping new file mode 100644 index 0000000000..2654c4a619 --- /dev/null +++ b/tests/regression/server_root/conf/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 575314fe59ed8a153611e66661af450d3bfd0b8a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 14:18:15 +0200 Subject: [PATCH 398/470] Fix misc directives test cases --- tests/regression/config/10-misc-directives.t | 2 +- tests/run-regression-tests.pl.in | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/regression/config/10-misc-directives.t b/tests/regression/config/10-misc-directives.t index 62a5e8e021..1c08d87961 100644 --- a/tests/regression/config/10-misc-directives.t +++ b/tests/regression/config/10-misc-directives.t @@ -55,7 +55,7 @@ error => [ qr/ModSecurity: Warning. Unconditional match in SecAction\./, 1 ], }, match_file => { - "$ENV{DATA_DIR}/ip.pag" => qr/\x00\x06dummy\x00\x00\x021\x00/, + "$ENV{DATA_DIR}/$ENV{RUNASUSER}-ip.pag" => qr/\x00\x06dummy\x00\x00\x021\x00/, }, match_response => { status => qr/^200$/, diff --git a/tests/run-regression-tests.pl.in b/tests/run-regression-tests.pl.in index bf95343d58..d8db033040 100755 --- a/tests/run-regression-tests.pl.in +++ b/tests/run-regression-tests.pl.in @@ -132,6 +132,7 @@ unless (defined $opt{S}) { HTTPD_CONF => $opt{C}, HTDOCS => $opt{H}, USER_AGENT => $UA_NAME, + RUNASUSER => $ENV{USER} || $ENV{LOGNAME} || $ENV{USERNAME} || 'unknown', ); #dbg("OPTIONS: ", \%opt); From 10659ad14d8573aa01f4a764a403630d85c85a5e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 15:30:04 +0200 Subject: [PATCH 399/470] Fix request directives test cases --- tests/regression/config/10-request-directives.t | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/config/10-request-directives.t b/tests/regression/config/10-request-directives.t index 21b83ff101..d5c6f143b4 100644 --- a/tests/regression/config/10-request-directives.t +++ b/tests/regression/config/10-request-directives.t @@ -578,10 +578,10 @@ SecRequestBodyLimit 131072 ), match_log => { - -debug => [ qr/Request body is larger than the configured limit/, 1], + error => [ qr/Multipart parsing error: Multipart: Final boundary missing./, 1], }, match_response => { - status => qr/^200$/, + status => qr/^500$/, }, request => normalize_raw_request_data( qq( From 33791eb14a1b8491156b16017f6e63aa8dda23c9 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 16:09:10 +0200 Subject: [PATCH 400/470] Fix multipart tests --- tests/regression/misc/00-multipart-parser.t | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t index e5ee4c13cd..35ba5ba3d7 100644 --- a/tests/regression/misc/00-multipart-parser.t +++ b/tests/regression/misc/00-multipart-parser.t @@ -270,7 +270,7 @@ debug => [ qr/Final boundary missing/, 1 ], }, match_response => { - status => qr/^200$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -1120,10 +1120,10 @@ SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,id:500121" ), match_log => { - debug => [ qr/boundary whitespace in C-T header/, 1 ], + debug => [ qr/Multipart: Warning: boundary whitespace in C-T header./, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -1216,10 +1216,10 @@ SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,id:500127" ), match_log => { - debug => [ qr/No boundaries found in payload/, 1 ], + debug => [ qr/Multipart parsing error: Multipart: No boundaries found in payload./, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -1262,11 +1262,11 @@ SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,id:500130" ), match_log => { - debug => [ qr/Invalid boundary in C-T \(characters\)/, 1 ], + debug => [ qr/Multipart parsing error: Multipart: No boundaries found in payload./, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -1404,7 +1404,7 @@ SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny,id:500139" ), match_log => { - debug => [ qr/boundary was quoted.*No boundaries found in payload/s, 1 ], + error => [ qr/Multipart parsing error \(init\): Multipart: Invalid boundary in C-T \(characters\)./s, 1 ], }, match_response => { status => qr/^403$/, From bc01714ca114d74349c7cf8f36a92aa30b31c119 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 16:11:24 +0200 Subject: [PATCH 401/470] Fix status engine tests --- tests/regression/misc/20-status-engine.t | 194 +++++++++++------------ 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/tests/regression/misc/20-status-engine.t b/tests/regression/misc/20-status-engine.t index a8ec6f3e03..e0cef4a293 100644 --- a/tests/regression/misc/20-status-engine.t +++ b/tests/regression/misc/20-status-engine.t @@ -1,28 +1,28 @@ ### Test the SecStatusEngine -# On -{ - type => "misc", - comment => "Setting SecStatusEngine to On", - conf => qq( - SecRuleEngine On - SecStatusEngine On - ), - match_log => { - error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], - -error => [ qr/Status engine is currently disabled, enable it by set SecStatusEngine to On/, 1], - }, - 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", - ], - "arg1=val1&arg2=val2", - ), -}, +## On +#{ +# type => "misc", +# comment => "Setting SecStatusEngine to On", +# conf => qq( +# SecRuleEngine On +# SecStatusEngine On +# ), +# match_log => { +# error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], +# -error => [ qr/Status engine is currently disabled, enable it by set SecStatusEngine to On/, 1], +# }, +# 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", +# ], +# "arg1=val1&arg2=val2", +# ), +#}, # Off { type => "misc", @@ -46,78 +46,78 @@ "arg1=val1&arg2=val2", ), }, -# On and SecServerSignature -{ - type => "misc", - comment => "SecStatusEngine On using SecServerSignature", - conf => qq( - SecRuleEngine On - SecServerSignature "SpiderServer v0.1a" - SecStatusEngine On - ), - match_log => { - error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], - -error => [ qr/StatusEngine call: .*SpiderServer v0.1a.*/, 1], - }, - 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", - ], - "arg1=val1&arg2=val2", - ), -}, -# On and SecServerSignature -{ - type => "misc", - comment => "SecStatusEngine On/SecServerSignature - checking signature", - conf => qq( - SecRuleEngine On - SecServerSignature "SpiderServer v0.1a" - SecStatusEngine On - ), - match_log => { - error => { - apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], - nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], - } - }, - 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", - ], - "arg1=val1&arg2=val2", - ), -}, -# On and SecServerSignature -{ - type => "misc", - comment => "SecStatusEngine On - checking signature", - conf => qq( - SecStatusEngine On - ), - match_log => { - error => { - apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], - nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], - } - }, - 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", - ], - "arg1=val1&arg2=val2", - ), -}, +## On and SecServerSignature +#{ +# type => "misc", +# comment => "SecStatusEngine On using SecServerSignature", +# conf => qq( +# SecRuleEngine On +# SecServerSignature "SpiderServer v0.1a" +# SecStatusEngine On +# ), +# match_log => { +# error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], +# -error => [ qr/StatusEngine call: .*SpiderServer v0.1a.*/, 1], +# }, +# 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", +# ], +# "arg1=val1&arg2=val2", +# ), +#}, +## On and SecServerSignature +#{ +# type => "misc", +# comment => "SecStatusEngine On/SecServerSignature - checking signature", +# conf => qq( +# SecRuleEngine On +# SecServerSignature "SpiderServer v0.1a" +# SecStatusEngine On +# ), +# match_log => { +# error => { +# apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], +# nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], +# } +# }, +# 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", +# ], +# "arg1=val1&arg2=val2", +# ), +#}, +## On and SecServerSignature +#{ +# type => "misc", +# comment => "SecStatusEngine On - checking signature", +# conf => qq( +# SecStatusEngine On +# ), +# match_log => { +# error => { +# apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], +# nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], +# } +# }, +# 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", +# ], +# "arg1=val1&arg2=val2", +# ), +#}, From 1362a30e93f27105e062eb546b9e79d7059cfc36 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 16:14:06 +0200 Subject: [PATCH 402/470] Fix SecRemoteRules test - that's need anymore --- tests/regression/misc/40-secRemoteRules.t.in | 84 ++++++++++---------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/tests/regression/misc/40-secRemoteRules.t.in b/tests/regression/misc/40-secRemoteRules.t.in index 93acd7316d..ee44777108 100644 --- a/tests/regression/misc/40-secRemoteRules.t.in +++ b/tests/regression/misc/40-secRemoteRules.t.in @@ -1,43 +1,45 @@ ### SecRemoteRules - -{ - type => "misc", - comment => "SecRemoteRules load", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" - ), - match_log => { - error => [ qr/ModSecurity: Loaded 1 rule/, 1], - }, -}, -{ - type => "misc", - comment => "SecRemoteRules apply some remote rules", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" - ), - match_log => { - error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], - debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, +# probably no need these anymore +# plus it's hard to set up an infrastucture +# +#{ +# type => "misc", +# comment => "SecRemoteRules load", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" +# ), +# match_log => { +# error => [ qr/ModSecurity: Loaded 1 rule/, 1], +# }, +#}, +#{ +# type => "misc", +# comment => "SecRemoteRules apply some remote rules", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" +# ), +# match_log => { +# error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], +# debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, From 780304caf437dfa3cb340fa4e74cd67c5e37ab5a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 16:19:26 +0200 Subject: [PATCH 403/470] Fix ipmatchfromfile external tests - temporary suspended all tests --- .../misc/50-ipmatchfromfile-external.t.in | 140 +++++++++--------- 1 file changed, 71 insertions(+), 69 deletions(-) diff --git a/tests/regression/misc/50-ipmatchfromfile-external.t.in b/tests/regression/misc/50-ipmatchfromfile-external.t.in index 6b674cabd0..c3f9f02476 100644 --- a/tests/regression/misc/50-ipmatchfromfile-external.t.in +++ b/tests/regression/misc/50-ipmatchfromfile-external.t.in @@ -1,71 +1,73 @@ ### ipMatchFromFile external resource - -{ - type => "misc", - comment => "ipMatchFromFile", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:10500,pass" - ), - match_log => { - error => [ qr/ModSecurity: Warning. IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1], - debug => [ qr/IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1 ], - -error => [ qr/ModSecurity: Problems loading external resources:/, 1], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, -{ - type => "misc", - comment => "ipMatchFromFile - 404 download", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRulesFailAction Warn - SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:10500,pass" - ), - match_log => { - error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, -{ - type => "misc", - comment => "ipMatchFromFile - bad certificate name", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRulesFailAction Warn - 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.|Couldn't connect to server.]/, 1], - }, -}, +# no infrasturcure to test +# +# permanently suspended +#{ +# type => "misc", +# comment => "ipMatchFromFile", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:10500,pass" +# ), +# match_log => { +# error => [ qr/ModSecurity: Warning. IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1], +# debug => [ qr/IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1 ], +# -error => [ qr/ModSecurity: Problems loading external resources:/, 1], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, +#{ +# type => "misc", +# comment => "ipMatchFromFile - 404 download", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRulesFailAction Warn +# SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:10500,pass" +# ), +# match_log => { +# error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, +#{ +# type => "misc", +# comment => "ipMatchFromFile - bad certificate name", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRulesFailAction Warn +# 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.|Couldn't connect to server.]/, 1], +# }, +#}, From 63af83080c952b187764c73f660fed5c3dc61c21 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 16:22:29 +0200 Subject: [PATCH 404/470] Fix pmfromfile external tests - temporary suspended all tests --- .../misc/60-pmfromfile-external.t.in | 166 +++++++++--------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/tests/regression/misc/60-pmfromfile-external.t.in b/tests/regression/misc/60-pmfromfile-external.t.in index 2910ed11b9..f16340a6dd 100644 --- a/tests/regression/misc/60-pmfromfile-external.t.in +++ b/tests/regression/misc/60-pmfromfile-external.t.in @@ -1,84 +1,86 @@ ### pmfromfile external resource - -{ - type => "misc", - comment => "pmfromfile", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" - ), - match_log => { - error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], - debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], - -error => [ qr/ModSecurity: Problems loading external resources:/, 1], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, -{ - type => "misc", - comment => "pmfromfile - 404 download", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRulesFailAction Warn - SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:'123',phase:2,log,pass,t:none" - - ), - match_log => { - error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, -{ - type => "misc", - comment => "pmfromfile - bad certificate name", - conf => qq( - SecRuleEngine On - SecDebugLog $ENV{DEBUG_LOG} - SecDebugLogLevel 9 - SecRequestBodyAccess On - SecRemoteRulesFailAction Warn - SecRule REQUEST_FILENAME "\@pmFromFile https://status.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" - - ), - 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.|Couldn't connect to server.]/, 1], - }, - match_response => { - status => qr/^404$/, - }, - request => new HTTP::Request( - POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", - [ - "Content-Type" => "application/x-www-form-urlencoded", - ], - # Args - "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" - ), -}, +# all tests need an external infrastructure +# termporary suspended +# +#{ +# type => "misc", +# comment => "pmfromfile", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" +# ), +# match_log => { +# error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], +# debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], +# -error => [ qr/ModSecurity: Problems loading external resources:/, 1], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, +#{ +# type => "misc", +# comment => "pmfromfile - 404 download", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRulesFailAction Warn +# SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:'123',phase:2,log,pass,t:none" +# +# ), +# match_log => { +# error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, +#{ +# type => "misc", +# comment => "pmfromfile - bad certificate name", +# conf => qq( +# SecRuleEngine On +# SecDebugLog $ENV{DEBUG_LOG} +# SecDebugLogLevel 9 +# SecRequestBodyAccess On +# SecRemoteRulesFailAction Warn +# SecRule REQUEST_FILENAME "\@pmFromFile https://status.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" +# +# ), +# 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.|Couldn't connect to server.]/, 1], +# }, +# match_response => { +# status => qr/^404$/, +# }, +# request => new HTTP::Request( +# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", +# [ +# "Content-Type" => "application/x-www-form-urlencoded", +# ], +# # Args +# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" +# ), +#}, From c7cacf80f21b6dba268c9c8878a7665e633a75ec Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 17:21:44 +0200 Subject: [PATCH 405/470] Fix xml processing tests --- tests/regression/rule/10-xml.t | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tests/regression/rule/10-xml.t b/tests/regression/rule/10-xml.t index f2632745b7..ad1ed91941 100644 --- a/tests/regression/rule/10-xml.t +++ b/tests/regression/rule/10-xml.t @@ -169,13 +169,13 @@ phase:2,deny,id:12345" ), match_log => { - debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ], - -debug => [ qr/Failed to load|Successfully validated/, 1 ], - -error => [ qr/Failed to load|Successfully validated/, 1 ], - audit => [ qr/^Message: .*Failed parsing document.*\nMessage:/m, 1 ], + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error: XML: Failed to parse document./s, 1 ], + debug => [ qr/XML parser error: XML: Failed to parse document./, 1 ], + error => [ qr/XML parser error: XML: Failed to parse document./, 1 ], + audit => [ qr/XML parser error: XML: Failed to parse document./m, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", @@ -350,6 +350,8 @@ SecXmlExternalEntity On SecDebugLog $ENV{DEBUG_LOG} SecDebugLogLevel 9 + SecAuditEngine RelevantOnly + SecAuditLog "$ENV{AUDIT_LOG}" SecRule REQUEST_HEADERS:Content-Type "^text/xml\$" "id:500026, \\ phase:1,t:none,t:lowercase,nolog,pass,ctl:requestBodyProcessor=XML" SecRule REQBODY_PROCESSOR "!^XML\$" nolog,pass,skipAfter:12345,id:500027 @@ -357,12 +359,12 @@ phase:2,deny,id:12345" ), match_log => { - debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error.*validation failed because content is not well formed/s, 1 ], - -debug => [ qr/Failed to load|Successfully validated/, 1 ], - -error => [ qr/Failed to load|Successfully validated/, 1 ], + debug => [ qr/XML: Initialising parser.*XML: Parsing complete \(well_formed 0\).*XML parser error: XML: Failed to parse document./s, 1 ], + debug => [ qr/XML parser error: XML: Failed to parse document./, 1 ], + audit => [ qr/^Message: .*Failed to parse document.*\nMessage:/m, 1 ], }, match_response => { - status => qr/^403$/, + status => qr/^500$/, }, request => new HTTP::Request( POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt", From b6d14b7fce80b3f686e0b31296b7d1ff9949b6fb Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 17:38:37 +0200 Subject: [PATCH 406/470] Add necessary arguments to perl test script --- tests/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 130bdba398..181a5aa7ed 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -80,7 +80,7 @@ TESTS = $(check_SCRIPTS) test: check test-regression: run-regression-tests.pl - $(PERL) run-regression-tests.pl + $(PERL) run-regression-tests.pl -S . test-regression-nginx: run-regression-tests-nginx.pl $(PERL) run-regression-tests-nginx.pl From c964f9cbf685295f28b2ba0112b37f721b3f7d8e Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 21:51:51 +0200 Subject: [PATCH 407/470] Remove unused tests --- tests/regression/misc/20-status-engine.t | 123 ------------------ tests/regression/misc/40-secRemoteRules.t.in | 45 ------- .../misc/50-ipmatchfromfile-external.t.in | 73 ----------- .../misc/60-pmfromfile-external.t.in | 86 ------------ 4 files changed, 327 deletions(-) delete mode 100644 tests/regression/misc/20-status-engine.t delete mode 100644 tests/regression/misc/40-secRemoteRules.t.in delete mode 100644 tests/regression/misc/50-ipmatchfromfile-external.t.in delete mode 100644 tests/regression/misc/60-pmfromfile-external.t.in diff --git a/tests/regression/misc/20-status-engine.t b/tests/regression/misc/20-status-engine.t deleted file mode 100644 index e0cef4a293..0000000000 --- a/tests/regression/misc/20-status-engine.t +++ /dev/null @@ -1,123 +0,0 @@ -### Test the SecStatusEngine - -## On -#{ -# type => "misc", -# comment => "Setting SecStatusEngine to On", -# conf => qq( -# SecRuleEngine On -# SecStatusEngine On -# ), -# match_log => { -# error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], -# -error => [ qr/Status engine is currently disabled, enable it by set SecStatusEngine to On/, 1], -# }, -# 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", -# ], -# "arg1=val1&arg2=val2", -# ), -#}, -# Off -{ - type => "misc", - comment => "Setting SecStatusEngine to Off", - conf => qq( - SecRuleEngine On - SecStatusEngine Off - ), - match_log => { - -error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], - error => [ qr/Status engine is currently disabled, enable it by set SecStatusEngine to On/, 1], - }, - 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", - ], - "arg1=val1&arg2=val2", - ), -}, -## On and SecServerSignature -#{ -# type => "misc", -# comment => "SecStatusEngine On using SecServerSignature", -# conf => qq( -# SecRuleEngine On -# SecServerSignature "SpiderServer v0.1a" -# SecStatusEngine On -# ), -# match_log => { -# error => [ qr/ModSecurity: StatusEngine call successfully sent/, 1], -# -error => [ qr/StatusEngine call: .*SpiderServer v0.1a.*/, 1], -# }, -# 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", -# ], -# "arg1=val1&arg2=val2", -# ), -#}, -## On and SecServerSignature -#{ -# type => "misc", -# comment => "SecStatusEngine On/SecServerSignature - checking signature", -# conf => qq( -# SecRuleEngine On -# SecServerSignature "SpiderServer v0.1a" -# SecStatusEngine On -# ), -# match_log => { -# error => { -# apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], -# nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], -# } -# }, -# 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", -# ], -# "arg1=val1&arg2=val2", -# ), -#}, -## On and SecServerSignature -#{ -# type => "misc", -# comment => "SecStatusEngine On - checking signature", -# conf => qq( -# SecStatusEngine On -# ), -# match_log => { -# error => { -# apache => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,Apache/, 1], -# nginx => [ qr/StatusEngine call: \"[0-9]+.[0-9]+.[0-9]+[-RC]*[0-9]*\,nginx/, 1], -# } -# }, -# 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", -# ], -# "arg1=val1&arg2=val2", -# ), -#}, - diff --git a/tests/regression/misc/40-secRemoteRules.t.in b/tests/regression/misc/40-secRemoteRules.t.in deleted file mode 100644 index ee44777108..0000000000 --- a/tests/regression/misc/40-secRemoteRules.t.in +++ /dev/null @@ -1,45 +0,0 @@ -### SecRemoteRules -# probably no need these anymore -# plus it's hard to set up an infrastucture -# -#{ -# type => "misc", -# comment => "SecRemoteRules load", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" -# ), -# match_log => { -# error => [ qr/ModSecurity: Loaded 1 rule/, 1], -# }, -#}, -#{ -# type => "misc", -# comment => "SecRemoteRules apply some remote rules", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRules 123 "https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt" -# ), -# match_log => { -# error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], -# debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, - diff --git a/tests/regression/misc/50-ipmatchfromfile-external.t.in b/tests/regression/misc/50-ipmatchfromfile-external.t.in deleted file mode 100644 index c3f9f02476..0000000000 --- a/tests/regression/misc/50-ipmatchfromfile-external.t.in +++ /dev/null @@ -1,73 +0,0 @@ -### ipMatchFromFile external resource -# no infrasturcure to test -# -# permanently suspended -#{ -# type => "misc", -# comment => "ipMatchFromFile", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:10500,pass" -# ), -# match_log => { -# error => [ qr/ModSecurity: Warning. IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1], -# debug => [ qr/IPmatchFromFile: \"127.0.0.1\" matched at REMOTE_ADDR./, 1 ], -# -error => [ qr/ModSecurity: Problems loading external resources:/, 1], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, -#{ -# type => "misc", -# comment => "ipMatchFromFile - 404 download", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRulesFailAction Warn -# SecRule REMOTE_ADDR "\@ipMatchFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:10500,pass" -# ), -# match_log => { -# error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, -#{ -# type => "misc", -# comment => "ipMatchFromFile - bad certificate name", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRulesFailAction Warn -# 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.|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 deleted file mode 100644 index f16340a6dd..0000000000 --- a/tests/regression/misc/60-pmfromfile-external.t.in +++ /dev/null @@ -1,86 +0,0 @@ -### pmfromfile external resource -# all tests need an external infrastructure -# termporary suspended -# -#{ -# type => "misc", -# comment => "pmfromfile", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" -# ), -# match_log => { -# error => [ qr/ModSecurity: Warning. Matched phrase \"127.0.0.1\" at REQUEST_FILENAME./, 1], -# debug => [ qr/Matched phrase \"127.0.0.1\" at REQUEST_FILENAME/, 1 ], -# -error => [ qr/ModSecurity: Problems loading external resources:/, 1], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, -#{ -# type => "misc", -# comment => "pmfromfile - 404 download", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRulesFailAction Warn -# SecRule REQUEST_FILENAME "\@pmFromFile https://www.modsecurity.org/modsecurity-regression-test-404.txt" "id:'123',phase:2,log,pass,t:none" -# -# ), -# match_log => { -# error => [ qr/ModSecurity: Problems loading external resources: Failed to download: \"https:\/\/www.modsecurity.org\/modsecurity-regression-test-404.txt\" error: HTTP response code said error./, 1], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, -#{ -# type => "misc", -# comment => "pmfromfile - bad certificate name", -# conf => qq( -# SecRuleEngine On -# SecDebugLog $ENV{DEBUG_LOG} -# SecDebugLogLevel 9 -# SecRequestBodyAccess On -# SecRemoteRulesFailAction Warn -# SecRule REQUEST_FILENAME "\@pmFromFile https://status.modsecurity.org/modsecurity-regression-test.txt" "id:'123',phase:2,log,pass,t:none" -# -# ), -# 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.|Couldn't connect to server.]/, 1], -# }, -# match_response => { -# status => qr/^404$/, -# }, -# request => new HTTP::Request( -# POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/127.0.0.1.html", -# [ -# "Content-Type" => "application/x-www-form-urlencoded", -# ], -# # Args -# "some_variable=-1' and 1=1 union/* foo */select load_file('/etc/passwd')--" -# ), -#}, - From cb107a75266a5355090549d93f656d49126b351a Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 21:59:24 +0200 Subject: [PATCH 408/470] Add non-versioned files to .gitignore --- .gitignore | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3391ea5134..869c7f2c60 100644 --- a/.gitignore +++ b/.gitignore @@ -108,4 +108,16 @@ m4/lt~obsolete.m4 Makefile # IDEs -.idea \ No newline at end of file +.idea + +# tests +tests/regression/server_root/conf/*t*.conf +tests/regression/server_root/upload/*-file-* +tests/regression/server_root/data/*-ip.* +tests/regression/server_root/logs/*.log +tests/regression/server_root/logs/audit/*/ +tests/*.pl +tests/*.trs +tests/*.log + + From 30f90a4d5c4ba136431d4ed5d98220ea5b1967ac Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Mon, 28 Jul 2025 22:04:31 +0200 Subject: [PATCH 409/470] Remove unwanted tests from configure.ac --- build/compile | 11 +++++++---- configure.ac | 3 --- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/build/compile b/build/compile index df363c8fbf..49b3d05fde 100755 --- a/build/compile +++ b/build/compile @@ -1,9 +1,9 @@ #! /bin/sh # Wrapper for compilers which do not understand '-c -o'. -scriptversion=2018-03-07.03; # UTC +scriptversion=2024-06-19.01; # UTC -# Copyright (C) 1999-2021 Free Software Foundation, Inc. +# Copyright (C) 1999-2024 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify @@ -143,7 +143,7 @@ func_cl_wrapper () # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in - *.o | *.[oO][bB][jJ]) + *.o | *.lo | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift @@ -248,14 +248,17 @@ If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . +GNU Automake home page: . +General help using GNU software: . EOF exit $? ;; -v | --v*) - echo "compile $scriptversion" + echo "compile (GNU Automake) $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ + clang-cl | *[/\\]clang-cl | clang-cl.exe | *[/\\]clang-cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; diff --git a/configure.ac b/configure.ac index 69228a6b93..7103729163 100644 --- a/configure.ac +++ b/configure.ac @@ -946,9 +946,6 @@ 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]) From fb4a3468f6aace5091f8561146044aac74216565 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 29 Jul 2025 09:24:11 +0200 Subject: [PATCH 410/470] Update .gitignore Co-authored-by: Max Leske <250711+theseion@users.noreply.github.com> --- .gitignore | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 869c7f2c60..d8d6784f63 100644 --- a/.gitignore +++ b/.gitignore @@ -111,11 +111,7 @@ Makefile .idea # tests -tests/regression/server_root/conf/*t*.conf -tests/regression/server_root/upload/*-file-* -tests/regression/server_root/data/*-ip.* -tests/regression/server_root/logs/*.log -tests/regression/server_root/logs/audit/*/ +tests/regression/server_root/** tests/*.pl tests/*.trs tests/*.log From dfbde557acc41d858dbe04d4b6eaec64478347ff Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Wed, 30 Jul 2025 10:55:33 +0200 Subject: [PATCH 411/470] Fix invalid request handling --- apache2/apache2_io.c | 48 +++++++++++++++++----------------- apache2/mod_security2.c | 57 ++++++----------------------------------- 2 files changed, 32 insertions(+), 73 deletions(-) diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 405b649ae4..8deeb01c9a 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -192,27 +192,29 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: This request does not have a body."); } - return 0; + return APR_SUCCESS; } if (msr->txcfg->reqbody_access != 1) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Request body access not enabled."); } - return 0; + return APR_SUCCESS; } 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; + return HTTP_INTERNAL_SERVER_ERROR; } 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; + if (bb_in == NULL) { + return HTTP_INTERNAL_SERVER_ERROR; + } do { apr_status_t rc; @@ -222,25 +224,17 @@ 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; - case APR_TIMEUP : - *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); - return -4; case AP_FILTER_ERROR : *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)"); - return -3; + break; case APR_EGENERAL : *error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away."); - return -2; + break; default : *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); - return -1; + break; } + return ap_map_http_request_error(rc, HTTP_BAD_REQUEST); } /* Loop through the buckets in the brigade in order @@ -256,7 +250,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ); if (rc != APR_SUCCESS) { *error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc)); - return -1; + return HTTP_INTERNAL_SERVER_ERROR; } if (msr->txcfg->debuglog_level >= 9) { @@ -269,7 +263,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " "configured limit (%ld).", msr->txcfg->reqbody_limit); - return -5; + return HTTP_REQUEST_ENTITY_TOO_LARGE; } else if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) { *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " @@ -290,7 +284,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " "configured limit (%ld).", msr->txcfg->reqbody_limit); - return -5; + return HTTP_REQUEST_ENTITY_TOO_LARGE; } } @@ -300,7 +294,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { 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; + return HTTP_INTERNAL_SERVER_ERROR; } #endif } @@ -319,7 +313,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { *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); - return -5; + return HTTP_REQUEST_ENTITY_TOO_LARGE; } else if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) { *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); @@ -329,12 +323,12 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } else { *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); - return -5; + return HTTP_REQUEST_ENTITY_TOO_LARGE; } } if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) - return -1; + return HTTP_INTERNAL_SERVER_ERROR; } } @@ -357,7 +351,13 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { msr->if_status = IF_STATUS_WANTS_TO_RUN; - return rcbe; + if (rcbe == -5) { + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + if (rcbe < 0) { + return HTTP_INTERNAL_SERVER_ERROR; + } + return APR_SUCCESS; } diff --git a/apache2/mod_security2.c b/apache2/mod_security2.c index 0dcb6b3e75..97c49646bc 100644 --- a/apache2/mod_security2.c +++ b/apache2/mod_security2.c @@ -1032,56 +1032,15 @@ static int hook_request_late(request_rec *r) { } rc = read_request_body(msr, &my_error_msg); - if (rc < 0 && msr->txcfg->is_enabled == MODSEC_ENABLED) { - switch(rc) { - case -1 : - if (my_error_msg != NULL) { - msr_log(msr, 1, "%s", my_error_msg); - } - return HTTP_INTERNAL_SERVER_ERROR; - break; - case -4 : /* Timeout. */ - if (my_error_msg != NULL) { - msr_log(msr, 4, "%s", my_error_msg); - } - r->connection->keepalive = AP_CONN_CLOSE; - return HTTP_REQUEST_TIME_OUT; - break; - case -5 : /* Request body limit reached. */ - msr->inbound_error = 1; - if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { - r->connection->keepalive = AP_CONN_CLOSE; - if (my_error_msg != NULL) { - msr_log(msr, 1, "%s. Deny with code (%d)", my_error_msg, HTTP_REQUEST_ENTITY_TOO_LARGE); - } - return HTTP_REQUEST_ENTITY_TOO_LARGE; - } else { - if (my_error_msg != NULL) { - msr_log(msr, 1, "%s", my_error_msg); - } - } - break; - case -6 : /* EOF when reading request body. */ - if (my_error_msg != NULL) { - msr_log(msr, 4, "%s", my_error_msg); - } - 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; + if (rc != OK) { + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); } - - msr->msc_reqbody_error = 1; - msr->msc_reqbody_error_msg = my_error_msg; + if (rc == HTTP_REQUEST_ENTITY_TOO_LARGE) { + msr->inbound_error = 1; + } + r->connection->keepalive = AP_CONN_CLOSE; + return rc; } /* Update the request headers. They might have changed after From 18cae5003a7160792a2e96000a9d6bd07cdf7ee2 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 5 Aug 2025 21:13:58 +0200 Subject: [PATCH 412/470] Change release version to v2.9.12 --- CHANGES | 10 ++++++++++ apache2/msc_release.h | 2 +- iis/installer.wxs | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index d2282ac9eb..4cf9c09356 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,13 @@ +05 Aug 2025 - 2.9.12 +-------------------- + + * fix: Improper error handling + [PR from private repo - @orangetw, @pgajdos, @ylavic, @theseion, @fzipi, @airween + fixed CVE-2025-54571] + * fix: mod_security2's regression tests [Issue #3425 - @airween] + * fix: remove unused condition from msc_status_engine.c [Issue #3412 - @airween] + * fix: remove unwanted '\0' string terminator from argument's value [Issue #3411 - @airween] + 01 Jul 2025 - 2.9.11 -------------------- diff --git a/apache2/msc_release.h b/apache2/msc_release.h index 658e61595a..e496dc6659 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 "11" +#define MODSEC_VERSION_MAINT "12" #define MODSEC_VERSION_TYPE "" #define MODSEC_VERSION_RELEASE "" diff --git a/iis/installer.wxs b/iis/installer.wxs index bb9e4a4b82..6189e6b892 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + From 0d99f076b0c4a76051b4d3256359e298c1f5a332 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Thu, 28 Aug 2025 23:46:26 +0800 Subject: [PATCH 413/470] Add event message resource for IIS and update build/installation - Added ModSecurityIISMessage.mc message resource file for event source metadata - Updated Makefile.win to compile .mc to .res resource file and link into ModSecurityIIS.dll - Modified installer.wxs to register event source pointing to ModSecurityIIS.dll --- iis/Makefile.win | 15 +++++++++++++-- iis/ModSecurityIISMessage.mc | 5 +++++ iis/installer.wxs | 6 ++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 iis/ModSecurityIISMessage.mc diff --git a/iis/Makefile.win b/iis/Makefile.win index d07f795ad9..635e2c2034 100644 --- a/iis/Makefile.win +++ b/iis/Makefile.win @@ -85,6 +85,8 @@ OBJS4 = libinjection_html5.obj \ libinjection_sqli.obj \ libinjection_xss.obj +OBJS5 = ModSecurityIISMessage.res + all: $(DLL) dll: $(DLL) @@ -101,12 +103,21 @@ $(OBJS2): ..\standalone\$*.c .cpp.obj: $(CC) $(CFLAGS) -c $< -Fo$@ -$(DLL): $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) - $(LINK) $(LDFLAGS) $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(LIBS) +$(DLL): $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) + $(LINK) $(LDFLAGS) $(OBJS1) $(OBJS2) $(OBJS3) $(OBJS4) $(OBJS5) $(LIBS) IF EXIST $(DLL).manifest $(MT) -manifest $(DLL).manifest -outputresource:$(DLL);#1 +$(OBJS5): ModSecurityIISMessage.rc + rc /r ModSecurityIISMessage.rc + +ModSecurityIISMessage.rc: ModSecurityIISMessage.mc + mc -U ModSecurityIISMessage.mc + clean: del /f *.obj del /f *.dll del /f *.exp del /f *.lib + del /f *.rc + del /f *.bin + del /f *.res diff --git a/iis/ModSecurityIISMessage.mc b/iis/ModSecurityIISMessage.mc new file mode 100644 index 0000000000..49106bfa74 --- /dev/null +++ b/iis/ModSecurityIISMessage.mc @@ -0,0 +1,5 @@ +MessageId=0x1 +Language=English +%1 +. + diff --git a/iis/installer.wxs b/iis/installer.wxs index 6189e6b892..9197a733bf 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -402,6 +402,9 @@ Source="Release\amd64\zlib1.dll" /> + + Date: Fri, 29 Aug 2025 04:20:20 +0800 Subject: [PATCH 414/470] adjust Makefile indentation --- iis/Makefile.win | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iis/Makefile.win b/iis/Makefile.win index 635e2c2034..04df4fb430 100644 --- a/iis/Makefile.win +++ b/iis/Makefile.win @@ -118,6 +118,6 @@ clean: del /f *.dll del /f *.exp del /f *.lib - del /f *.rc - del /f *.bin - del /f *.res + del /f *.rc + del /f *.bin + del /f *.res From 336ef3990887e50a4351e123d97ef5e07d063506 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 01:23:08 +0800 Subject: [PATCH 415/470] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20CI/CD=20=E5=B7=A5?= =?UTF-8?q?=E4=BD=9C=E6=B5=81=E5=92=8C=20CMake=20=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=20IIS=20=E6=A8=A1=E5=9D=97=E6=9E=84?= =?UTF-8?q?=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/test-ci-windows.yml | 69 ++++++ iis/CMakeLists.txt | 330 ++++++++++++++++++++++++++ iis/vcpkg.json | 9 + 3 files changed, 408 insertions(+) create mode 100644 .github/workflows/test-ci-windows.yml create mode 100644 iis/CMakeLists.txt create mode 100644 iis/vcpkg.json diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml new file mode 100644 index 0000000000..7abe75eebf --- /dev/null +++ b/.github/workflows/test-ci-windows.yml @@ -0,0 +1,69 @@ +name: CI/CD for IIS Module + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: > + git + make + autoconf + automake + libtool + mingw-w64-ucrt-x86_64-gcc + mingw-w64-ucrt-x86_64-pkg-config + + - name: Clone and build ssdeep + shell: msys2 {0} + run: | + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + cd ssdeep + autoreconf -i + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + make dll + mkdir -p ${{ github.workspace }}/ssdeep-install/bin + mkdir -p ${{ github.workspace }}/ssdeep-install/include + cp fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ + cp fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ + cp fuzzy.def ${{ github.workspace }}/ssdeep-install/ + + - name: Configure CMake for IIS Module + run: | + cmake \ + -DAPACHE_ROOT="C:/tools/Apache24" \ + -DSSDEEP_ROOT="${{ github.workspace }}/ssdeep-install" \ + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install" \ + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" \ + -DWITH_SSDEEP=ON \ + -DWITH_LUA=ON \ + -DWITH_YAJL=ON \ + -S IIS -B iis/build + + - name: Build IIS Module + shell: pwsh + run: | + cmake --build iis/build --config Release + + # - name: Package IIS Module with WiX + # shell: pwsh + # run: | + # $CURRENT_DIR = "${{ github.workspace }}/iis/wix" + # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 + # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-64.msi" \ No newline at end of file diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt new file mode 100644 index 0000000000..11ebd1f92c --- /dev/null +++ b/iis/CMakeLists.txt @@ -0,0 +1,330 @@ +cmake_minimum_required(VERSION 3.15) +project(ModSecurityIIS C CXX) + +find_package(LibXml2 CONFIG REQUIRED) +find_package(PCRE2 CONFIG REQUIRED) +find_package(CURL CONFIG REQUIRED) + +# iis/CMakeLists.txt +set(IIS_MODULE_NAME "modsecurityiis") # Name should match the original output + +# Source files for IIS module (reusing Apache sources) +set(IIS_APACHE_SOURCES + ../apache2/mod_security2.c + ../apache2/apache2_config.c + ../apache2/apache2_io.c + ../apache2/apache2_util.c + ../apache2/re.c + ../apache2/re_operators.c + ../apache2/re_actions.c + ../apache2/re_tfns.c + ../apache2/re_variables.c + ../apache2/msc_logging.c + ../apache2/msc_xml.c + ../apache2/msc_multipart.c + ../apache2/modsecurity.c + ../apache2/msc_parsers.c + ../apache2/msc_util.c + ../apache2/msc_pcre.c + ../apache2/persist_dbm.c + ../apache2/msc_reqbody.c + ../apache2/msc_geo.c + ../apache2/msc_gsb.c + ../apache2/msc_crypt.c + ../apache2/msc_tree.c + ../apache2/msc_unicode.c + ../apache2/acmp.c + ../apache2/msc_lua.c + ../apache2/msc_release.c + ../apache2/msc_status_engine.c + ../apache2/msc_remote_rules.c + ../apache2/msc_json.c + ../apache2/libinjection/libinjection_html5.c + ../apache2/libinjection/libinjection_sqli.c + ../apache2/libinjection/libinjection_xss.c +) + +# Source files for standalone components (if they exist in the project) +set(IIS_STANDALONE_SOURCES + ../standalone/api.c + ../standalone/buckets.c + ../standalone/config.c + ../standalone/filters.c + ../standalone/hooks.c + ../standalone/regex.c + ../standalone/server.c +) + +# Source files for IIS-specific components +set(IIS_MODULE_SOURCES + main.cpp + moduleconfig.cpp + mymodule.cpp +) + + +# Determine architecture +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCHITECTURE "x64") +else() + set(ARCHITECTURE "x86") +endif() + +# Check if standalone directory exists, if not, exclude those sources +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) + set(IIS_STANDALONE_SOURCES "") +endif() + +set(IIS_RESOURCE_MC "${CMAKE_CURRENT_SOURCE_DIR}/ModSecurityIISMessage.mc") + +set(MC_GENERATED_RC "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.rc") +set(MC_GENERATED_H "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.h") +add_custom_command( + OUTPUT ${MC_GENERATED_RC} ${MC_GENERATED_H} + COMMAND mc.exe + ARGS -U -h "${CMAKE_CURRENT_BINARY_DIR}/" -r "${CMAKE_CURRENT_BINARY_DIR}/" "${IIS_RESOURCE_MC}" + DEPENDS "${IIS_RESOURCE_MC}" + COMMENT "Generating resource files from ${IIS_RESOURCE_MC}" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +set(MC_GENERATED_RES "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.res") +add_custom_command( + OUTPUT ${MC_GENERATED_RES} + COMMAND rc.exe + ARGS /fo "${MC_GENERATED_RES}" "${MC_GENERATED_RC}" + DEPENDS ${MC_GENERATED_RC} + COMMENT "Building resource file: ${MC_GENERATED_RES}" +) + +set_source_files_properties( + ${MC_GENERATED_RC} + ${MC_GENERATED_H} + ${MC_GENERATED_RES} + PROPERTIES GENERATED TRUE +) + +add_library(${IIS_MODULE_NAME} SHARED + ${IIS_APACHE_SOURCES} + ${IIS_STANDALONE_SOURCES} + ${IIS_MODULE_SOURCES} + ${MC_GENERATED_RES} +) + +# Set the output name and extension +set_target_properties(${IIS_MODULE_NAME} PROPERTIES + OUTPUT_NAME ${IIS_MODULE_NAME} + PREFIX "" + SUFFIX ".dll" +) + +# Include directories +target_include_directories(${IIS_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../apache2 + ${CMAKE_CURRENT_SOURCE_DIR}/../apache2/libinjection + ${LIBXML2_INCLUDE_DIR}/libxml + ${PCRE_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} # 添加构建目录以访问生成的头文件 +) + +# Include standalone directory if it exists +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) + target_include_directories(${IIS_MODULE_NAME} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/../standalone + ) +endif() + +# Apache-specific includes +if(APACHE_ROOT) + target_include_directories(${IIS_MODULE_NAME} PRIVATE + ${APACHE_ROOT}/include + ) +endif() + +# Compile definitions to match the original Makefile.win +set(MODSECURITY_VERSION_FLAG "VERSION_IIS") # Define the version flag string +target_compile_definitions(${IIS_MODULE_NAME} PRIVATE + WIN32 + WINNT + inline=APR_INLINE + AP_DECLARE_STATIC + WITH_CURL + WITH_REMOTE_RULES + MSC_LARGE_STREAM_INPUT + WITH_YAJL + ${MODSECURITY_VERSION_FLAG} # Use the defined version flag +) + +option(WITH_LUA "Enable Lua support" OFF) +# Optional compile definitions +if(WITH_LUA) + find_package(Lua CONFIG REQUIRED) + target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_LUA) + target_include_directories(${IIS_MODULE_NAME} PRIVATE ${LUA_INCLUDE_DIR}) +endif() + +# Default Apache root based on architecture +if(NOT APACHE_ROOT) + if(ARCHITECTURE STREQUAL "x64") + set(APACHE_ROOT "C:/Apache24_x64" CACHE PATH "Path to Apache x64 installation") + else() + set(APACHE_ROOT "C:/Apache24_x86" CACHE PATH "Path to Apache x86 installation") + endif() +endif() + +option(WITH_YAJL "Enable YAJL support" OFF) +if(WITH_YAJL) + # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) + find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg_installed/${ARCHITECTURE}-windows/include" + NO_DEFAULT_PATH + ) + find_library(YAJL_LIBRARY NAMES yajl + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg_installed/${ARCHITECTURE}-windows/lib" + NO_DEFAULT_PATH + ) + + if(YAJL_INCLUDE_DIR AND YAJL_LIBRARY) + set(YAJL_INCLUDE_DIRS ${YAJL_INCLUDE_DIR}) + set(YAJL_LIBRARIES ${YAJL_LIBRARY}) + target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_YAJL) + target_include_directories(${IIS_MODULE_NAME} PRIVATE ${YAJL_INCLUDE_DIRS}) + else() + message(WARNING "YAJL not found. Please ensure yajl is installed via vcpkg in the iis/vcpkg_installed directory. Disabling YAJL support.") + option(WITH_YAJL "Enable YAJL support" OFF) # Disable if not found + endif() +endif() + +option(WITH_SSDEEP "Enable SSDEEP support" OFF) +if(WITH_SSDEEP) + + set(SSDEEP_ROOT "" CACHE PATH "Path to manually built ssdeep") + if(NOT SSDEEP_ROOT OR NOT EXISTS "${SSDEEP_ROOT}") + message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") + set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) + else() + message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") + + # 查找头文件 + find_path(SSDEEP_INCLUDE_DIR fuzzy.h + PATHS "${SSDEEP_ROOT}/include" + NO_DEFAULT_PATH + ) + + if(SSDEEP_INCLUDE_DIR) + message(STATUS "Found manually built ssdeep include: ${SSDEEP_INCLUDE_DIR}") + target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_SSDEEP) + target_include_directories(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_INCLUDE_DIR}) + + # 检查 fuzzy.def 文件是否存在 + set(SSDEEP_DEF_FILE "${SSDEEP_ROOT}/fuzzy.def") + if(NOT EXISTS "${SSDEEP_DEF_FILE}") + message(WARNING "fuzzy.def not found at ${SSDEEP_DEF_FILE}. Disabling SSDEEP support.") + set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) + else() + set(SSDEEP_GENERATED_LIB "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.lib") + + # 添加自定义命令生成 fuzzy.lib + add_custom_command( + OUTPUT ${SSDEEP_GENERATED_LIB} + COMMAND lib.exe /machine:${ARCHITECTURE} /def:${SSDEEP_DEF_FILE} /out:${SSDEEP_GENERATED_LIB} + DEPENDS "${SSDEEP_DEF_FILE}" + COMMENT "Generating SSDEEP .lib from .def for MSVC" + VERBATIM + ) + + # 确保自定义命令的输出被标记为生成文件 + set_source_files_properties(${SSDEEP_GENERATED_LIB} PROPERTIES GENERATED TRUE) + + # 添加自定义目标确保生成 fuzzy.lib + add_custom_target(generate_ssdeep_lib ALL + DEPENDS ${SSDEEP_GENERATED_LIB} + COMMENT "Ensuring ssdeep lib is generated" + ) + + # 使主目标依赖于 fuzzy.lib 的生成 + add_dependencies(${IIS_MODULE_NAME} generate_ssdeep_lib) + + endif() + else() + message(WARNING "SSDEEP include (fuzzy.h) not found at ${SSDEEP_ROOT}/include. Disabling SSDEEP support.") + set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) + endif() + endif() +endif() + +# Compiler-specific options for MSVC to match the original Makefile.win +if(MSVC) + target_compile_options(${IIS_MODULE_NAME} PRIVATE + /nologo + /O2 + /W3 + /wd4244 + /wd4018 + /MD + /Zi + ) + + # Linker options to match the original Makefile.win + set_target_properties(${IIS_MODULE_NAME} PROPERTIES + LINK_FLAGS "/DEBUG /OPT:REF /OPT:ICF" + ) +endif() + +# Link libraries to match the original Makefile.win +target_link_libraries(${IIS_MODULE_NAME} PRIVATE + LibXml2::LibXml2 + PCRE2::8BIT + CURL::libcurl + kernel32 + user32 + gdi32 + winspool + comdlg32 + advapi32 + shell32 + ole32 + oleaut32 + uuid + odbc32 + odbccp32 + ws2_32 + iphlpapi +) + +# Apache-specific libraries +if(APACHE_ROOT) + target_link_libraries(${IIS_MODULE_NAME} PRIVATE + ${APACHE_ROOT}/lib/libhttpd.lib + ${APACHE_ROOT}/lib/libapr-1.lib + ${APACHE_ROOT}/lib/libaprutil-1.lib + ) +endif() + +# Optional link libraries +if(WITH_LUA) + target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${LUA_LIBRARIES}) +endif() + +if(WITH_YAJL) + target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${YAJL_LIBRARIES}) +endif() + +if(WITH_SSDEEP AND SSDEEP_INCLUDE_DIR AND SSDEEP_GENERATED_LIB) + target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_GENERATED_LIB}) +else() + message(WARNING "SSDEEP library not found or generated. Disabling SSDEEP support.") + option(WITH_SSDEEP "Enable SSDEEP support" OFF) # Disable if library not found +endif() + +# Install target - copy to release files directory +install(TARGETS ${IIS_MODULE_NAME} + RUNTIME DESTINATION . + LIBRARY DESTINATION . +) + +# Also install the PDB file if it's generated +install(FILES $ DESTINATION . OPTIONAL) \ No newline at end of file diff --git a/iis/vcpkg.json b/iis/vcpkg.json new file mode 100644 index 0000000000..55f76ebe87 --- /dev/null +++ b/iis/vcpkg.json @@ -0,0 +1,9 @@ +{ + "dependencies": [ + "curl", + "libxml2", + "lua", + "pcre2", + "yajl" + ] +} \ No newline at end of file From 68483e1a7da3eabcc5d505c998fe57eec724ab54 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 01:33:32 +0800 Subject: [PATCH 416/470] Test CI Windows --- .github/workflows/test-ci-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 7abe75eebf..d31d424b62 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -3,10 +3,10 @@ name: CI/CD for IIS Module on: push: branches: - - main + - v2/test-ci-windows pull_request: branches: - - main + - v2/test-ci-windows jobs: build: From 8769f16380ed284f9478a2b37a62878a01340d10 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 01:39:39 +0800 Subject: [PATCH 417/470] fix powershell --- .github/workflows/test-ci-windows.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d31d424b62..c61d446de1 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -46,14 +46,14 @@ jobs: - name: Configure CMake for IIS Module run: | - cmake \ - -DAPACHE_ROOT="C:/tools/Apache24" \ - -DSSDEEP_ROOT="${{ github.workspace }}/ssdeep-install" \ - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install" \ - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" \ - -DWITH_SSDEEP=ON \ - -DWITH_LUA=ON \ - -DWITH_YAJL=ON \ + cmake ` + -DAPACHE_ROOT="C:/tools/Apache24" ` + -DSSDEEP_ROOT="${{ github.workspace }}/ssdeep-install" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" ` + -DWITH_SSDEEP=ON ` + -DWITH_LUA=ON ` + -DWITH_YAJL=ON ` -S IIS -B iis/build - name: Build IIS Module From 18095c0e0b2910cc3e031f87b8faa689d3241cb3 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 02:58:12 +0800 Subject: [PATCH 418/470] test --- .github/workflows/test-ci-windows.yml | 88 ++++++++++----------------- 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index c61d446de1..40ee6d1940 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,61 +9,39 @@ on: - v2/test-ci-windows jobs: - build: + check-apache-structure: runs-on: windows-latest - + steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Setup MSYS2 - uses: msys2/setup-msys2@v2 - with: - msystem: UCRT64 - update: true - install: > - git - make - autoconf - automake - libtool - mingw-w64-ucrt-x86_64-gcc - mingw-w64-ucrt-x86_64-pkg-config - - - name: Clone and build ssdeep - shell: msys2 {0} - run: | - git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - cd ssdeep - autoreconf -i - ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - make dll - mkdir -p ${{ github.workspace }}/ssdeep-install/bin - mkdir -p ${{ github.workspace }}/ssdeep-install/include - cp fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ - cp fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ - cp fuzzy.def ${{ github.workspace }}/ssdeep-install/ - - - name: Configure CMake for IIS Module - run: | - cmake ` - -DAPACHE_ROOT="C:/tools/Apache24" ` - -DSSDEEP_ROOT="${{ github.workspace }}/ssdeep-install" ` - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/install" ` - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" ` - -DWITH_SSDEEP=ON ` - -DWITH_LUA=ON ` - -DWITH_YAJL=ON ` - -S IIS -B iis/build - - - name: Build IIS Module - shell: pwsh + - name: Check Apache24 directory structure run: | - cmake --build iis/build --config Release - - # - name: Package IIS Module with WiX - # shell: pwsh - # run: | - # $CURRENT_DIR = "${{ github.workspace }}/iis/wix" - # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 - # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-64.msi" \ No newline at end of file + $apachePath = "C:\tools\Apache24" + + if (Test-Path $apachePath) { + Write-Host "Apache24 directory exists at: $apachePath" + Write-Host "Subdirectories:" + Get-ChildItem -Path $apachePath -Directory | ForEach-Object { + Write-Host " - $($_.Name)" + } + + Write-Host "`nChecking for APR headers in include directory:" + $includePath = Join-Path $apachePath "include" + if (Test-Path $includePath) { + Get-ChildItem -Path $includePath -Filter "apr*.h" | Select-Object -First 10 | ForEach-Object { + Write-Host " - $($_.Name)" + } + + # 特别检查 apr_perms_set.h + $permsSetPath = Join-Path $includePath "apr_perms_set.h" + if (Test-Path $permsSetPath) { + Write-Host "`nFOUND: apr_perms_set.h exists at $permsSetPath" + } else { + Write-Host "`nMISSING: apr_perms_set.h not found in $includePath" + } + } else { + Write-Host " Include directory not found at $includePath" + } + } else { + Write-Host "Apache24 directory does not exist at: $apachePath" + } + shell: pwsh \ No newline at end of file From 5802c016a0e7c81f50498eb9c0e6245c9558025c Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 03:02:34 +0800 Subject: [PATCH 419/470] test again --- .github/workflows/test-ci-windows.yml | 76 +++++++++++++++++++-------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 40ee6d1940..1ad2a3f34d 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,38 +9,72 @@ on: - v2/test-ci-windows jobs: - check-apache-structure: + inspect-apache: runs-on: windows-latest steps: + - name: Check Apache24 bin directory + run: | + $binPath = "C:\tools\Apache24\bin" + Write-Host "=== Apache24 bin Directory Contents ===" + if (Test-Path $binPath) { + Write-Host "Directory exists at: $binPath" + Write-Host "Files and subdirectories:" + Get-ChildItem -Path $binPath -Recurse | ForEach-Object { + if ($_.PSIsContainer) { + Write-Host " [DIR] $($_.FullName)" + } else { + Write-Host " [FILE] $($_.FullName) ($($_.Length) bytes)" + } + } + } else { + Write-Host "Bin directory does not exist at: $binPath" + } + shell: pwsh + + - name: Check Apache24 include directory + run: | + $includePath = "C:\tools\Apache24\include" + Write-Host "=== Apache24 include Directory Contents ===" + if (Test-Path $includePath) { + Write-Host "Directory exists at: $includePath" + Write-Host "Files and subdirectories:" + Get-ChildItem -Path $includePath -Recurse | ForEach-Object { + if ($_.PSIsContainer) { + Write-Host " [DIR] $($_.FullName)" + } else { + Write-Host " [FILE] $($_.FullName) ($($_.Length) bytes)" + } + } + + # 特别检查 APR 头文件 + Write-Host "`n=== APR Header Files ===" + Get-ChildItem -Path $includePath -Filter "apr*.h" -Recurse | ForEach-Object { + Write-Host " $($_.FullName)" + } + + # 检查是否存在 apr_perms_set.h + $permsSetPath = Join-Path $includePath "apr_perms_set.h" + if (Test-Path $permsSetPath) { + Write-Host "`nFOUND: apr_perms_set.h exists at $permsSetPath" + } else { + Write-Host "`nMISSING: apr_perms_set.h not found in $includePath" + } + } else { + Write-Host "Include directory does not exist at: $includePath" + } + shell: pwsh + - name: Check Apache24 directory structure run: | $apachePath = "C:\tools\Apache24" - + Write-Host "=== Apache24 Overall Structure ===" if (Test-Path $apachePath) { Write-Host "Apache24 directory exists at: $apachePath" - Write-Host "Subdirectories:" + Write-Host "Top-level directories:" Get-ChildItem -Path $apachePath -Directory | ForEach-Object { Write-Host " - $($_.Name)" } - - Write-Host "`nChecking for APR headers in include directory:" - $includePath = Join-Path $apachePath "include" - if (Test-Path $includePath) { - Get-ChildItem -Path $includePath -Filter "apr*.h" | Select-Object -First 10 | ForEach-Object { - Write-Host " - $($_.Name)" - } - - # 特别检查 apr_perms_set.h - $permsSetPath = Join-Path $includePath "apr_perms_set.h" - if (Test-Path $permsSetPath) { - Write-Host "`nFOUND: apr_perms_set.h exists at $permsSetPath" - } else { - Write-Host "`nMISSING: apr_perms_set.h not found in $includePath" - } - } else { - Write-Host " Include directory not found at $includePath" - } } else { Write-Host "Apache24 directory does not exist at: $apachePath" } From 84425206e8536890fd0829b7cb48877e84d55ec5 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 03:58:12 +0800 Subject: [PATCH 420/470] test 3 --- .github/workflows/test-ci-windows.yml | 107 +++++++++++--------------- iis/CMakeLists.txt | 29 ++++--- 2 files changed, 58 insertions(+), 78 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 1ad2a3f34d..3f792e086d 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,73 +9,54 @@ on: - v2/test-ci-windows jobs: - inspect-apache: + build: runs-on: windows-latest - + steps: - - name: Check Apache24 bin directory + - name: Create test files (MSYS2) + uses: msys2/setup-msys2@v2 + shell: msys2 {0} run: | - $binPath = "C:\tools\Apache24\bin" - Write-Host "=== Apache24 bin Directory Contents ===" - if (Test-Path $binPath) { - Write-Host "Directory exists at: $binPath" - Write-Host "Files and subdirectories:" - Get-ChildItem -Path $binPath -Recurse | ForEach-Object { - if ($_.PSIsContainer) { - Write-Host " [DIR] $($_.FullName)" - } else { - Write-Host " [FILE] $($_.FullName) ($($_.Length) bytes)" - } - } - } else { - Write-Host "Bin directory does not exist at: $binPath" - } - shell: pwsh - - - name: Check Apache24 include directory + # 创建测试目录和文件 + mkdir -p test-files + echo "This is a test file" > test-files/test.txt + echo "fuzzy definition file" > test-files/fuzzy.def + + # 复制到工作区目录 + mkdir -p ${{ github.workspace }}/artifacts + cp -r test-files/* ${{ github.workspace }}/artifacts/ + + # 验证文件已复制 + echo "Files in artifacts directory:" + ls -la ${{ github.workspace }}/artifacts/ + + - name: Verify file transfer (PowerShell) + shell: powershell run: | - $includePath = "C:\tools\Apache24\include" - Write-Host "=== Apache24 include Directory Contents ===" - if (Test-Path $includePath) { - Write-Host "Directory exists at: $includePath" - Write-Host "Files and subdirectories:" - Get-ChildItem -Path $includePath -Recurse | ForEach-Object { - if ($_.PSIsContainer) { - Write-Host " [DIR] $($_.FullName)" - } else { - Write-Host " [FILE] $($_.FullName) ($($_.Length) bytes)" - } - } - - # 特别检查 APR 头文件 - Write-Host "`n=== APR Header Files ===" - Get-ChildItem -Path $includePath -Filter "apr*.h" -Recurse | ForEach-Object { - Write-Host " $($_.FullName)" - } - - # 检查是否存在 apr_perms_set.h - $permsSetPath = Join-Path $includePath "apr_perms_set.h" - if (Test-Path $permsSetPath) { - Write-Host "`nFOUND: apr_perms_set.h exists at $permsSetPath" - } else { - Write-Host "`nMISSING: apr_perms_set.h not found in $includePath" - } + Write-Host "Checking transferred files in PowerShell:" + Get-ChildItem -Path "${{ github.workspace }}\artifacts" -Recurse + + # 验证文件内容 + Write-Host "Content of test.txt:" + Get-Content "${{ github.workspace }}\artifacts\test.txt" + + Write-Host "Content of fuzzy.def:" + Get-Content "${{ github.workspace }}\artifacts\fuzzy.def" + + # 检查文件是否存在 + $testFile = "${{ github.workspace }}\artifacts\test.txt" + $fuzzyFile = "${{ github.workspace }}\artifacts\fuzzy.def" + + if (Test-Path $testFile -PathType Leaf) { + Write-Host "✓ test.txt successfully transferred" } else { - Write-Host "Include directory does not exist at: $includePath" + Write-Host "✗ test.txt not found" + exit 1 } - shell: pwsh - - - name: Check Apache24 directory structure - run: | - $apachePath = "C:\tools\Apache24" - Write-Host "=== Apache24 Overall Structure ===" - if (Test-Path $apachePath) { - Write-Host "Apache24 directory exists at: $apachePath" - Write-Host "Top-level directories:" - Get-ChildItem -Path $apachePath -Directory | ForEach-Object { - Write-Host " - $($_.Name)" - } + + if (Test-Path $fuzzyFile -PathType Leaf) { + Write-Host "✓ fuzzy.def successfully transferred" } else { - Write-Host "Apache24 directory does not exist at: $apachePath" - } - shell: pwsh \ No newline at end of file + Write-Host "✗ fuzzy.def not found" + exit 1 + } \ No newline at end of file diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 11ebd1f92c..a5c6d82bd6 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -4,6 +4,7 @@ project(ModSecurityIIS C CXX) find_package(LibXml2 CONFIG REQUIRED) find_package(PCRE2 CONFIG REQUIRED) find_package(CURL CONFIG REQUIRED) +find_package(APR CONFIG REQUIRED) # iis/CMakeLists.txt set(IIS_MODULE_NAME "modsecurityiis") # Name should match the original output @@ -125,9 +126,10 @@ target_include_directories(${IIS_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../apache2 ${CMAKE_CURRENT_SOURCE_DIR}/../apache2/libinjection ${LIBXML2_INCLUDE_DIR}/libxml - ${PCRE_INCLUDE_DIRS} + ${PCRE2_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} - ${CMAKE_CURRENT_BINARY_DIR} # 添加构建目录以访问生成的头文件 + ${APR_INCLUDE_DIRS} + ${CMAKE_CURRENT_BINARY_DIR} ) # Include standalone directory if it exists @@ -139,6 +141,12 @@ endif() # Apache-specific includes if(APACHE_ROOT) + if(NOT EXISTS "${APACHE_ROOT}") + message(FATAL_ERROR "APACHE_ROOT is defined but the directory '${APACHE_ROOT}' does not exist. Please set APACHE_ROOT to a valid Apache installation directory.") + endif() + if(NOT EXISTS "${APACHE_ROOT}/lib") + message(FATAL_ERROR "APACHE_ROOT/lib directory does not exist. Expected: '${APACHE_ROOT}/lib'. Please ensure Apache libraries are available.") + endif() target_include_directories(${IIS_MODULE_NAME} PRIVATE ${APACHE_ROOT}/include ) @@ -166,24 +174,15 @@ if(WITH_LUA) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${LUA_INCLUDE_DIR}) endif() -# Default Apache root based on architecture -if(NOT APACHE_ROOT) - if(ARCHITECTURE STREQUAL "x64") - set(APACHE_ROOT "C:/Apache24_x64" CACHE PATH "Path to Apache x64 installation") - else() - set(APACHE_ROOT "C:/Apache24_x86" CACHE PATH "Path to Apache x86 installation") - endif() -endif() - option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg_installed/${ARCHITECTURE}-windows/include" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH ) find_library(YAJL_LIBRARY NAMES yajl - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/vcpkg_installed/${ARCHITECTURE}-windows/lib" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/lib" NO_DEFAULT_PATH ) @@ -193,7 +192,7 @@ if(WITH_YAJL) target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_YAJL) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${YAJL_INCLUDE_DIRS}) else() - message(WARNING "YAJL not found. Please ensure yajl is installed via vcpkg in the iis/vcpkg_installed directory. Disabling YAJL support.") + message(WARNING "YAJL not found. YAJL_INCLUDE_DIR: '${YAJL_INCLUDE_DIR}', YAJL_LIBRARY: '${YAJL_LIBRARY}'. Please ensure yajl is installed via vcpkg in the vcpkg_installed directory. Disabling YAJL support.") option(WITH_YAJL "Enable YAJL support" OFF) # Disable if not found endif() endif() @@ -203,7 +202,7 @@ if(WITH_SSDEEP) set(SSDEEP_ROOT "" CACHE PATH "Path to manually built ssdeep") if(NOT SSDEEP_ROOT OR NOT EXISTS "${SSDEEP_ROOT}") - message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") + message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") From 0e2b4b92547e78d653625a9787c9b94c81d38fdc Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:01:10 +0800 Subject: [PATCH 421/470] test workflow_dispatch --- .github/workflows/test-ci-windows.yml | 96 ++++++++++++++------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 3f792e086d..40d7819d3d 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -1,62 +1,68 @@ -name: CI/CD for IIS Module +name: File Generation and Reading Test on: - push: - branches: - - v2/test-ci-windows - pull_request: - branches: - - v2/test-ci-windows + workflow_dispatch: # 允许手动触发 jobs: - build: - runs-on: windows-latest - - steps: - - name: Create test files (MSYS2) - uses: msys2/setup-msys2@v2 - shell: msys2 {0} - run: | - # 创建测试目录和文件 - mkdir -p test-files - echo "This is a test file" > test-files/test.txt - echo "fuzzy definition file" > test-files/fuzzy.def - - # 复制到工作区目录 - mkdir -p ${{ github.workspace }}/artifacts - cp -r test-files/* ${{ github.workspace }}/artifacts/ - - # 验证文件已复制 - echo "Files in artifacts directory:" - ls -la ${{ github.workspace }}/artifacts/ + file-test: + runs-on: windows-latest # 使用 Windows 运行器 - - name: Verify file transfer (PowerShell) + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Generate test files (Step 1) shell: powershell run: | - Write-Host "Checking transferred files in PowerShell:" - Get-ChildItem -Path "${{ github.workspace }}\artifacts" -Recurse + # 创建工作目录 + $testDir = "${{ github.workspace }}\test-files" + New-Item -ItemType Directory -Path $testDir -Force - # 验证文件内容 - Write-Host "Content of test.txt:" - Get-Content "${{ github.workspace }}\artifacts\test.txt" + # 创建几个测试文件 + "This is a test content for file1.txt" | Out-File -FilePath "$testDir\file1.txt" + "fuzzy.def test content" | Out-File -FilePath "$testDir\fuzzy.def" - Write-Host "Content of fuzzy.def:" - Get-Content "${{ github.workspace }}\artifacts\fuzzy.def" + # 创建一个包含文件列表的 JSON 文件 + $files = Get-ChildItem -Path $testDir + $fileInfo = @() + foreach ($file in $files) { + $fileInfo += @{ + Name = $file.Name + Path = $file.FullName + Size = $file.Length + LastWriteTime = $file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") + } + } + $fileInfo | ConvertTo-Json | Out-File -FilePath "$testDir\files.json" - # 检查文件是否存在 - $testFile = "${{ github.workspace }}\artifacts\test.txt" - $fuzzyFile = "${{ github.workspace }}\artifacts\fuzzy.def" + # 输出生成的文件信息 + Write-Host "Generated files:" + Get-ChildItem -Path $testDir | Format-Table Name, Length - if (Test-Path $testFile -PathType Leaf) { - Write-Host "✓ test.txt successfully transferred" - } else { - Write-Host "✗ test.txt not found" + - name: Read test files (Step 2) + shell: powershell + run: | + $testDir = "${{ github.workspace }}\test-files" + + # 检查目录是否存在 + if (-not (Test-Path -Path $testDir)) { + Write-Error "Test directory does not exist!" exit 1 } - if (Test-Path $fuzzyFile -PathType Leaf) { - Write-Host "✓ fuzzy.def successfully transferred" + # 读取文件列表 + $filesJson = Get-Content -Path "$testDir\files.json" -Raw | ConvertFrom-Json + Write-Host "Files found:" + $filesJson | Format-Table Name, Size + + # 读取特定文件内容 + Write-Host "Content of fuzzy.def:" + Get-Content -Path "$testDir\fuzzy.def" + + # 验证文件存在 + if (Test-Path -Path "$testDir\fuzzy.def") { + Write-Host "SUCCESS: fuzzy.def file exists and is accessible!" } else { - Write-Host "✗ fuzzy.def not found" + Write-Error "ERROR: fuzzy.def file not found!" exit 1 } \ No newline at end of file From 45c151482b32dbcd630fa4fb67dc9e7b117a4752 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:04:24 +0800 Subject: [PATCH 422/470] ........ --- .github/workflows/test-ci-windows.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 40d7819d3d..31bc08f517 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -1,7 +1,13 @@ name: File Generation and Reading Test on: - workflow_dispatch: # 允许手动触发 + push: + branches: + - v2/test-ci-windows + pull_request: + branches: + - v2/test-ci-windows + jobs: file-test: From 85f60f40433f540d7577d7f7af5d2ca025e04cc9 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:11:29 +0800 Subject: [PATCH 423/470] here we go again --- .github/workflows/test-ci-windows.yml | 117 ++++++++++++-------------- 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 31bc08f517..d5c41050f4 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -1,4 +1,4 @@ -name: File Generation and Reading Test +name: CI/CD for IIS Module on: push: @@ -8,67 +8,62 @@ on: branches: - v2/test-ci-windows - jobs: - file-test: - runs-on: windows-latest # 使用 Windows 运行器 - + build: + runs-on: windows-latest + steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Generate test files (Step 1) - shell: powershell + - name: Checkout code + uses: actions/checkout@v5 + + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: > + git + make + autoconf + automake + libtool + mingw-w64-ucrt-x86_64-gcc + mingw-w64-ucrt-x86_64-pkg-config + + - name: Clone and build ssdeep + shell: msys2 {0} run: | - # 创建工作目录 - $testDir = "${{ github.workspace }}\test-files" - New-Item -ItemType Directory -Path $testDir -Force - - # 创建几个测试文件 - "This is a test content for file1.txt" | Out-File -FilePath "$testDir\file1.txt" - "fuzzy.def test content" | Out-File -FilePath "$testDir\fuzzy.def" - - # 创建一个包含文件列表的 JSON 文件 - $files = Get-ChildItem -Path $testDir - $fileInfo = @() - foreach ($file in $files) { - $fileInfo += @{ - Name = $file.Name - Path = $file.FullName - Size = $file.Length - LastWriteTime = $file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") - } - } - $fileInfo | ConvertTo-Json | Out-File -FilePath "$testDir\files.json" - - # 输出生成的文件信息 - Write-Host "Generated files:" - Get-ChildItem -Path $testDir | Format-Table Name, Length - - - name: Read test files (Step 2) - shell: powershell + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + cd ssdeep + autoreconf -i + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + make dll + mkdir -p ${{ github.workspace }}/ssdeep-install/bin + mkdir -p ${{ github.workspace }}/ssdeep-install/include + cp fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ + cp fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ + cp fuzzy.def ${{ github.workspace }}/ssdeep-install/ + + - name: Configure CMake for IIS Module + run: | + cmake ` + -DAPACHE_ROOT="C:\tools\Apache24" ` + -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` + -DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" ` + -DWITH_SSDEEP=ON ` + -DWITH_LUA=ON ` + -DWITH_YAJL=ON ` + -S IIS -B iis\build + + - name: Build IIS Module + shell: pwsh run: | - $testDir = "${{ github.workspace }}\test-files" - - # 检查目录是否存在 - if (-not (Test-Path -Path $testDir)) { - Write-Error "Test directory does not exist!" - exit 1 - } - - # 读取文件列表 - $filesJson = Get-Content -Path "$testDir\files.json" -Raw | ConvertFrom-Json - Write-Host "Files found:" - $filesJson | Format-Table Name, Size - - # 读取特定文件内容 - Write-Host "Content of fuzzy.def:" - Get-Content -Path "$testDir\fuzzy.def" - - # 验证文件存在 - if (Test-Path -Path "$testDir\fuzzy.def") { - Write-Host "SUCCESS: fuzzy.def file exists and is accessible!" - } else { - Write-Error "ERROR: fuzzy.def file not found!" - exit 1 - } \ No newline at end of file + cmake --build iis\build --config Release + + # - name: Package IIS Module with WiX + # shell: pwsh + # run: | + # $CURRENT_DIR = "${{ github.workspace }}/iis/wix" + # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 + # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-64.msi" \ No newline at end of file From 952ac5f2553611aefafbdc218ca09f18367a8142 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:25:15 +0800 Subject: [PATCH 424/470] da.n --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d5c41050f4..3f091aaa57 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -50,7 +50,7 @@ jobs: -DAPACHE_ROOT="C:\tools\Apache24" ` -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` - -DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\vcpkg\scripts\buildsystems\vcpkg.cmake" ` -DWITH_SSDEEP=ON ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` From 53bcd8328155dd440d7017351d66bc570f470d27 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:28:37 +0800 Subject: [PATCH 425/470] my bad --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 3f091aaa57..eb6d534e06 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -50,7 +50,7 @@ jobs: -DAPACHE_ROOT="C:\tools\Apache24" ` -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\vcpkg\scripts\buildsystems\vcpkg.cmake" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` -DWITH_SSDEEP=ON ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` From dc7fcdcf70bedfb578758707318076be5e42bba7 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 04:54:08 +0800 Subject: [PATCH 426/470] forget json --- iis/vcpkg.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iis/vcpkg.json b/iis/vcpkg.json index 55f76ebe87..3abb499b35 100644 --- a/iis/vcpkg.json +++ b/iis/vcpkg.json @@ -4,6 +4,7 @@ "libxml2", "lua", "pcre2", - "yajl" + "yajl", + "apr" ] } \ No newline at end of file From 3eafb4e9df5f92f28274c32ed47cc4b4058e3735 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 15:37:07 +0800 Subject: [PATCH 427/470] tt --- .github/workflows/test-ci-windows.yml | 37 ++++++++++++++------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index eb6d534e06..6f83140a7c 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -40,26 +40,27 @@ jobs: make dll mkdir -p ${{ github.workspace }}/ssdeep-install/bin mkdir -p ${{ github.workspace }}/ssdeep-install/include - cp fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ - cp fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ - cp fuzzy.def ${{ github.workspace }}/ssdeep-install/ + cp -v fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ + cp -v fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ + cp -v fuzzy.def ${{ github.workspace }}/ssdeep-install/ - - name: Configure CMake for IIS Module - run: | - cmake ` - -DAPACHE_ROOT="C:\tools\Apache24" ` - -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` - -DWITH_SSDEEP=ON ` - -DWITH_LUA=ON ` - -DWITH_YAJL=ON ` - -S IIS -B iis\build + # - name: Configure CMake for IIS Module + # run: | + # Test-Path "${{ github.workspace }}\ssdeep-install\bin\fuzzy.dll" + # cmake ` + # -DAPACHE_ROOT="C:\tools\Apache24" ` + # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` + # -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` + # -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + # -DWITH_SSDEEP=ON ` + # -DWITH_LUA=ON ` + # -DWITH_YAJL=ON ` + # -S IIS -B iis\build - - name: Build IIS Module - shell: pwsh - run: | - cmake --build iis\build --config Release + # - name: Build IIS Module + # shell: pwsh + # run: | + # cmake --build iis\build --config Release # - name: Package IIS Module with WiX # shell: pwsh From 87ae85f8cae0551ae298e6da45f9d8232ad19acf Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 15:45:22 +0800 Subject: [PATCH 428/470] again! --- .github/workflows/test-ci-windows.yml | 45 ++++++++++++++------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 6f83140a7c..3f7564d9c4 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -33,34 +33,37 @@ jobs: - name: Clone and build ssdeep shell: msys2 {0} run: | + MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') + echo "Converted workspace path: $MSYS2_WORKSPACE" + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 cd ssdeep autoreconf -i ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" make dll - mkdir -p ${{ github.workspace }}/ssdeep-install/bin - mkdir -p ${{ github.workspace }}/ssdeep-install/include - cp -v fuzzy.dll ${{ github.workspace }}/ssdeep-install/bin/ - cp -v fuzzy.h ${{ github.workspace }}/ssdeep-install/include/ - cp -v fuzzy.def ${{ github.workspace }}/ssdeep-install/ - # - name: Configure CMake for IIS Module - # run: | - # Test-Path "${{ github.workspace }}\ssdeep-install\bin\fuzzy.dll" - # cmake ` - # -DAPACHE_ROOT="C:\tools\Apache24" ` - # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` - # -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` - # -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` - # -DWITH_SSDEEP=ON ` - # -DWITH_LUA=ON ` - # -DWITH_YAJL=ON ` - # -S IIS -B iis\build + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include + cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/ + cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/ + cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/ - # - name: Build IIS Module - # shell: pwsh - # run: | - # cmake --build iis\build --config Release + - name: Configure CMake for IIS Module + run: | + cmake ` + -DAPACHE_ROOT="C:\tools\Apache24" ` + -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -DWITH_SSDEEP=ON ` + -DWITH_LUA=ON ` + -DWITH_YAJL=ON ` + -S IIS -B iis\build + + - name: Build IIS Module + shell: pwsh + run: | + cmake --build iis\build --config Release # - name: Package IIS Module with WiX # shell: pwsh From 5977c8c8d2f67304ebd320562e54b80e161d8445 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 15:49:10 +0800 Subject: [PATCH 429/470] fffff --- .github/workflows/test-ci-windows.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 3f7564d9c4..d86ecf861a 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -42,11 +42,11 @@ jobs: ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" make dll - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include - cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/ - cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/ - cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/ + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin" + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include" + cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/" + cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/" + cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" - name: Configure CMake for IIS Module run: | From c432a6a8956f46fbeb77d69a8d25c8cef2dd99ea Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Fri, 19 Sep 2025 16:54:55 +0800 Subject: [PATCH 430/470] vcpkg Caching --- .github/workflows/test-ci-windows.yml | 15 +++++++++++++++ iis/CMakeLists.txt | 3 +++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d86ecf861a..f13f60f902 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -11,6 +11,11 @@ on: jobs: build: runs-on: windows-latest + + # For Caching + permissions: + actions: read + contents: read steps: - name: Checkout code @@ -48,7 +53,17 @@ jobs: cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/" cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" + - name: Restore vcpkg cache + id: vcpkg-cache + uses: TAServers/vcpkg-cache@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + prefix: vcpkg-iis-module/ + - name: Configure CMake for IIS Module + env: + VCPKG_FEATURE_FLAGS: "binarycaching" + VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" run: | cmake ` -DAPACHE_ROOT="C:\tools\Apache24" ` diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index a5c6d82bd6..428cc80c7a 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.15) + +set(VCPKG_BUILD_TYPE release) + project(ModSecurityIIS C CXX) find_package(LibXml2 CONFIG REQUIRED) From 4662e7581d5dbe6e5eea4c645bb413c476b06efa Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 00:39:35 +0800 Subject: [PATCH 431/470] change target --- iis/CMakeLists.txt | 84 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 428cc80c7a..0de10bd93c 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required(VERSION 3.15) -set(VCPKG_BUILD_TYPE release) - project(ModSecurityIIS C CXX) find_package(LibXml2 CONFIG REQUIRED) @@ -150,6 +148,27 @@ if(APACHE_ROOT) if(NOT EXISTS "${APACHE_ROOT}/lib") message(FATAL_ERROR "APACHE_ROOT/lib directory does not exist. Expected: '${APACHE_ROOT}/lib'. Please ensure Apache libraries are available.") endif() + + # Create imported targets for Apache libraries + add_library(Apache::httpd SHARED IMPORTED) + set_target_properties(Apache::httpd PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${APACHE_ROOT}/include" + IMPORTED_IMPLIB "${APACHE_ROOT}/lib/libhttpd.lib" + IMPORTED_LOCATION "${APACHE_ROOT}/bin/libhttpd.dll" + ) + + add_library(Apache::apr SHARED IMPORTED) + set_target_properties(Apache::apr PROPERTIES + IMPORTED_IMPLIB "${APACHE_ROOT}/lib/libapr-1.lib" + IMPORTED_LOCATION "${APACHE_ROOT}/bin/libapr-1.dll" + ) + + add_library(Apache::aprutil SHARED IMPORTED) + set_target_properties(Apache::aprutil PROPERTIES + IMPORTED_IMPLIB "${APACHE_ROOT}/lib/libaprutil-1.lib" + IMPORTED_LOCATION "${APACHE_ROOT}/bin/libaprutil-1.dll" + ) + target_include_directories(${IIS_MODULE_NAME} PRIVATE ${APACHE_ROOT}/include ) @@ -228,6 +247,7 @@ if(WITH_SSDEEP) set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() set(SSDEEP_GENERATED_LIB "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.lib") + set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/bin/fuzzy.dll") # 添加自定义命令生成 fuzzy.lib add_custom_command( @@ -250,7 +270,14 @@ if(WITH_SSDEEP) # 使主目标依赖于 fuzzy.lib 的生成 add_dependencies(${IIS_MODULE_NAME} generate_ssdeep_lib) - endif() + add_library(SSDEEP::fuzzy SHARED IMPORTED) + set_target_properties(SSDEEP::fuzzy PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SSDEEP_INCLUDE_DIR}" + IMPORTED_LOCATION "${SSDEEP_GENERATED_dll}" + IMPORTED_IMPLIB "${SSDEEP_GENERATED_LIB}" + ) + + endif() else() message(WARNING "SSDEEP include (fuzzy.h) not found at ${SSDEEP_ROOT}/include. Disabling SSDEEP support.") set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) @@ -300,10 +327,12 @@ target_link_libraries(${IIS_MODULE_NAME} PRIVATE # Apache-specific libraries if(APACHE_ROOT) target_link_libraries(${IIS_MODULE_NAME} PRIVATE - ${APACHE_ROOT}/lib/libhttpd.lib - ${APACHE_ROOT}/lib/libapr-1.lib - ${APACHE_ROOT}/lib/libaprutil-1.lib + Apache::httpd + Apache::apr + Apache::aprutil ) +else() + message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") endif() # Optional link libraries @@ -316,17 +345,58 @@ if(WITH_YAJL) endif() if(WITH_SSDEEP AND SSDEEP_INCLUDE_DIR AND SSDEEP_GENERATED_LIB) - target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_GENERATED_LIB}) + target_link_libraries(${IIS_MODULE_NAME} PRIVATE SSDEEP::fuzzy) else() message(WARNING "SSDEEP library not found or generated. Disabling SSDEEP support.") option(WITH_SSDEEP "Enable SSDEEP support" OFF) # Disable if library not found endif() +if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") + add_custom_command(TARGET ${IIS_MODULE_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${APACHE_ROOT}/bin/libhttpd.dll" + $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${APACHE_ROOT}/bin/libaprutil-1.dll" + $ + COMMENT "Copying Apache DLLs to output directory" + ) +else() + message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") +endif() + +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") + add_custom_command(TARGET ${IIS_MODULE_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${SSDEEP_ROOT}/bin/fuzzy.dll" + $ + COMMENT "Copying SSDEEP DLL to output directory" + ) +else() + message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the SSDEEP installation directory.") +endif() + + # Install target - copy to release files directory install(TARGETS ${IIS_MODULE_NAME} RUNTIME DESTINATION . LIBRARY DESTINATION . ) +if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") + install(FILES + "${APACHE_ROOT}/bin/libhttpd.dll" + "${APACHE_ROOT}/bin/libaprutil-1.dll" + DESTINATION . + ) +endif() + +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") + install(FILES + "${SSDEEP_ROOT}/bin/fuzzy.dll" + DESTINATION . + ) +endif() + # Also install the PDB file if it's generated install(FILES $ DESTINATION . OPTIONAL) \ No newline at end of file From 9165787ae616a27638ef7806b7db83c348266bbc Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 19:27:22 +0800 Subject: [PATCH 432/470] Test winget availability --- .github/workflows/test-ci-windows.yml | 148 +++++++++++++++----------- 1 file changed, 87 insertions(+), 61 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index f13f60f902..fbbd6368a9 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,76 +9,102 @@ on: - v2/test-ci-windows jobs: - build: - runs-on: windows-latest + test-winget: + name: Test winget availability + runs-on: windows-latest # 使用最新的 Windows Server 运行器 - # For Caching - permissions: - actions: read - contents: read - steps: - - name: Checkout code - uses: actions/checkout@v5 + - name: Check if winget is installed + run: | + # 检查 winget 是否可用 + winget --version + if ($LASTEXITCODE -eq 0) { + Write-Host "✅ winget is installed and working correctly" + } else { + Write-Error "❌ winget is not available or not functioning properly" + exit 1 + } + shell: pwsh # 使用 PowerShell 作为 shell + + - name: Optional - List installed packages (if winget is available) + if: success() + run: | + # 列出已安装的包以验证 winget 功能 + winget list --name "Microsoft Visual C++" + Write-Host "winget functionality verified successfully" + shell: pwsh + +# jobs: +# build: +# runs-on: windows-latest + +# # For Caching +# permissions: +# actions: read +# contents: read - - name: Setup MSYS2 - uses: msys2/setup-msys2@v2 - with: - msystem: UCRT64 - update: true - install: > - git - make - autoconf - automake - libtool - mingw-w64-ucrt-x86_64-gcc - mingw-w64-ucrt-x86_64-pkg-config +# steps: +# - name: Checkout code +# uses: actions/checkout@v5 - - name: Clone and build ssdeep - shell: msys2 {0} - run: | - MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - echo "Converted workspace path: $MSYS2_WORKSPACE" +# - name: Setup MSYS2 +# uses: msys2/setup-msys2@v2 +# with: +# msystem: UCRT64 +# update: true +# install: > +# git +# make +# autoconf +# automake +# libtool +# mingw-w64-ucrt-x86_64-gcc +# mingw-w64-ucrt-x86_64-pkg-config - git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - cd ssdeep - autoreconf -i - ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - make dll +# - name: Clone and build ssdeep +# shell: msys2 {0} +# run: | +# MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') +# echo "Converted workspace path: $MSYS2_WORKSPACE" - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin" - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include" - cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/" - cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/" - cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" +# git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 +# cd ssdeep +# autoreconf -i +# ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" +# make dll - - name: Restore vcpkg cache - id: vcpkg-cache - uses: TAServers/vcpkg-cache@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - prefix: vcpkg-iis-module/ +# mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin" +# mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include" +# cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/" +# cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/" +# cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" - - name: Configure CMake for IIS Module - env: - VCPKG_FEATURE_FLAGS: "binarycaching" - VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" - run: | - cmake ` - -DAPACHE_ROOT="C:\tools\Apache24" ` - -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` - -DWITH_SSDEEP=ON ` - -DWITH_LUA=ON ` - -DWITH_YAJL=ON ` - -S IIS -B iis\build +# - name: Restore vcpkg cache +# id: vcpkg-cache +# uses: TAServers/vcpkg-cache@v3 +# with: +# token: ${{ secrets.GITHUB_TOKEN }} +# prefix: vcpkg-iis-module/ - - name: Build IIS Module - shell: pwsh - run: | - cmake --build iis\build --config Release +# - name: Configure CMake for IIS Module +# env: +# VCPKG_FEATURE_FLAGS: "binarycaching" +# VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" +# run: | +# cmake ` +# -DAPACHE_ROOT="C:\tools\Apache24" ` +# -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` +# -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` +# -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` +# -DWITH_SSDEEP=ON ` +# -DWITH_LUA=ON ` +# -DWITH_YAJL=ON ` +# -S IIS -B iis\build + +# - name: Build IIS Module +# shell: pwsh +# run: | +# cmake --build iis\build --config Release # - name: Package IIS Module with WiX # shell: pwsh From 44813cb4296444f1b6522ac3f2f8b46fe76eb5df Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 21:35:26 +0800 Subject: [PATCH 433/470] test x86 --- .github/workflows/test-ci-windows.yml | 181 +++++++++++++------------- 1 file changed, 94 insertions(+), 87 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index fbbd6368a9..7cfa059033 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,106 +9,113 @@ on: - v2/test-ci-windows jobs: - test-winget: - name: Test winget availability - runs-on: windows-latest # 使用最新的 Windows Server 运行器 + build: + strategy: + matrix: + arch: [x86, x64] + runs-on: windows-latest + # For Caching + permissions: + actions: read + contents: read + steps: - - name: Check if winget is installed - run: | - # 检查 winget 是否可用 - winget --version - if ($LASTEXITCODE -eq 0) { - Write-Host "✅ winget is installed and working correctly" - } else { - Write-Error "❌ winget is not available or not functioning properly" - exit 1 - } - shell: pwsh # 使用 PowerShell 作为 shell - - - name: Optional - List installed packages (if winget is available) - if: success() - run: | - # 列出已安装的包以验证 winget 功能 - winget list --name "Microsoft Visual C++" - Write-Host "winget functionality verified successfully" + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Apache for x86 + if: matrix.arch == 'x86' shell: pwsh - -# jobs: -# build: -# runs-on: windows-latest - -# # For Caching -# permissions: -# actions: read -# contents: read + run: | + $apachePath = "${{ github.workspace }}\apache-x86" + New-Item -ItemType Directory -Path $apachePath -Force + choco install apache-httpd -y --force --forcex86 --params="`"/installLocation:$apachePath /noService`"" + # 设置环境变量供后续步骤使用 + echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append -# steps: -# - name: Checkout code -# uses: actions/checkout@v5 + - name: Set Apache path for x64 + if: matrix.arch == 'x64' + shell: pwsh + run: | + # 对于 x64,使用预装的 Apache + echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append -# - name: Setup MSYS2 -# uses: msys2/setup-msys2@v2 -# with: -# msystem: UCRT64 -# update: true -# install: > -# git -# make -# autoconf -# automake -# libtool -# mingw-w64-ucrt-x86_64-gcc -# mingw-w64-ucrt-x86_64-pkg-config + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} + update: true + install: > + git + make + autoconf + automake + libtool + ${{ matrix.arch == 'x86' && 'mingw-w64-ucrt-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + ${{ matrix.arch == 'x86' && 'mingw-w64-ucrt-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} -# - name: Clone and build ssdeep -# shell: msys2 {0} -# run: | -# MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') -# echo "Converted workspace path: $MSYS2_WORKSPACE" + - name: Clone and build ssdeep + shell: msys2 {0} + run: | + MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') + echo "Converted workspace path: $MSYS2_WORKSPACE" -# git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 -# cd ssdeep -# autoreconf -i -# ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" -# make dll + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + cd ssdeep + autoreconf -i + + if [ "${{ matrix.arch }}" = "x86" ]; then + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 + else + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + fi + + make dll -# mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/bin" -# mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/include" -# cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/bin/" -# cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/include/" -# cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" + cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" + cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" + cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" -# - name: Restore vcpkg cache -# id: vcpkg-cache -# uses: TAServers/vcpkg-cache@v3 -# with: -# token: ${{ secrets.GITHUB_TOKEN }} -# prefix: vcpkg-iis-module/ + - name: Restore vcpkg cache + id: vcpkg-cache + uses: TAServers/vcpkg-cache@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + prefix: vcpkg-iis-module-${{ matrix.arch }}/ -# - name: Configure CMake for IIS Module -# env: -# VCPKG_FEATURE_FLAGS: "binarycaching" -# VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" -# run: | -# cmake ` -# -DAPACHE_ROOT="C:\tools\Apache24" ` -# -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` -# -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install" ` -# -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` -# -DWITH_SSDEEP=ON ` -# -DWITH_LUA=ON ` -# -DWITH_YAJL=ON ` -# -S IIS -B iis\build + - name: Configure CMake for IIS Module + env: + VCPKG_FEATURE_FLAGS: "binarycaching" + VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" + VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-windows + run: | + $archFlag = "${{ matrix.arch }}" + $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } + + cmake ` + -DAPACHE_ROOT="$env:APACHE_ROOT" ` + -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install-${{ matrix.arch }}" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -A $cmakeArch ` + -DWITH_SSDEEP=ON ` + -DWITH_LUA=ON ` + -DWITH_YAJL=ON ` + -S IIS -B "iis\build-${{ matrix.arch }}" -# - name: Build IIS Module -# shell: pwsh -# run: | -# cmake --build iis\build --config Release + - name: Build IIS Module + shell: pwsh + run: | + cmake --build "iis\build-${{ matrix.arch }}" --config Release # - name: Package IIS Module with WiX # shell: pwsh # run: | # $CURRENT_DIR = "${{ github.workspace }}/iis/wix" - # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 - # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-64.msi" \ No newline at end of file + # $arch = "${{ matrix.arch }}" + # $wixArch = if ($arch -eq "x86") { "x86" } else { "x64" } + # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch $wixArch + # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-$arch.msi" \ No newline at end of file From a05038ed5f055803d2cbb1d2e1aaafe81640a4b7 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 21:42:36 +0800 Subject: [PATCH 434/470] no ucrt64 --- .github/workflows/test-ci-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 7cfa059033..91ed860930 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -52,8 +52,8 @@ jobs: autoconf automake libtool - ${{ matrix.arch == 'x86' && 'mingw-w64-ucrt-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} - ${{ matrix.arch == 'x86' && 'mingw-w64-ucrt-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} - name: Clone and build ssdeep shell: msys2 {0} From 388148872746191879bc891b0fa7411da5a03126 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 22:11:24 +0800 Subject: [PATCH 435/470] path error? --- .github/workflows/test-ci-windows.yml | 11 +++++++++-- iis/CMakeLists.txt | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 91ed860930..4872bd338c 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -31,14 +31,12 @@ jobs: $apachePath = "${{ github.workspace }}\apache-x86" New-Item -ItemType Directory -Path $apachePath -Force choco install apache-httpd -y --force --forcex86 --params="`"/installLocation:$apachePath /noService`"" - # 设置环境变量供后续步骤使用 echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Set Apache path for x64 if: matrix.arch == 'x64' shell: pwsh run: | - # 对于 x64,使用预装的 Apache echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup MSYS2 @@ -95,6 +93,15 @@ jobs: $archFlag = "${{ matrix.arch }}" $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } + $vcpkgIncludePath = "${{ github.workspace }}\build\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } + cmake ` -DAPACHE_ROOT="$env:APACHE_ROOT" ` -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 0de10bd93c..b92acf82e0 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -199,6 +199,7 @@ endif() option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) + message(Finding YAJL in ${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH From bd6d6381bbe5e9bb6c8c01f55749e114ebea836b Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 22:25:18 +0800 Subject: [PATCH 436/470] find path --- .github/workflows/test-ci-windows.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 4872bd338c..fd1cc2fad1 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -93,7 +93,7 @@ jobs: $archFlag = "${{ matrix.arch }}" $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } - $vcpkgIncludePath = "${{ github.workspace }}\build\vcpkg_installed\${{ matrix.arch }}-windows\include" + $vcpkgIncludePath = "${{ github.workspace }}\iis\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" Write-Host "Checking vcpkg include path: $vcpkgIncludePath" if (Test-Path -Path $vcpkgIncludePath) { Write-Host "vcpkg include path exists. Contents:" @@ -113,10 +113,10 @@ jobs: -DWITH_YAJL=ON ` -S IIS -B "iis\build-${{ matrix.arch }}" - - name: Build IIS Module - shell: pwsh - run: | - cmake --build "iis\build-${{ matrix.arch }}" --config Release + # - name: Build IIS Module + # shell: pwsh + # run: | + # cmake --build "iis\build-${{ matrix.arch }}" --config Release # - name: Package IIS Module with WiX # shell: pwsh From 3dabde3ac6b987a0485c74bbbc4e5b6042658a78 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 22:31:42 +0800 Subject: [PATCH 437/470] where are you? --- .github/workflows/test-ci-windows.yml | 55 ++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index fd1cc2fad1..4020d2b5ac 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -30,7 +30,7 @@ jobs: run: | $apachePath = "${{ github.workspace }}\apache-x86" New-Item -ItemType Directory -Path $apachePath -Force - choco install apache-httpd -y --force --forcex86 --params="`"/installLocation:$apachePath /noService`"" + choco install apache-httpd -y --force --forcex86 --no-progress -r --params="`"/installLocation:$apachePath /noService`"" echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Set Apache path for x64 @@ -92,15 +92,6 @@ jobs: run: | $archFlag = "${{ matrix.arch }}" $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } - - $vcpkgIncludePath = "${{ github.workspace }}\iis\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } cmake ` -DAPACHE_ROOT="$env:APACHE_ROOT" ` @@ -113,6 +104,50 @@ jobs: -DWITH_YAJL=ON ` -S IIS -B "iis\build-${{ matrix.arch }}" + $vcpkgIncludePath = "${{ github.workspace }}\iis\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } + + $vcpkgIncludePath = "${{ github.workspace }}\iis\build\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } + + $vcpkgIncludePath = "${{ github.workspace }}\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } + + $vcpkgIncludePath = "${{ github.workspace }}\build\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } + + $vcpkgIncludePath = "${{ github.workspace }}\iis\vcpkg_installed\${{ matrix.arch }}-windows\include" + Write-Host "Checking vcpkg include path: $vcpkgIncludePath" + if (Test-Path -Path $vcpkgIncludePath) { + Write-Host "vcpkg include path exists. Contents:" + Get-ChildItem -Path $vcpkgIncludePath + } else { + Write-Host "vcpkg include path does not exist." + } # - name: Build IIS Module # shell: pwsh # run: | From 73531e9dfbe5d4c665d80dca59050fc929a02752 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 22:38:41 +0800 Subject: [PATCH 438/470] should fine --- .github/workflows/test-ci-windows.yml | 52 +++------------------------ iis/CMakeLists.txt | 5 ++- 2 files changed, 6 insertions(+), 51 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 4020d2b5ac..d7d966f041 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -104,54 +104,10 @@ jobs: -DWITH_YAJL=ON ` -S IIS -B "iis\build-${{ matrix.arch }}" - $vcpkgIncludePath = "${{ github.workspace }}\iis\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } - - $vcpkgIncludePath = "${{ github.workspace }}\iis\build\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } - - $vcpkgIncludePath = "${{ github.workspace }}\build-${{ matrix.arch }}\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } - - $vcpkgIncludePath = "${{ github.workspace }}\build\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } - - $vcpkgIncludePath = "${{ github.workspace }}\iis\vcpkg_installed\${{ matrix.arch }}-windows\include" - Write-Host "Checking vcpkg include path: $vcpkgIncludePath" - if (Test-Path -Path $vcpkgIncludePath) { - Write-Host "vcpkg include path exists. Contents:" - Get-ChildItem -Path $vcpkgIncludePath - } else { - Write-Host "vcpkg include path does not exist." - } - # - name: Build IIS Module - # shell: pwsh - # run: | - # cmake --build "iis\build-${{ matrix.arch }}" --config Release + - name: Build IIS Module + shell: pwsh + run: | + cmake --build "iis\build-${{ matrix.arch }}" --config Release # - name: Package IIS Module with WiX # shell: pwsh diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index b92acf82e0..9366dc7d63 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -199,13 +199,12 @@ endif() option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) - message(Finding YAJL in ${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH ) find_library(YAJL_LIBRARY NAMES yajl - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/lib" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/lib" NO_DEFAULT_PATH ) From d4a91295adb188b5d3739a261720631cc9547964 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 20 Sep 2025 23:57:58 +0800 Subject: [PATCH 439/470] test package --- .github/workflows/test-ci-windows.yml | 51 ++++++++++++++++++++++----- iis/CMakeLists.txt | 5 +++ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d7d966f041..7d4f9bf523 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -92,11 +92,12 @@ jobs: run: | $archFlag = "${{ matrix.arch }}" $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } + $installDir = if ($archFlag -eq "x86") { "x86" } else { "amd64" } cmake ` -DAPACHE_ROOT="$env:APACHE_ROOT" ` -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\install-${{ matrix.arch }}" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` -A $cmakeArch ` -DWITH_SSDEEP=ON ` @@ -109,11 +110,43 @@ jobs: run: | cmake --build "iis\build-${{ matrix.arch }}" --config Release - # - name: Package IIS Module with WiX - # shell: pwsh - # run: | - # $CURRENT_DIR = "${{ github.workspace }}/iis/wix" - # $arch = "${{ matrix.arch }}" - # $wixArch = if ($arch -eq "x86") { "x86" } else { "x64" } - # candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch $wixArch - # light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer-$arch.msi" \ No newline at end of file + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: iis-module-${{ matrix.arch }} + path: iis/build-${{ matrix.arch }}/Release/ + + package: + needs: build + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Download x86 artifacts + uses: actions/download-artifact@v4 + with: + name: iis-module-x86 + path: iis/release/x86/ + + + - name: Download x64 artifacts + uses: actions/download-artifact@v4 + with: + name: iis-module-x64 + path: iis/release/amd64/ + + - name: Package IIS Module with WiX + shell: pwsh + run: | + $CURRENT_DIR = "${{ github.workspace }}\iis\" + candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 + light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer\modsecurityiis-x64.msi" + candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x86 + light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer\modsecurityiis-x86.msi" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: modsecurityiis-installers + path: iis/installer/*.msi diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 9366dc7d63..4f061d2508 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -149,6 +149,8 @@ if(APACHE_ROOT) message(FATAL_ERROR "APACHE_ROOT/lib directory does not exist. Expected: '${APACHE_ROOT}/lib'. Please ensure Apache libraries are available.") endif() + file(TO_CMAKE_PATH "${APACHE_ROOT}" APACHE_ROOT) + # Create imported targets for Apache libraries add_library(Apache::httpd SHARED IMPORTED) set_target_properties(Apache::httpd PROPERTIES @@ -227,6 +229,9 @@ if(WITH_SSDEEP) message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() + + file(TO_CMAKE_PATH "${SSDEEP_ROOT}" SSDEEP_ROOT) + message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") # 查找头文件 From d75eea074d81c366db27575c678452726192764b Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 02:33:02 +0800 Subject: [PATCH 440/470] untest --- .github/workflows/test-ci-windows.yml | 39 +- iis/installer.wxs | 519 +++++--------------------- 2 files changed, 126 insertions(+), 432 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 7d4f9bf523..7fec6392ce 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -123,30 +123,43 @@ jobs: - name: Checkout code uses: actions/checkout@v5 + - name: Download x64 artifacts + uses: actions/download-artifact@v4 + with: + name: iis-module-x64 + path: iis/release/amd64/ + - name: Download x86 artifacts uses: actions/download-artifact@v4 with: name: iis-module-x86 path: iis/release/x86/ + - name: Generate wxs files + shell: pwsh + run: | + heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" + heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" - - name: Download x64 artifacts - uses: actions/download-artifact@v4 - with: - name: iis-module-x64 - path: iis/release/amd64/ - - - name: Package IIS Module with WiX + - name: Compile wxs files + shell: pwsh + run: | + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" + + - name: Link wixobj files into MSI shell: pwsh run: | - $CURRENT_DIR = "${{ github.workspace }}\iis\" - candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x64 - light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer\modsecurityiis-x64.msi" - candle.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wxs" -out "$CURRENT_DIR\installer.wixobj" -arch x86 - light.exe -ext WixUtilExtension -ext WixUIExtension "$CURRENT_DIR\installer.wixobj" -out "$CURRENT_DIR\installer\modsecurityiis-x86.msi" + light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: modsecurityiis-installers + path: iis/installer/modsecurityiis.msi - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: modsecurityiis-installers - path: iis/installer/*.msi + path: iis/installer/modsecurityiis.msi diff --git a/iis/installer.wxs b/iis/installer.wxs index 9197a733bf..7f134bea39 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -17,17 +17,19 @@ - + - + + + @@ -87,24 +89,28 @@ + + + - - VersionNT64 - - NOT VersionNT64 - - - - - + + + VersionNT64 + + NOT VersionNT64 + + + + + @@ -121,7 +127,7 @@ - + @@ -129,437 +135,112 @@ - + - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + - + + - + (NOT &ModSec64=3) AND (NOT &ModSec32=3) &ModSec64=3 OR &ModSec32=3 - + (NOT &ModSec32=3) &ModSec32=3 - + 1 @@ -649,9 +330,9 @@ &ModSec64=3 OR &ModSec32=3 (NOT &ModSec64=3) AND (NOT &ModSec32=3) - + &ModSec32=3 - + NOT Installed OR WixUI_InstallMode = "Change" NOT Installed OR WixUI_InstallMode = "Change" Installed AND PATCH @@ -686,12 +367,12 @@ - + - + @@ -701,45 +382,45 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file From 3b67ddeabe322190c30a9024efb1407878674a30 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 02:41:15 +0800 Subject: [PATCH 441/470] but untest --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 7fec6392ce..d9dfd1f0a6 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -145,7 +145,7 @@ jobs: shell: pwsh run: | candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" - candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ - name: Link wixobj files into MSI shell: pwsh From df8e7e44001740cb55b7d184cc6b4b82d99dbb6f Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 02:48:01 +0800 Subject: [PATCH 442/470] sorry --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d9dfd1f0a6..10c4ec5657 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -144,7 +144,7 @@ jobs: - name: Compile wxs files shell: pwsh run: | - candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ - name: Link wixobj files into MSI From 66b20eaa0819fbe092055fee3a85da392ae4bc68 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 03:20:48 +0800 Subject: [PATCH 443/470] find iis --- .github/workflows/test-ci-windows.yml | 313 ++++++++++++++------------ 1 file changed, 167 insertions(+), 146 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 10c4ec5657..1ee54f4b31 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,157 +9,178 @@ on: - v2/test-ci-windows jobs: - build: - strategy: - matrix: - arch: [x86, x64] - runs-on: windows-latest + # build: + # strategy: + # matrix: + # arch: [x86, x64] + # runs-on: windows-latest - # For Caching - permissions: - actions: read - contents: read - - steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Install Apache for x86 - if: matrix.arch == 'x86' - shell: pwsh - run: | - $apachePath = "${{ github.workspace }}\apache-x86" - New-Item -ItemType Directory -Path $apachePath -Force - choco install apache-httpd -y --force --forcex86 --no-progress -r --params="`"/installLocation:$apachePath /noService`"" - echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Set Apache path for x64 - if: matrix.arch == 'x64' - shell: pwsh - run: | - echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Setup MSYS2 - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} - update: true - install: > - git - make - autoconf - automake - libtool - ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} - ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} - - - name: Clone and build ssdeep - shell: msys2 {0} - run: | - MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - echo "Converted workspace path: $MSYS2_WORKSPACE" - - git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - cd ssdeep - autoreconf -i + # # For Caching + # permissions: + # actions: read + # contents: read + + # steps: + # - name: Checkout code + # uses: actions/checkout@v5 + + # - name: Install Apache for x86 + # if: matrix.arch == 'x86' + # shell: pwsh + # run: | + # $apachePath = "${{ github.workspace }}\apache-x86" + # New-Item -ItemType Directory -Path $apachePath -Force + # choco install apache-httpd -y --force --forcex86 --no-progress -r --params="`"/installLocation:$apachePath /noService`"" + # echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # - name: Set Apache path for x64 + # if: matrix.arch == 'x64' + # shell: pwsh + # run: | + # echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # - name: Setup MSYS2 + # uses: msys2/setup-msys2@v2 + # with: + # msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} + # update: true + # install: > + # git + # make + # autoconf + # automake + # libtool + # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} + + # - name: Clone and build ssdeep + # shell: msys2 {0} + # run: | + # MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') + # echo "Converted workspace path: $MSYS2_WORKSPACE" + + # git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + # cd ssdeep + # autoreconf -i - if [ "${{ matrix.arch }}" = "x86" ]; then - ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 - else - ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - fi + # if [ "${{ matrix.arch }}" = "x86" ]; then + # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 + # else + # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + # fi - make dll - - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" - mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" - cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" - cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" - cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" - - - name: Restore vcpkg cache - id: vcpkg-cache - uses: TAServers/vcpkg-cache@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - prefix: vcpkg-iis-module-${{ matrix.arch }}/ - - - name: Configure CMake for IIS Module - env: - VCPKG_FEATURE_FLAGS: "binarycaching" - VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" - VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-windows - run: | - $archFlag = "${{ matrix.arch }}" - $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } - $installDir = if ($archFlag -eq "x86") { "x86" } else { "amd64" } - - cmake ` - -DAPACHE_ROOT="$env:APACHE_ROOT" ` - -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` - -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` - -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` - -A $cmakeArch ` - -DWITH_SSDEEP=ON ` - -DWITH_LUA=ON ` - -DWITH_YAJL=ON ` - -S IIS -B "iis\build-${{ matrix.arch }}" - - - name: Build IIS Module - shell: pwsh - run: | - cmake --build "iis\build-${{ matrix.arch }}" --config Release - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: iis-module-${{ matrix.arch }} - path: iis/build-${{ matrix.arch }}/Release/ + # make dll + + # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" + # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" + # cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" + # cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" + # cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" + + # - name: Restore vcpkg cache + # id: vcpkg-cache + # uses: TAServers/vcpkg-cache@v3 + # with: + # token: ${{ secrets.GITHUB_TOKEN }} + # prefix: vcpkg-iis-module-${{ matrix.arch }}/ + + # - name: Configure CMake for IIS Module + # env: + # VCPKG_FEATURE_FLAGS: "binarycaching" + # VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" + # VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-windows + # run: | + # $archFlag = "${{ matrix.arch }}" + # $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } + # $installDir = if ($archFlag -eq "x86") { "x86" } else { "amd64" } + + # cmake ` + # -DAPACHE_ROOT="$env:APACHE_ROOT" ` + # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` + # -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` + # -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + # -A $cmakeArch ` + # -DWITH_SSDEEP=ON ` + # -DWITH_LUA=ON ` + # -DWITH_YAJL=ON ` + # -S IIS -B "iis\build-${{ matrix.arch }}" + + # - name: Build IIS Module + # shell: pwsh + # run: | + # cmake --build "iis\build-${{ matrix.arch }}" --config Release + + # - name: Upload artifacts + # uses: actions/upload-artifact@v4 + # with: + # name: iis-module-${{ matrix.arch }} + # path: iis/build-${{ matrix.arch }}/Release/ - package: - needs: build + # package: + # needs: build + # runs-on: windows-latest + # steps: + # - name: Checkout code + # uses: actions/checkout@v5 + + # - name: Download x64 artifacts + # uses: actions/download-artifact@v4 + # with: + # name: iis-module-x64 + # path: iis/release/amd64/ + + # - name: Download x86 artifacts + # uses: actions/download-artifact@v4 + # with: + # name: iis-module-x86 + # path: iis/release/x86/ + + # - name: Generate wxs files + # shell: pwsh + # run: | + # heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" + # heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" + + # - name: Compile wxs files + # shell: pwsh + # run: | + # candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ + # candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ + + # - name: Link wixobj files into MSI + # shell: pwsh + # run: | + # light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" + + # - name: Upload artifacts + # uses: actions/upload-artifact@v4 + # with: + # name: modsecurityiis-installers + # path: iis/modsecurityiis.msi + + test: + needs: package runs-on: windows-latest steps: - - name: Checkout code - uses: actions/checkout@v5 - - - name: Download x64 artifacts - uses: actions/download-artifact@v4 - with: - name: iis-module-x64 - path: iis/release/amd64/ - - - name: Download x86 artifacts - uses: actions/download-artifact@v4 - with: - name: iis-module-x86 - path: iis/release/x86/ - - - name: Generate wxs files - shell: pwsh - run: | - heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" - heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" - - - name: Compile wxs files - shell: pwsh - run: | - candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ - candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ - - - name: Link wixobj files into MSI + - name: Enable IIS Feature shell: pwsh run: | - light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: modsecurityiis-installers - path: iis/installer/modsecurityiis.msi - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: modsecurityiis-installers - path: iis/installer/modsecurityiis.msi + $iisStatus = Get-WindowsFeature -Name Web-Server + if ($iisStatus.Installed -eq $false) { + Write-Host "IIS is not installed. Installing now..." + Install-WindowsFeature -Name Web-Server -IncludeManagementTools + } else { + Write-Host "IIS is already installed." + } + Install-WindowsFeature -name Web-Server -IncludeManagementTools + Install-WindowsFeature -name Web-Server, Web-ASP, Web-Mgmt-Tools, Web-WebSockets + + # - name: Download MSI + # uses: actions/download-artifact@v4 + # with: + # name: modsecurityiis-installers + # path: iis/ + + # - name: Install MSI + # shell: pwsh + # run: | \ No newline at end of file From 955e99d9408039b597e7ae7ce1eded2d59368873 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 03:22:05 +0800 Subject: [PATCH 444/470] oh --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 1ee54f4b31..faf1a7a613 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -159,7 +159,7 @@ jobs: # path: iis/modsecurityiis.msi test: - needs: package +# needs: package runs-on: windows-latest steps: - name: Enable IIS Feature From 7024ef914ab8d03b05d0ad0e8ae6042dd92bf750 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 05:01:46 +0800 Subject: [PATCH 445/470] fix --- .github/workflows/test-ci-windows.yml | 327 +++++++++++++------------- iis/CMakeLists.txt | 19 +- 2 files changed, 174 insertions(+), 172 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index faf1a7a613..6efa1da3d8 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -9,178 +9,177 @@ on: - v2/test-ci-windows jobs: - # build: - # strategy: - # matrix: - # arch: [x86, x64] - # runs-on: windows-latest + build: + strategy: + matrix: + arch: [x86, x64] + runs-on: windows-latest - # # For Caching - # permissions: - # actions: read - # contents: read - - # steps: - # - name: Checkout code - # uses: actions/checkout@v5 - - # - name: Install Apache for x86 - # if: matrix.arch == 'x86' - # shell: pwsh - # run: | - # $apachePath = "${{ github.workspace }}\apache-x86" - # New-Item -ItemType Directory -Path $apachePath -Force - # choco install apache-httpd -y --force --forcex86 --no-progress -r --params="`"/installLocation:$apachePath /noService`"" - # echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - # - name: Set Apache path for x64 - # if: matrix.arch == 'x64' - # shell: pwsh - # run: | - # echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - # - name: Setup MSYS2 - # uses: msys2/setup-msys2@v2 - # with: - # msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} - # update: true - # install: > - # git - # make - # autoconf - # automake - # libtool - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} - - # - name: Clone and build ssdeep - # shell: msys2 {0} - # run: | - # MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - # echo "Converted workspace path: $MSYS2_WORKSPACE" - - # git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - # cd ssdeep - # autoreconf -i + # For Caching + permissions: + actions: read + contents: read + + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Install Apache for x86 + if: matrix.arch == 'x86' + shell: pwsh + run: | + $apachePath = "${{ github.workspace }}\apache-x86" + New-Item -ItemType Directory -Path $apachePath -Force + choco install apache-httpd -y --force --forcex86 --no-progress -r --params="'/installLocation:$apachePath /noService'" + echo "APACHE_ROOT=$apachePath\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - name: Set Apache path for x64 + if: matrix.arch == 'x64' + shell: pwsh + run: | + echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + # - name: Setup MSYS2 + # uses: msys2/setup-msys2@v2 + # with: + # msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} + # update: true + # install: > + # git + # make + # autoconf + # automake + # libtool + # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} + + # - name: Clone and build ssdeep + # shell: msys2 {0} + # run: | + # MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') + # echo "Converted workspace path: $MSYS2_WORKSPACE" + + # git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + # cd ssdeep + # autoreconf -i - # if [ "${{ matrix.arch }}" = "x86" ]; then - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 - # else - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - # fi + # if [ "${{ matrix.arch }}" = "x86" ]; then + # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 + # else + # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + # fi - # make dll - - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" - # cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" - # cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" - # cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" - - # - name: Restore vcpkg cache - # id: vcpkg-cache - # uses: TAServers/vcpkg-cache@v3 - # with: - # token: ${{ secrets.GITHUB_TOKEN }} - # prefix: vcpkg-iis-module-${{ matrix.arch }}/ - - # - name: Configure CMake for IIS Module - # env: - # VCPKG_FEATURE_FLAGS: "binarycaching" - # VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" - # VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-windows - # run: | - # $archFlag = "${{ matrix.arch }}" - # $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } - # $installDir = if ($archFlag -eq "x86") { "x86" } else { "amd64" } - - # cmake ` - # -DAPACHE_ROOT="$env:APACHE_ROOT" ` - # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` - # -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` - # -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` - # -A $cmakeArch ` - # -DWITH_SSDEEP=ON ` - # -DWITH_LUA=ON ` - # -DWITH_YAJL=ON ` - # -S IIS -B "iis\build-${{ matrix.arch }}" - - # - name: Build IIS Module - # shell: pwsh - # run: | - # cmake --build "iis\build-${{ matrix.arch }}" --config Release - - # - name: Upload artifacts - # uses: actions/upload-artifact@v4 - # with: - # name: iis-module-${{ matrix.arch }} - # path: iis/build-${{ matrix.arch }}/Release/ + # make dll + + # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" + # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" + # cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" + # cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" + # cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" + + - name: Restore vcpkg cache + id: vcpkg-cache + uses: TAServers/vcpkg-cache@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + prefix: vcpkg-iis-module-${{ matrix.arch }}/ + + - name: Configure CMake for IIS Module + env: + VCPKG_FEATURE_FLAGS: "binarycaching" + VCPKG_BINARY_SOURCES: "clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite" + VCPKG_DEFAULT_TRIPLET: ${{ matrix.arch }}-windows + run: | + $archFlag = "${{ matrix.arch }}" + $cmakeArch = if ($archFlag -eq "x86") { "Win32" } else { "x64" } + $installDir = if ($archFlag -eq "x86") { "x86" } else { "amd64" } + + cmake ` + -DAPACHE_ROOT="$env:APACHE_ROOT" ` + # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` + -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` + -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -A $cmakeArch ` + # -DWITH_SSDEEP=ON ` + -DWITH_LUA=ON ` + -DWITH_YAJL=ON ` + -S IIS -B "iis\build-${{ matrix.arch }}" + + - name: Build IIS Module + shell: pwsh + run: | + cmake --build "iis\build-${{ matrix.arch }}" --config Release + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: iis-module-${{ matrix.arch }} + path: iis/build-${{ matrix.arch }}/Release/ - # package: - # needs: build - # runs-on: windows-latest - # steps: - # - name: Checkout code - # uses: actions/checkout@v5 - - # - name: Download x64 artifacts - # uses: actions/download-artifact@v4 - # with: - # name: iis-module-x64 - # path: iis/release/amd64/ - - # - name: Download x86 artifacts - # uses: actions/download-artifact@v4 - # with: - # name: iis-module-x86 - # path: iis/release/x86/ - - # - name: Generate wxs files - # shell: pwsh - # run: | - # heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" - # heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" - - # - name: Compile wxs files - # shell: pwsh - # run: | - # candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ - # candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ - - # - name: Link wixobj files into MSI - # shell: pwsh - # run: | - # light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" - - # - name: Upload artifacts - # uses: actions/upload-artifact@v4 - # with: - # name: modsecurityiis-installers - # path: iis/modsecurityiis.msi + package: + needs: build + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Download x64 artifacts + uses: actions/download-artifact@v4 + with: + name: iis-module-x64 + path: iis/release/amd64/ + + - name: Download x86 artifacts + uses: actions/download-artifact@v4 + with: + name: iis-module-x86 + path: iis/release/x86/ + + - name: Generate wxs files + shell: pwsh + run: | + heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" + heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" + + - name: Compile wxs files + shell: pwsh + run: | + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ + candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ + + - name: Link wixobj files into MSI + shell: pwsh + run: | + light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: modsecurityiis-installers + path: iis/modsecurityiis.msi test: -# needs: package + needs: package runs-on: windows-latest steps: - - name: Enable IIS Feature + - name: Download MSI + uses: actions/download-artifact@v4 + with: + name: modsecurityiis-installers + path: ${{ github.workspace }}\ + + - name: Install MSI shell: pwsh run: | - $iisStatus = Get-WindowsFeature -Name Web-Server - if ($iisStatus.Installed -eq $false) { - Write-Host "IIS is not installed. Installing now..." - Install-WindowsFeature -Name Web-Server -IncludeManagementTools - } else { - Write-Host "IIS is already installed." - } - Install-WindowsFeature -name Web-Server -IncludeManagementTools - Install-WindowsFeature -name Web-Server, Web-ASP, Web-Mgmt-Tools, Web-WebSockets - - # - name: Download MSI - # uses: actions/download-artifact@v4 - # with: - # name: modsecurityiis-installers - # path: iis/ + msiexec /i modsecurityiis.msi /qn /norestart + + - name: ReStart IIS Feature + shell: pwsh + run: | + Restart-Service W3SVC - # - name: Install MSI - # shell: pwsh - # run: | \ No newline at end of file + - name: Test IIS Module + shell: pwsh + run: | + curl -I http://localhost/ + Get-EventLog -LogName Application -Newest 10 \ No newline at end of file diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 4f061d2508..b984bbada6 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -171,6 +171,12 @@ if(APACHE_ROOT) IMPORTED_LOCATION "${APACHE_ROOT}/bin/libaprutil-1.dll" ) + add_library(Apache::apriconv SHARED IMPORTED) + set_target_properties(Apache::apriconv SHARED IMPORTED PROPERTIES + IMPORTED_IMPLIB "${APACHE_ROOT}/lib/libapriconv-1.lib" + IMPORTED_LOCATION "${APACHE_ROOT}/bin/libapriconv-1.dll" + ) + target_include_directories(${IIS_MODULE_NAME} PRIVATE ${APACHE_ROOT}/include ) @@ -283,9 +289,6 @@ if(WITH_SSDEEP) ) endif() - else() - message(WARNING "SSDEEP include (fuzzy.h) not found at ${SSDEEP_ROOT}/include. Disabling SSDEEP support.") - set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) endif() endif() endif() @@ -335,6 +338,7 @@ if(APACHE_ROOT) Apache::httpd Apache::apr Apache::aprutil + Apache::apriconv ) else() message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") @@ -351,9 +355,6 @@ endif() if(WITH_SSDEEP AND SSDEEP_INCLUDE_DIR AND SSDEEP_GENERATED_LIB) target_link_libraries(${IIS_MODULE_NAME} PRIVATE SSDEEP::fuzzy) -else() - message(WARNING "SSDEEP library not found or generated. Disabling SSDEEP support.") - option(WITH_SSDEEP "Enable SSDEEP support" OFF) # Disable if library not found endif() if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") @@ -364,6 +365,9 @@ if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") COMMAND ${CMAKE_COMMAND} -E copy_if_different "${APACHE_ROOT}/bin/libaprutil-1.dll" $ + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${APACHE_ROOT}/bin/libapriconv-1.dll" + $ COMMENT "Copying Apache DLLs to output directory" ) else() @@ -377,8 +381,6 @@ if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") $ COMMENT "Copying SSDEEP DLL to output directory" ) -else() - message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the SSDEEP installation directory.") endif() @@ -392,6 +394,7 @@ if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") install(FILES "${APACHE_ROOT}/bin/libhttpd.dll" "${APACHE_ROOT}/bin/libaprutil-1.dll" + "${APACHE_ROOT}/bin/libapriconv-1.dll" DESTINATION . ) endif() From a97e8e6f726ff0439bb3f0e2dfe58a9fdb2a097a Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 05:04:05 +0800 Subject: [PATCH 446/470] comment --- .github/workflows/test-ci-windows.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 6efa1da3d8..f39d00005c 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -96,15 +96,16 @@ jobs: cmake ` -DAPACHE_ROOT="$env:APACHE_ROOT" ` - # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` -A $cmakeArch ` - # -DWITH_SSDEEP=ON ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` -S IIS -B "iis\build-${{ matrix.arch }}" + # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` + # -DWITH_SSDEEP=ON ` + - name: Build IIS Module shell: pwsh run: | From 056144060eae7551bd6e481d4aa26bb245075099 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 05:06:45 +0800 Subject: [PATCH 447/470] LLM --- iis/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index b984bbada6..639be7edc3 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -172,7 +172,7 @@ if(APACHE_ROOT) ) add_library(Apache::apriconv SHARED IMPORTED) - set_target_properties(Apache::apriconv SHARED IMPORTED PROPERTIES + set_target_properties(Apache::apriconv PROPERTIES IMPORTED_IMPLIB "${APACHE_ROOT}/lib/libapriconv-1.lib" IMPORTED_LOCATION "${APACHE_ROOT}/bin/libapriconv-1.dll" ) From 2563b1cec7b02d112c44c83134b384714cdaadb4 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 16:15:30 +0800 Subject: [PATCH 448/470] add def --- iis/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index 639be7edc3..ad61443f2e 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -62,6 +62,7 @@ set(IIS_MODULE_SOURCES main.cpp moduleconfig.cpp mymodule.cpp + mymodule.def ) From 67cab1cde1b713a87da1e490c4f55e54ab2b2c62 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 18:00:08 +0800 Subject: [PATCH 449/470] should? --- .github/workflows/test-ci-windows.yml | 19 ++------------- iis/CMakeLists.txt | 35 +++++++-------------------- 2 files changed, 11 insertions(+), 43 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index f39d00005c..328dfd437f 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -136,21 +136,13 @@ jobs: name: iis-module-x86 path: iis/release/x86/ - - name: Generate wxs files + - name: Generate MSI files shell: pwsh run: | heat dir "iis\release\amd64" -cg ModSec64Components -dr inetsrv64 -gg -sreg -srd -var var.ModSecurityIISRelease64 -out "iis\ModSec64.wxs" heat dir "iis\release\x86" -cg ModSec32Components -dr inetsrv32 -gg -sreg -srd -var var.ModSecurityIISRelease32 -out "iis\ModSec32.wxs" - - - name: Compile wxs files - shell: pwsh - run: | candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wxs" "iis\ModSec64.wxs" -arch x64 -dModSecurityIISRelease64="iis\release\amd64\" -out iis\ candle.exe -ext WixUtilExtension -ext WixUIExtension "iis\ModSec32.wxs" -arch x86 -dModSecurityIISRelease32="iis\release\x86\" -out iis\ - - - name: Link wixobj files into MSI - shell: pwsh - run: | light.exe -ext WixUtilExtension -ext WixUIExtension "iis\installer.wixobj" "iis\ModSec32.wixobj" "iis\ModSec64.wixobj" -out "iis\modsecurityiis.msi" - name: Upload artifacts @@ -163,20 +155,13 @@ jobs: needs: package runs-on: windows-latest steps: - - name: Download MSI + - name: Install MSI uses: actions/download-artifact@v4 with: name: modsecurityiis-installers path: ${{ github.workspace }}\ - - - name: Install MSI - shell: pwsh run: | msiexec /i modsecurityiis.msi /qn /norestart - - - name: ReStart IIS Feature - shell: pwsh - run: | Restart-Service W3SVC - name: Test IIS Module diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index ad61443f2e..b7d7c20e5c 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -57,15 +57,6 @@ set(IIS_STANDALONE_SOURCES ../standalone/server.c ) -# Source files for IIS-specific components -set(IIS_MODULE_SOURCES - main.cpp - moduleconfig.cpp - mymodule.cpp - mymodule.def -) - - # Determine architecture if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(ARCHITECTURE "x64") @@ -91,19 +82,18 @@ add_custom_command( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) -set(MC_GENERATED_RES "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.res") -add_custom_command( - OUTPUT ${MC_GENERATED_RES} - COMMAND rc.exe - ARGS /fo "${MC_GENERATED_RES}" "${MC_GENERATED_RC}" - DEPENDS ${MC_GENERATED_RC} - COMMENT "Building resource file: ${MC_GENERATED_RES}" +# Source files for IIS-specific components +set(IIS_MODULE_SOURCES + main.cpp + moduleconfig.cpp + mymodule.cpp + mymodule.def + ${MC_GENERATED_RC} ) set_source_files_properties( ${MC_GENERATED_RC} ${MC_GENERATED_H} - ${MC_GENERATED_RES} PROPERTIES GENERATED TRUE ) @@ -111,7 +101,6 @@ add_library(${IIS_MODULE_NAME} SHARED ${IIS_APACHE_SOURCES} ${IIS_STANDALONE_SOURCES} ${IIS_MODULE_SOURCES} - ${MC_GENERATED_RES} ) # Set the output name and extension @@ -209,11 +198,11 @@ option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/include" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH ) find_library(YAJL_LIBRARY NAMES yajl - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/lib" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/lib" NO_DEFAULT_PATH ) @@ -241,7 +230,6 @@ if(WITH_SSDEEP) message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") - # 查找头文件 find_path(SSDEEP_INCLUDE_DIR fuzzy.h PATHS "${SSDEEP_ROOT}/include" NO_DEFAULT_PATH @@ -252,7 +240,6 @@ if(WITH_SSDEEP) target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_SSDEEP) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_INCLUDE_DIR}) - # 检查 fuzzy.def 文件是否存在 set(SSDEEP_DEF_FILE "${SSDEEP_ROOT}/fuzzy.def") if(NOT EXISTS "${SSDEEP_DEF_FILE}") message(WARNING "fuzzy.def not found at ${SSDEEP_DEF_FILE}. Disabling SSDEEP support.") @@ -261,7 +248,6 @@ if(WITH_SSDEEP) set(SSDEEP_GENERATED_LIB "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.lib") set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/bin/fuzzy.dll") - # 添加自定义命令生成 fuzzy.lib add_custom_command( OUTPUT ${SSDEEP_GENERATED_LIB} COMMAND lib.exe /machine:${ARCHITECTURE} /def:${SSDEEP_DEF_FILE} /out:${SSDEEP_GENERATED_LIB} @@ -270,16 +256,13 @@ if(WITH_SSDEEP) VERBATIM ) - # 确保自定义命令的输出被标记为生成文件 set_source_files_properties(${SSDEEP_GENERATED_LIB} PROPERTIES GENERATED TRUE) - # 添加自定义目标确保生成 fuzzy.lib add_custom_target(generate_ssdeep_lib ALL DEPENDS ${SSDEEP_GENERATED_LIB} COMMENT "Ensuring ssdeep lib is generated" ) - # 使主目标依赖于 fuzzy.lib 的生成 add_dependencies(${IIS_MODULE_NAME} generate_ssdeep_lib) add_library(SSDEEP::fuzzy SHARED IMPORTED) From 3c173f297ae1a97055cb362fe545f1df48622639 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 18:02:44 +0800 Subject: [PATCH 450/470] ok.. --- .github/workflows/test-ci-windows.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 328dfd437f..8b607c910f 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -160,10 +160,13 @@ jobs: with: name: modsecurityiis-installers path: ${{ github.workspace }}\ + + - name: Install MSI + shell: pwsh run: | msiexec /i modsecurityiis.msi /qn /norestart Restart-Service W3SVC - + - name: Test IIS Module shell: pwsh run: | From f82b27baf9a78d67896a69ee87f6ae32599ca76b Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 18:05:43 +0800 Subject: [PATCH 451/470] ...... --- iis/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index b7d7c20e5c..abd2229a60 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -198,11 +198,11 @@ option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH ) find_library(YAJL_LIBRARY NAMES yajl - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/lib" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/lib" NO_DEFAULT_PATH ) From 1fde9d8fff134d186162a704416de294c4af8c35 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 20:37:56 +0800 Subject: [PATCH 452/470] testing --- .github/workflows/test-ci-windows.yml | 131 +++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 8b607c910f..412b4c0f89 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -155,6 +155,9 @@ jobs: needs: package runs-on: windows-latest steps: + - name: Checkout code + uses: actions/checkout@v5 + - name: Install MSI uses: actions/download-artifact@v4 with: @@ -164,11 +167,131 @@ jobs: - name: Install MSI shell: pwsh run: | - msiexec /i modsecurityiis.msi /qn /norestart - Restart-Service W3SVC + $msiPath = "${{ github.workspace }}\modsecurityiis.msi" + if (-not (Test-Path $msiPath)) { + Write-Error "MSI file not found at $msiPath" + exit 1 + } + + # Install with logging for debugging + $installLog = "${{ github.workspace }}\install.log" + $installResult = Start-Process -FilePath "msiexec.exe" -ArgumentList @( + "/i", "`"$msiPath`"", + "/qn", + "/norestart", + "/l*", "`"$installLog`"" + ) -Wait -PassThru + if ($installResult.ExitCode -ne 0) { + Write-Error "MSI installation failed with exit code $($installResult.ExitCode)" + Get-Content $installLog | Write-Host + exit 1 + } + + $installDir = "C:\Program Files\ModSecurity IIS" + $requiredFiles = @( + "modsecurity.conf", + "modsecurity_iis.conf" + ) + + foreach ($file in $requiredFiles) { + $filePath = Join-Path $installDir $file + if (-not (Test-Path $filePath)) { + Write-Error "Required file $file not found in installation directory" + exit 1 + } + } + + - name: Install OWASP Core Rules + shell: pwsh + run: | + $crsVersion = "v4.18.0" + $crsUrl = "https://github.com/coreruleset/coreruleset/archive/refs/tags/$crsVersion.tar.gz" + $crsDir = "C:\Program Files\ModSecurity IIS\coreruleset" + $modSecurityConfigDir = "C:\Program Files\ModSecurity IIS" + + try { + New-Item -ItemType Directory -Path $crsDir -Force + Invoke-WebRequest -Uri $crsUrl -OutFile "$crsDir\$crsVersion.tar.gz" + tar -xzf "$crsDir\$crsVersion.tar.gz" -C $crsDir --strip-components=1 + + Get-ChildItem "$crsDir" -Recurse -Filter "*.example" | ForEach-Object { + $newName = $_.Name.Replace(".example", "") + Rename-Item -Path $_.FullName -NewName $newName + } + + $modSecurityConfigFile = "$modSecurityConfigDir\modsecurity_iis.conf" + + $crsRules = @( + "Include coreruleset/crs-setup.conf", + "Include coreruleset/rules/*.conf", + "Include coreruleset/plugins/*-config.conf", + "Include coreruleset/plugins/*-before.conf", + "Include coreruleset/rules/*.conf", + "Include coreruleset/plugins/*-after.conf" + ) + + Add-Content -Path $modSecurityConfigFile -Value $crsRules + + (Get-Content -Path $modSecurityConfigDir\modsecurity.conf) -replace 'SecRuleEngine DetectionOnly', 'SecRuleEngine On' | Set-Content -Path $modSecurityConfigDir\modsecurity.conf + + } + catch { + Write-Error "Failed to install OWASP Core Rules: $($_.Exception.Message)" + exit 1 + } + - name: Test IIS Module shell: pwsh run: | - curl -I http://localhost/ - Get-EventLog -LogName Application -Newest 10 \ No newline at end of file + $iisConfigDir = "C:\Program Files\ModSecurity IIS\" + + Restart-Service W3SVC -Force + + $modules = & "$env:SystemRoot\system32\inetsrv\appcmd.exe" list modules + if ($LASTEXITCODE -ne 0) { + Write-Error "appcmd failed with exit code $LASTEXITCODE" + exit 1 + } + + if (-not ($modules -match "ModSecurity")) { + Write-Error "ModSecurity module not found in IIS modules" + Write-Host "IIS modules: $modules" + exit 1 + } + + $testCases = @( + @{Url = "http://localhost/"; Description = "Normal request"; ExpectedCode = 200}, + @{Url = "http://localhost/?id=1' OR '1'='1"; Description = "SQL injection attempt"; ExpectedCode = 403}, + @{Url = "http://localhost/?q="; Description = "XSS attempt"; ExpectedCode = 403} + ) + + foreach ($test in $testCases) { + try { + $response = Invoke-WebRequest $test.Url -UseBasicParsing -SkipHttpErrorCheck -TimeoutSec 30 + + if ($response.StatusCode -eq $test.ExpectedCode) { + Write-Host "PASS: $($test.Description) - returned $($response.StatusCode)" + } + else { + Write-Host "FAIL: $($test.Description) - expected $($test.ExpectedCode) but got $($response.StatusCode)" + } + } + catch { + Write-Host "ERROR: $($test.Description) - request failed: $($_.Exception.Message)" + } + } + + + # Check event log + $badMessagePattern = 'Failed to find the RegisterModule entrypoint|The description for Event ID|The data is the error|dll failed to load' + + $events = Get-EventLog -LogName Application -Newest 100 | + Where-Object { $_.Message -match $badMessagePattern } | + Where-Object { $_.Source -match 'IIS|W3SVC|mscor|IIS-W3SVC|IIS-W3WP|ModSecurity' } + + if ($events -and $events.Count -gt 0) { + Write-Host '::error:: Found errors in event log' + $events | Select-Object TimeGenerated, Source, EntryType, EventID, Message | Format-List + Exit 1 + } \ No newline at end of file From e9a9850c46bce5534c92e433b65d5fd83b5e28b6 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sun, 21 Sep 2025 21:40:52 +0800 Subject: [PATCH 453/470] there there --- .github/workflows/test-ci-windows.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 412b4c0f89..14d9f238c9 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -158,7 +158,7 @@ jobs: - name: Checkout code uses: actions/checkout@v5 - - name: Install MSI + - name: Download MSI files uses: actions/download-artifact@v4 with: name: modsecurityiis-installers @@ -294,4 +294,6 @@ jobs: Write-Host '::error:: Found errors in event log' $events | Select-Object TimeGenerated, Source, EntryType, EventID, Message | Format-List Exit 1 - } \ No newline at end of file + } + + Get-EventLog -LogName Application -Source ModSecurity -Newest 10 \ No newline at end of file From 691617b5ae912f35c6fb7ff3f7a1baf69015627a Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Mon, 22 Sep 2025 17:37:19 +0800 Subject: [PATCH 454/470] try to fix ipv6 --- iis/mymodule.cpp | 112 ++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 45 deletions(-) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index e9d5ce3768..d4bec9ba14 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -17,6 +17,9 @@ #undef inline #define inline inline +#include "winsock2.h" +#include + // IIS7 Server API header file #include #include @@ -30,8 +33,6 @@ #include "api.h" #include "moduleconfig.h" -#include "winsock2.h" - class REQUEST_STORED_CONTEXT : public IHttpStoredContext { @@ -90,63 +91,84 @@ 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); - - if(buf == NULL) + if (pAddr == NULL) { return ""; + } - buf[0] = 0; - - WSAAddressToString(pAddr, sizeof(SOCKADDR), NULL, buf, &len); + char ipbuf[INET6_ADDRSTRLEN] = {0}; + const char *res = ""; - // 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; + switch (pAddr->sa_family) { + case AF_INET: + { + SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; + if (InetNtopA(AF_INET, &sin->sin_addr, ipbuf, sizeof(ipbuf)) != NULL) { + res = (const char *)apr_pstrdup(pool, ipbuf); + } else { + res = ""; + } + } + break; + case AF_INET6: + { + SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; + if (InetNtopA(AF_INET6, &sin6->sin6_addr, ipbuf, sizeof(ipbuf)) != NULL) { + res = (const char *)apr_pstrdup(pool, ipbuf); + } else { + res = ""; + } + } + break; + default: + res = ""; + break; } - return buf; + return (char *)res; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - int adrlen = 16, iplen = 4; + apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - if(pAddr->sa_family == AF_INET6) - { - adrlen = 46; - iplen = 16; + addr->pool = pool; + addr->hostname = "unknown"; + addr->servname = addr->hostname; + addr->family = AF_UNSPEC; + addr->addr_str_len = 0; + addr->ipaddr_len = 0; + addr->ipaddr_ptr = NULL; + addr->salen = 0; + addr->port = 0; + + if (pAddr == NULL) { + return addr; } - addr->addr_str_len = adrlen; addr->family = pAddr->sa_family; - addr->hostname = "unknown"; -#ifdef WIN32 - addr->ipaddr_len = sizeof(IN_ADDR); -#else - addr->ipaddr_len = sizeof(struct in_addr); -#endif - addr->ipaddr_ptr = &addr->sa.sin.sin_addr; - addr->pool = pool; - addr->port = 80; -#ifdef WIN32 - memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen); -#else - memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen); -#endif - addr->sa.sin.sin_family = pAddr->sa_family; - addr->sa.sin.sin_port = 80; - addr->salen = sizeof(addr->sa); - addr->servname = addr->hostname; + if (pAddr->sa_family == AF_INET) { + SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; + addr->addr_str_len = INET_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in_addr); + addr->ipaddr_ptr = &addr->sa.sin.sin_addr; + addr->sa.sin.sin_family = AF_INET; + addr->sa.sin.sin_port = sin->sin_port; /* keep network byte order */ + /* copy address */ + memcpy(&addr->sa.sin.sin_addr, &sin->sin_addr, sizeof(struct in_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin->sin_port); + } else if (pAddr->sa_family == AF_INET6) { + SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; + addr->addr_str_len = INET6_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in6_addr); + addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; + addr->sa.sin6.sin6_family = AF_INET6; + addr->sa.sin6.sin6_port = sin6->sin6_port; + memcpy(&addr->sa.sin6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin6->sin6_port); + } return addr; } From e67f3a4fe607282545e53c5b493d725fef57a82b Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Mon, 22 Sep 2025 17:49:28 +0800 Subject: [PATCH 455/470] why config error --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 14d9f238c9..38cd8136f7 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -296,4 +296,4 @@ jobs: Exit 1 } - Get-EventLog -LogName Application -Source ModSecurity -Newest 10 \ No newline at end of file + Get-EventLog -LogName Application -Source ModSecurity | Format-List \ No newline at end of file From 5320e3601548077ee8823964b7d09b3105cc6ebd Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Mon, 22 Sep 2025 18:06:50 +0800 Subject: [PATCH 456/470] fix include --- .github/workflows/test-ci-windows.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 38cd8136f7..d2c0eb2723 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -224,7 +224,6 @@ jobs: $crsRules = @( "Include coreruleset/crs-setup.conf", - "Include coreruleset/rules/*.conf", "Include coreruleset/plugins/*-config.conf", "Include coreruleset/plugins/*-before.conf", "Include coreruleset/rules/*.conf", From c0dc37f484d00f45484c769a8a166f66debfb11b Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Mon, 22 Sep 2025 18:06:50 +0800 Subject: [PATCH 457/470] mujiansu --- .github/workflows/test-ci-windows.yml | 1 - iis/mymodule.cpp | 50 +++++++++------------------ 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 38cd8136f7..d2c0eb2723 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -224,7 +224,6 @@ jobs: $crsRules = @( "Include coreruleset/crs-setup.conf", - "Include coreruleset/rules/*.conf", "Include coreruleset/plugins/*-config.conf", "Include coreruleset/plugins/*-before.conf", "Include coreruleset/rules/*.conf", diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index d4bec9ba14..7e29933b05 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -91,40 +91,22 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - if (pAddr == NULL) { - return ""; - } - - char ipbuf[INET6_ADDRSTRLEN] = {0}; - const char *res = ""; - - switch (pAddr->sa_family) { - case AF_INET: - { - SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; - if (InetNtopA(AF_INET, &sin->sin_addr, ipbuf, sizeof(ipbuf)) != NULL) { - res = (const char *)apr_pstrdup(pool, ipbuf); - } else { - res = ""; - } - } - break; - case AF_INET6: - { - SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; - if (InetNtopA(AF_INET6, &sin6->sin6_addr, ipbuf, sizeof(ipbuf)) != NULL) { - res = (const char *)apr_pstrdup(pool, ipbuf); - } else { - res = ""; - } - } - break; - default: - res = ""; - break; - } - - return (char *)res; + if (pAddr == NULL) { + return ""; + } + + DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + char* buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == NULL) { + return ""; + } + buf[0] = '\0'; + + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { + return ""; + } + + return buf; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) From 97464778b92bc7904ff793dd0ccea338cc24194c Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Tue, 23 Sep 2025 23:29:24 +0800 Subject: [PATCH 458/470] fix(iis): Improve IP address handling and socket address copying functionality Refactor the `GetIpAddr` function to use `GetNameInfo` for IP address retrieval, enhancing IPv6 compatibility. Optimize the `CopySockAddr` function to correctly handle IPv4 and IPv6 addresses and port information. (Implementation based on mujiansu's work in issue #1988) --- iis/mymodule.cpp | 93 +++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index e9d5ce3768..1fd2ee964f 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -90,63 +90,66 @@ 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); - - if(buf == NULL) + if (pAddr == NULL) { return ""; - - buf[0] = 0; - - 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; } - + + DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + char* buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == NULL) { + return ""; + } + buf[0] = '\0'; + + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { + return ""; + } + return buf; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - int adrlen = 16, iplen = 4; + apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - if(pAddr->sa_family == AF_INET6) - { - adrlen = 46; - iplen = 16; + addr->pool = pool; + addr->hostname = "unknown"; + addr->servname = addr->hostname; + addr->family = AF_UNSPEC; + addr->addr_str_len = 0; + addr->ipaddr_len = 0; + addr->ipaddr_ptr = NULL; + addr->salen = 0; + addr->port = 0; + + if (pAddr == NULL) { + return addr; } - addr->addr_str_len = adrlen; addr->family = pAddr->sa_family; - addr->hostname = "unknown"; -#ifdef WIN32 - addr->ipaddr_len = sizeof(IN_ADDR); -#else - addr->ipaddr_len = sizeof(struct in_addr); -#endif - addr->ipaddr_ptr = &addr->sa.sin.sin_addr; - addr->pool = pool; - addr->port = 80; -#ifdef WIN32 - memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen); -#else - memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen); -#endif - addr->sa.sin.sin_family = pAddr->sa_family; - addr->sa.sin.sin_port = 80; - addr->salen = sizeof(addr->sa); - addr->servname = addr->hostname; + if (pAddr->sa_family == AF_INET) { + SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; + addr->addr_str_len = INET_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in_addr); + addr->ipaddr_ptr = &addr->sa.sin.sin_addr; + addr->sa.sin.sin_family = AF_INET; + addr->sa.sin.sin_port = sin->sin_port; /* keep network byte order */ + /* copy address */ + memcpy(&addr->sa.sin.sin_addr, &sin->sin_addr, sizeof(struct in_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin->sin_port); + } else if (pAddr->sa_family == AF_INET6) { + SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; + addr->addr_str_len = INET6_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in6_addr); + addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; + addr->sa.sin6.sin6_family = AF_INET6; + addr->sa.sin6.sin6_port = sin6->sin6_port; + memcpy(&addr->sa.sin6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin6->sin6_port); + } return addr; } From 02d080563df2e8eadbce50aac857f59cbc61b472 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Mon, 20 Oct 2025 13:55:59 +0800 Subject: [PATCH 459/470] fix: SonarCloud issues --- iis/mymodule.cpp | 58 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 1fd2ee964f..5bfadac032 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -90,46 +90,46 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - if (pAddr == NULL) { - return ""; - } - - DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); - char* buf = (char*)apr_palloc(pool, NI_MAXHOST); - if (buf == NULL) { - return ""; - } - buf[0] = '\0'; - - if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { - return ""; - } - - return buf; + if (pAddr == nullptr) { + return apr_pstrdup(pool, ""); + } + + DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + auto buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == nullptr) { + return apr_pstrdup(pool, ""); + } + buf[0] = '\0'; + + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { + return apr_pstrdup(pool, ""); + } + + return buf; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - addr->pool = pool; - addr->hostname = "unknown"; - addr->servname = addr->hostname; - addr->family = AF_UNSPEC; - addr->addr_str_len = 0; - addr->ipaddr_len = 0; - addr->ipaddr_ptr = NULL; - addr->salen = 0; - addr->port = 0; - - if (pAddr == NULL) { + addr->pool = pool; + addr->hostname = "unknown"; + addr->servname = addr->hostname; + addr->family = AF_UNSPEC; + addr->addr_str_len = 0; + addr->ipaddr_len = 0; + addr->ipaddr_ptr = nullptr; + addr->salen = 0; + addr->port = 0; + + if (pAddr == nullptr) { return addr; } addr->family = pAddr->sa_family; if (pAddr->sa_family == AF_INET) { - SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; + auto sin = (SOCKADDR_IN *)pAddr; addr->addr_str_len = INET_ADDRSTRLEN; addr->ipaddr_len = sizeof(struct in_addr); addr->ipaddr_ptr = &addr->sa.sin.sin_addr; @@ -140,7 +140,7 @@ apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) addr->salen = sizeof(addr->sa); addr->port = ntohs(sin->sin_port); } else if (pAddr->sa_family == AF_INET6) { - SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; + auto sin6 = (SOCKADDR_IN6 *)pAddr; addr->addr_str_len = INET6_ADDRSTRLEN; addr->ipaddr_len = sizeof(struct in6_addr); addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; From 65546f0a191be894f0a14cf30d915587f89e0f42 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Tue, 21 Oct 2025 00:02:29 +0800 Subject: [PATCH 460/470] fix: SonarCloud issues --- .github/workflows/test-ci-windows.yml | 3 +++ iis/mymodule.cpp | 23 +++++++++++------------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index d2c0eb2723..405a1186e2 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -84,6 +84,8 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} prefix: vcpkg-iis-module-${{ matrix.arch }}/ + - uses: ammaraskar/msvc-problem-matcher@master + - name: Configure CMake for IIS Module env: VCPKG_FEATURE_FLAGS: "binarycaching" @@ -248,6 +250,7 @@ jobs: Restart-Service W3SVC -Force $modules = & "$env:SystemRoot\system32\inetsrv\appcmd.exe" list modules + Write-Host "IIS modules: $modules" if ($LASTEXITCODE -ne 0) { Write-Error "appcmd failed with exit code $LASTEXITCODE" exit 1 diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 7e29933b05..dfaee4b2cb 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -18,7 +18,6 @@ #define inline inline #include "winsock2.h" -#include // IIS7 Server API header file #include @@ -91,19 +90,19 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - if (pAddr == NULL) { - return ""; + if (pAddr == nullptr) { + return apr_pstrdup(pool, ""); } DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); - char* buf = (char*)apr_palloc(pool, NI_MAXHOST); - if (buf == NULL) { - return ""; + auto buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == nullptr) { + return apr_pstrdup(pool, ""); } buf[0] = '\0'; - if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST) != 0) { - return ""; + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { + return apr_pstrdup(pool, ""); } return buf; @@ -119,18 +118,18 @@ apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) addr->family = AF_UNSPEC; addr->addr_str_len = 0; addr->ipaddr_len = 0; - addr->ipaddr_ptr = NULL; + addr->ipaddr_ptr = nullptr; addr->salen = 0; addr->port = 0; - if (pAddr == NULL) { + if (pAddr == nullptr) { return addr; } addr->family = pAddr->sa_family; if (pAddr->sa_family == AF_INET) { - SOCKADDR_IN *sin = (SOCKADDR_IN *)pAddr; + auto sin = (SOCKADDR_IN *)pAddr; addr->addr_str_len = INET_ADDRSTRLEN; addr->ipaddr_len = sizeof(struct in_addr); addr->ipaddr_ptr = &addr->sa.sin.sin_addr; @@ -141,7 +140,7 @@ apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) addr->salen = sizeof(addr->sa); addr->port = ntohs(sin->sin_port); } else if (pAddr->sa_family == AF_INET6) { - SOCKADDR_IN6 *sin6 = (SOCKADDR_IN6 *)pAddr; + auto sin6 = (SOCKADDR_IN6 *)pAddr; addr->addr_str_len = INET6_ADDRSTRLEN; addr->ipaddr_len = sizeof(struct in6_addr); addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; From 6f53e50297a4c2dab133a7779d17fcf038726b48 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Tue, 21 Oct 2025 01:09:01 +0800 Subject: [PATCH 461/470] build: add ftw cloud test --- .github/workflows/test-ci-windows.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 405a1186e2..f4fa32c751 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -298,4 +298,14 @@ jobs: Exit 1 } - Get-EventLog -LogName Application -Source ModSecurity | Format-List \ No newline at end of file + Get-EventLog -LogName Application -Source ModSecurity | Format-List + + - name: Test ModSecurity Rules + shell: pwsh + run: | + $testRuleDir = "C:\Program Files\ModSecurity IIS\coreruleset\tests\regression\tests" + + go install github.com/coreruleset/go-ftw@latest + cd go\bin + & go-ftw.exe -d $testRuleDir --cloud -e 920380-1 --show-failures-only + From e6192b8056ccc9c10d19056348c0294304348e64 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Tue, 21 Oct 2025 01:31:22 +0800 Subject: [PATCH 462/470] fix: go bin location --- .github/workflows/test-ci-windows.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index f4fa32c751..35614cb786 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -306,6 +306,13 @@ jobs: $testRuleDir = "C:\Program Files\ModSecurity IIS\coreruleset\tests\regression\tests" go install github.com/coreruleset/go-ftw@latest - cd go\bin - & go-ftw.exe -d $testRuleDir --cloud -e 920380-1 --show-failures-only + $goBinPath = "" + if ($env:GOBIN) { + $goBinPath = $env:GOBIN + } elseif ($env:GOPATH) { + $goBinPath = Join-Path $env:GOPATH "bin" + } else { + $goBinPath = Join-Path $env:USERPROFILE "go\bin" + } + & "$goBinPath\go-ftw.exe" -d $testRuleDir --cloud -e 920380-1 --show-failures-only From fa4166ffd97b6798414ea3846c330f09653d2fad Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Tue, 21 Oct 2025 01:45:17 +0800 Subject: [PATCH 463/470] fix: go-ftw command --- .github/workflows/test-ci-windows.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 35614cb786..adc5a874f4 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -300,12 +300,15 @@ jobs: Get-EventLog -LogName Application -Source ModSecurity | Format-List + - name: Install go-ftw + shell: pwsh + run: | + go install github.com/coreruleset/go-ftw@latest + - name: Test ModSecurity Rules shell: pwsh run: | $testRuleDir = "C:\Program Files\ModSecurity IIS\coreruleset\tests\regression\tests" - - go install github.com/coreruleset/go-ftw@latest $goBinPath = "" if ($env:GOBIN) { $goBinPath = $env:GOBIN @@ -314,5 +317,6 @@ jobs: } else { $goBinPath = Join-Path $env:USERPROFILE "go\bin" } - & "$goBinPath\go-ftw.exe" -d $testRuleDir --cloud -e 920380-1 --show-failures-only + + & "$goBinPath\go-ftw.exe" run -d $testRuleDir --cloud -e 920380-1 --show-failures-only From 7eca5bb06d39881c5190e33ba884fd450f0afb00 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Thu, 23 Oct 2025 00:16:50 +0800 Subject: [PATCH 464/470] fix: testing error --- .github/workflows/test-ci-windows.yml | 31 +++++--- iis/CMakeLists.txt | 15 +--- iis/mymodule.cpp | 105 +++++++++++++------------- 3 files changed, 75 insertions(+), 76 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index adc5a874f4..070ce361b2 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -13,6 +13,7 @@ jobs: strategy: matrix: arch: [x86, x64] + config: [Release, RelWithDebInfo] runs-on: windows-latest # For Caching @@ -39,6 +40,10 @@ jobs: run: | echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + # Original Make file contain comment build script for ssdeep, + # which is rely on MSYS2, so we need to install MSYS2. + # If it's enabled, it need msys2 library for ssdeep. + # - name: Setup MSYS2 # uses: msys2/setup-msys2@v2 # with: @@ -103,7 +108,7 @@ jobs: -A $cmakeArch ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` - -S IIS -B "iis\build-${{ matrix.arch }}" + -S IIS -B "iis\build" # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` # -DWITH_SSDEEP=ON ` @@ -111,17 +116,20 @@ jobs: - name: Build IIS Module shell: pwsh run: | - cmake --build "iis\build-${{ matrix.arch }}" --config Release + cmake --build "iis\build" --config ${{ matrix.config }} - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: iis-module-${{ matrix.arch }} - path: iis/build-${{ matrix.arch }}/Release/ + name: iis-module-${{ matrix.arch }}-${{ matrix.config }} + path: iis/build/${{ matrix.config }}/ package: needs: build runs-on: windows-latest + strategy: + matrix: + config: [Release, RelWithDebInfo] steps: - name: Checkout code uses: actions/checkout@v5 @@ -129,13 +137,13 @@ jobs: - name: Download x64 artifacts uses: actions/download-artifact@v4 with: - name: iis-module-x64 + name: iis-module-x64-${{ matrix.config }} path: iis/release/amd64/ - name: Download x86 artifacts uses: actions/download-artifact@v4 with: - name: iis-module-x86 + name: iis-module-x86-${{ matrix.config }} path: iis/release/x86/ - name: Generate MSI files @@ -150,12 +158,15 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: modsecurityiis-installers + name: modsecurityiis-installers-${{ matrix.config }} path: iis/modsecurityiis.msi test: needs: package runs-on: windows-latest + strategy: + matrix: + config: [Release, RelWithDebInfo] steps: - name: Checkout code uses: actions/checkout@v5 @@ -163,8 +174,8 @@ jobs: - name: Download MSI files uses: actions/download-artifact@v4 with: - name: modsecurityiis-installers - path: ${{ github.workspace }}\ + name: modsecurityiis-installers-${{ matrix.config }} + path: ${{ github.workspace }}/ - name: Install MSI shell: pwsh @@ -318,5 +329,5 @@ jobs: $goBinPath = Join-Path $env:USERPROFILE "go\bin" } - & "$goBinPath\go-ftw.exe" run -d $testRuleDir --cloud -e 920380-1 --show-failures-only + & "$goBinPath\go-ftw.exe" run -d $testRuleDir --cloud -e "920100-2$|920100-4$|920100-8$|920100-12$|920272-5$|920290-1$|920620-1$|920380-1$" --show-failures-only diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index abd2229a60..c65dd14d15 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -175,8 +175,6 @@ endif() # Compile definitions to match the original Makefile.win set(MODSECURITY_VERSION_FLAG "VERSION_IIS") # Define the version flag string target_compile_definitions(${IIS_MODULE_NAME} PRIVATE - WIN32 - WINNT inline=APR_INLINE AP_DECLARE_STATIC WITH_CURL @@ -198,11 +196,11 @@ option(WITH_YAJL "Enable YAJL support" OFF) if(WITH_YAJL) # Manually find YAJL if config.cmake is not available (e.g., from vcpkg) find_path(YAJL_INCLUDE_DIR yajl/yajl_common.h - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/include" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/include" NO_DEFAULT_PATH ) find_library(YAJL_LIBRARY NAMES yajl - PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build-${ARCHITECTURE}/vcpkg_installed/${ARCHITECTURE}-windows/lib" + PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/vcpkg_installed/${ARCHITECTURE}-windows/lib" NO_DEFAULT_PATH ) @@ -281,17 +279,10 @@ endif() if(MSVC) target_compile_options(${IIS_MODULE_NAME} PRIVATE /nologo - /O2 /W3 /wd4244 /wd4018 - /MD - /Zi - ) - - # Linker options to match the original Makefile.win - set_target_properties(${IIS_MODULE_NAME} PROPERTIES - LINK_FLAGS "/DEBUG /OPT:REF /OPT:ICF" + ) endif() diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index dfaee4b2cb..98863fdc27 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -17,8 +17,6 @@ #undef inline #define inline inline -#include "winsock2.h" - // IIS7 Server API header file #include #include @@ -32,6 +30,8 @@ #include "api.h" #include "moduleconfig.h" +#include "winsock2.h" + class REQUEST_STORED_CONTEXT : public IHttpStoredContext { @@ -90,66 +90,63 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext char *GetIpAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - if (pAddr == nullptr) { - return apr_pstrdup(pool, ""); - } - - DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); - auto buf = (char*)apr_palloc(pool, NI_MAXHOST); - if (buf == nullptr) { - return apr_pstrdup(pool, ""); - } - buf[0] = '\0'; - - if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { - return apr_pstrdup(pool, ""); - } - - return buf; + 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); + + if(buf == NULL) + return ""; + + buf[0] = 0; + + 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; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); + apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); + int adrlen = 16, iplen = 4; - addr->pool = pool; - addr->hostname = "unknown"; - addr->servname = addr->hostname; - addr->family = AF_UNSPEC; - addr->addr_str_len = 0; - addr->ipaddr_len = 0; - addr->ipaddr_ptr = nullptr; - addr->salen = 0; - addr->port = 0; - - if (pAddr == nullptr) { - return addr; + if(pAddr->sa_family == AF_INET6) + { + adrlen = 46; + iplen = 16; } + addr->addr_str_len = adrlen; addr->family = pAddr->sa_family; - if (pAddr->sa_family == AF_INET) { - auto sin = (SOCKADDR_IN *)pAddr; - addr->addr_str_len = INET_ADDRSTRLEN; - addr->ipaddr_len = sizeof(struct in_addr); - addr->ipaddr_ptr = &addr->sa.sin.sin_addr; - addr->sa.sin.sin_family = AF_INET; - addr->sa.sin.sin_port = sin->sin_port; /* keep network byte order */ - /* copy address */ - memcpy(&addr->sa.sin.sin_addr, &sin->sin_addr, sizeof(struct in_addr)); - addr->salen = sizeof(addr->sa); - addr->port = ntohs(sin->sin_port); - } else if (pAddr->sa_family == AF_INET6) { - auto sin6 = (SOCKADDR_IN6 *)pAddr; - addr->addr_str_len = INET6_ADDRSTRLEN; - addr->ipaddr_len = sizeof(struct in6_addr); - addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; - addr->sa.sin6.sin6_family = AF_INET6; - addr->sa.sin6.sin6_port = sin6->sin6_port; - memcpy(&addr->sa.sin6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); - addr->salen = sizeof(addr->sa); - addr->port = ntohs(sin6->sin6_port); - } + addr->hostname = "unknown"; +#ifdef WIN32 + addr->ipaddr_len = sizeof(IN_ADDR); +#else + addr->ipaddr_len = sizeof(struct in_addr); +#endif + addr->ipaddr_ptr = &addr->sa.sin.sin_addr; + addr->pool = pool; + addr->port = 80; +#ifdef WIN32 + memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen); +#else + memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen); +#endif + addr->sa.sin.sin_family = pAddr->sa_family; + addr->sa.sin.sin_port = 80; + addr->salen = sizeof(addr->sa); + addr->servname = addr->hostname; return addr; } @@ -1324,4 +1321,4 @@ BOOL CMyHttpModule::WriteEventViewerLog(LPCSTR szNotification, WORD category) NULL, 1, 0, &szNotification, NULL ); } return FALSE; -} +} \ No newline at end of file From c85d3997805540a1f7dd56ca704499c584391b82 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Thu, 23 Oct 2025 01:25:12 +0800 Subject: [PATCH 465/470] fix: version number --- .github/workflows/test-ci-windows.yml | 2 +- iis/installer.wxs | 22 +++++++++++----------- iis/mymodule.cpp | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 070ce361b2..8917076169 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -12,7 +12,7 @@ jobs: build: strategy: matrix: - arch: [x86, x64] + arch: [x64, x86] config: [Release, RelWithDebInfo] runs-on: windows-latest diff --git a/iis/installer.wxs b/iis/installer.wxs index 7f134bea39..240db63e22 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + @@ -25,11 +25,11 @@ - + - + @@ -89,18 +89,18 @@ - + - + - + - + VersionNT64 @@ -108,9 +108,9 @@ - + - + @@ -152,7 +152,7 @@ - + @@ -194,7 +194,7 @@ - + diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index 98863fdc27..e9d5ce3768 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -1321,4 +1321,4 @@ BOOL CMyHttpModule::WriteEventViewerLog(LPCSTR szNotification, WORD category) NULL, 1, 0, &szNotification, NULL ); } return FALSE; -} \ No newline at end of file +} From b4e245e4103ba7c4eccf38ad677b694465452ce8 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 25 Oct 2025 00:20:32 +0800 Subject: [PATCH 466/470] build: Enable ssdeep and revert Version --- .github/workflows/test-ci-windows.yml | 82 +++++++++----------- iis/.gitignore | 1 + iis/CMakeLists.txt | 65 ++++------------ iis/installer.wxs | 2 +- iis/mymodule.cpp | 103 +++++++++++++------------- 5 files changed, 106 insertions(+), 147 deletions(-) create mode 100644 iis/.gitignore diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index 8917076169..f616b48bc6 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -2,11 +2,7 @@ name: CI/CD for IIS Module on: push: - branches: - - v2/test-ci-windows pull_request: - branches: - - v2/test-ci-windows jobs: build: @@ -39,48 +35,42 @@ jobs: shell: pwsh run: | echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - # Original Make file contain comment build script for ssdeep, - # which is rely on MSYS2, so we need to install MSYS2. - # If it's enabled, it need msys2 library for ssdeep. - # - name: Setup MSYS2 - # uses: msys2/setup-msys2@v2 - # with: - # msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} - # update: true - # install: > - # git - # make - # autoconf - # automake - # libtool - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} - # ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} - - # - name: Clone and build ssdeep - # shell: msys2 {0} - # run: | - # MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') - # echo "Converted workspace path: $MSYS2_WORKSPACE" - - # git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 - # cd ssdeep - # autoreconf -i + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} + update: true + install: > + git + make + autoconf + automake + libtool + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-gcc' || 'mingw-w64-ucrt-x86_64-gcc' }} + ${{ matrix.arch == 'x86' && 'mingw-w64-i686-pkg-config' || 'mingw-w64-ucrt-x86_64-pkg-config' }} + + - name: Clone and build ssdeep + shell: msys2 {0} + run: | + MSYS2_WORKSPACE=$(cygpath -u '${{ github.workspace }}') + + git clone https://github.com/ssdeep-project/ssdeep.git --depth 1 + cd ssdeep + autoreconf -i - # if [ "${{ matrix.arch }}" = "x86" ]; then - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 - # else - # ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" - # fi + if [ "${{ matrix.arch }}" = "x86" ]; then + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" --build=i686-pc-mingw32 + else + ./configure --enable-shared --disable-static CFLAGS="-O3" CXXFLAGS="-O3" + fi - # make dll + make dll - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin" - # mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include" - # cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/bin/" - # cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/include/" - # cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install-${{ matrix.arch }}/" + mkdir -p "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.dll "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.h "${MSYS2_WORKSPACE}/ssdeep-install/" + cp -v fuzzy.def "${MSYS2_WORKSPACE}/ssdeep-install/" - name: Restore vcpkg cache id: vcpkg-cache @@ -105,14 +95,13 @@ jobs: -DAPACHE_ROOT="$env:APACHE_ROOT" ` -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}\iis\release\$installDir" ` -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT\scripts\buildsystems\vcpkg.cmake" ` + -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install" ` + -DWITH_SSDEEP=ON ` -A $cmakeArch ` -DWITH_LUA=ON ` -DWITH_YAJL=ON ` -S IIS -B "iis\build" - # -DSSDEEP_ROOT="${{ github.workspace }}\ssdeep-install-${{ matrix.arch }}" ` - # -DWITH_SSDEEP=ON ` - - name: Build IIS Module shell: pwsh run: | @@ -316,6 +305,9 @@ jobs: run: | go install github.com/coreruleset/go-ftw@latest + # Certain rules are disabled due to specific IIS behavior patterns. + # Using go-ftw in cloud mode as the IIS connector does not generate logs in file format. + # Technically, Event logs can be streamed to files, but this requires implementing rate limits to avoid log overflow. - name: Test ModSecurity Rules shell: pwsh run: | diff --git a/iis/.gitignore b/iis/.gitignore new file mode 100644 index 0000000000..d16386367f --- /dev/null +++ b/iis/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/iis/CMakeLists.txt b/iis/CMakeLists.txt index c65dd14d15..fe5e1d0f51 100644 --- a/iis/CMakeLists.txt +++ b/iis/CMakeLists.txt @@ -7,10 +7,8 @@ find_package(PCRE2 CONFIG REQUIRED) find_package(CURL CONFIG REQUIRED) find_package(APR CONFIG REQUIRED) -# iis/CMakeLists.txt -set(IIS_MODULE_NAME "modsecurityiis") # Name should match the original output +set(IIS_MODULE_NAME "modsecurityiis") -# Source files for IIS module (reusing Apache sources) set(IIS_APACHE_SOURCES ../apache2/mod_security2.c ../apache2/apache2_config.c @@ -46,7 +44,6 @@ set(IIS_APACHE_SOURCES ../apache2/libinjection/libinjection_xss.c ) -# Source files for standalone components (if they exist in the project) set(IIS_STANDALONE_SOURCES ../standalone/api.c ../standalone/buckets.c @@ -57,18 +54,12 @@ set(IIS_STANDALONE_SOURCES ../standalone/server.c ) -# Determine architecture if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(ARCHITECTURE "x64") else() set(ARCHITECTURE "x86") endif() -# Check if standalone directory exists, if not, exclude those sources -if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) - set(IIS_STANDALONE_SOURCES "") -endif() - set(IIS_RESOURCE_MC "${CMAKE_CURRENT_SOURCE_DIR}/ModSecurityIISMessage.mc") set(MC_GENERATED_RC "${CMAKE_CURRENT_BINARY_DIR}/ModSecurityIISMessage.rc") @@ -110,27 +101,19 @@ set_target_properties(${IIS_MODULE_NAME} PROPERTIES SUFFIX ".dll" ) -# Include directories target_include_directories(${IIS_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../apache2 ${CMAKE_CURRENT_SOURCE_DIR}/../apache2/libinjection ${LIBXML2_INCLUDE_DIR}/libxml + ${CMAKE_CURRENT_SOURCE_DIR}/../standalone ${PCRE2_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${APR_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR} ) -# Include standalone directory if it exists -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../standalone) - target_include_directories(${IIS_MODULE_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/../standalone - ) -endif() - -# Apache-specific includes if(APACHE_ROOT) if(NOT EXISTS "${APACHE_ROOT}") message(FATAL_ERROR "APACHE_ROOT is defined but the directory '${APACHE_ROOT}' does not exist. Please set APACHE_ROOT to a valid Apache installation directory.") @@ -172,7 +155,6 @@ if(APACHE_ROOT) ) endif() -# Compile definitions to match the original Makefile.win set(MODSECURITY_VERSION_FLAG "VERSION_IIS") # Define the version flag string target_compile_definitions(${IIS_MODULE_NAME} PRIVATE inline=APR_INLINE @@ -181,11 +163,10 @@ target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_REMOTE_RULES MSC_LARGE_STREAM_INPUT WITH_YAJL - ${MODSECURITY_VERSION_FLAG} # Use the defined version flag + ${MODSECURITY_VERSION_FLAG} ) option(WITH_LUA "Enable Lua support" OFF) -# Optional compile definitions if(WITH_LUA) find_package(Lua CONFIG REQUIRED) target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_LUA) @@ -211,30 +192,26 @@ if(WITH_YAJL) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${YAJL_INCLUDE_DIRS}) else() message(WARNING "YAJL not found. YAJL_INCLUDE_DIR: '${YAJL_INCLUDE_DIR}', YAJL_LIBRARY: '${YAJL_LIBRARY}'. Please ensure yajl is installed via vcpkg in the vcpkg_installed directory. Disabling YAJL support.") - option(WITH_YAJL "Enable YAJL support" OFF) # Disable if not found + option(WITH_YAJL "Enable YAJL support" OFF) endif() endif() option(WITH_SSDEEP "Enable SSDEEP support" OFF) if(WITH_SSDEEP) - set(SSDEEP_ROOT "" CACHE PATH "Path to manually built ssdeep") - if(NOT SSDEEP_ROOT OR NOT EXISTS "${SSDEEP_ROOT}") + if(NOT EXISTS "${SSDEEP_ROOT}") message(WARNING "SSDEEP_ROOT is not defined or path does not exist. Current SSDEEP_ROOT: '${SSDEEP_ROOT}'. Please set SSDEEP_ROOT to the ssdeep installation directory. Disabling SSDEEP support.") set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() file(TO_CMAKE_PATH "${SSDEEP_ROOT}" SSDEEP_ROOT) - message(STATUS "SSDEEP_ROOT: ${SSDEEP_ROOT}") - find_path(SSDEEP_INCLUDE_DIR fuzzy.h - PATHS "${SSDEEP_ROOT}/include" + PATHS "${SSDEEP_ROOT}" NO_DEFAULT_PATH ) if(SSDEEP_INCLUDE_DIR) - message(STATUS "Found manually built ssdeep include: ${SSDEEP_INCLUDE_DIR}") target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_SSDEEP) target_include_directories(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_INCLUDE_DIR}) @@ -244,7 +221,7 @@ if(WITH_SSDEEP) set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) else() set(SSDEEP_GENERATED_LIB "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.lib") - set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/bin/fuzzy.dll") + set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.dll") add_custom_command( OUTPUT ${SSDEEP_GENERATED_LIB} @@ -271,43 +248,30 @@ if(WITH_SSDEEP) ) endif() + else() + message(WARNING "fuzzy.h not found at ${SSDEEP_INCLUDE_DIR}. Disabling SSDEEP support.") + set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE) endif() endif() endif() -# Compiler-specific options for MSVC to match the original Makefile.win if(MSVC) target_compile_options(${IIS_MODULE_NAME} PRIVATE /nologo /W3 /wd4244 /wd4018 - ) endif() -# Link libraries to match the original Makefile.win target_link_libraries(${IIS_MODULE_NAME} PRIVATE LibXml2::LibXml2 PCRE2::8BIT CURL::libcurl - kernel32 - user32 - gdi32 - winspool - comdlg32 - advapi32 - shell32 - ole32 - oleaut32 - uuid - odbc32 - odbccp32 ws2_32 iphlpapi ) -# Apache-specific libraries if(APACHE_ROOT) target_link_libraries(${IIS_MODULE_NAME} PRIVATE Apache::httpd @@ -319,7 +283,6 @@ else() message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") endif() -# Optional link libraries if(WITH_LUA) target_link_libraries(${IIS_MODULE_NAME} PRIVATE ${LUA_LIBRARIES}) endif() @@ -349,10 +312,10 @@ else() message(WARNING "APACHE_ROOT is not defined or path does not exist. Current APACHE_ROOT: '${APACHE_ROOT}'. Please set APACHE_ROOT to the Apache installation directory.") endif() -if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/fuzzy.dll") add_custom_command(TARGET ${IIS_MODULE_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${SSDEEP_ROOT}/bin/fuzzy.dll" + "${SSDEEP_ROOT}/fuzzy.dll" $ COMMENT "Copying SSDEEP DLL to output directory" ) @@ -374,9 +337,9 @@ if(APACHE_ROOT AND EXISTS "${APACHE_ROOT}/bin") ) endif() -if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/bin/fuzzy.dll") +if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/fuzzy.dll") install(FILES - "${SSDEEP_ROOT}/bin/fuzzy.dll" + "${SSDEEP_ROOT}/fuzzy.dll" DESTINATION . ) endif() diff --git a/iis/installer.wxs b/iis/installer.wxs index 240db63e22..3f17443327 100644 --- a/iis/installer.wxs +++ b/iis/installer.wxs @@ -7,7 +7,7 @@ lightArgs: --> - + diff --git a/iis/mymodule.cpp b/iis/mymodule.cpp index e9d5ce3768..dfaee4b2cb 100644 --- a/iis/mymodule.cpp +++ b/iis/mymodule.cpp @@ -17,6 +17,8 @@ #undef inline #define inline inline +#include "winsock2.h" + // IIS7 Server API header file #include #include @@ -30,8 +32,6 @@ #include "api.h" #include "moduleconfig.h" -#include "winsock2.h" - class REQUEST_STORED_CONTEXT : public IHttpStoredContext { @@ -90,63 +90,66 @@ 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); - - if(buf == NULL) - return ""; - - buf[0] = 0; - - 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; + if (pAddr == nullptr) { + return apr_pstrdup(pool, ""); + } + + DWORD addrSize = pAddr->sa_family == AF_INET ? sizeof(SOCKADDR_IN) : sizeof(SOCKADDR_IN6); + auto buf = (char*)apr_palloc(pool, NI_MAXHOST); + if (buf == nullptr) { + return apr_pstrdup(pool, ""); + } + buf[0] = '\0'; + + if (GetNameInfo(pAddr, addrSize, buf, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST) != 0) { + return apr_pstrdup(pool, ""); + } + + return buf; } apr_sockaddr_t *CopySockAddr(apr_pool_t *pool, PSOCKADDR pAddr) { - apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - int adrlen = 16, iplen = 4; + apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t)); - if(pAddr->sa_family == AF_INET6) - { - adrlen = 46; - iplen = 16; + addr->pool = pool; + addr->hostname = "unknown"; + addr->servname = addr->hostname; + addr->family = AF_UNSPEC; + addr->addr_str_len = 0; + addr->ipaddr_len = 0; + addr->ipaddr_ptr = nullptr; + addr->salen = 0; + addr->port = 0; + + if (pAddr == nullptr) { + return addr; } - addr->addr_str_len = adrlen; addr->family = pAddr->sa_family; - addr->hostname = "unknown"; -#ifdef WIN32 - addr->ipaddr_len = sizeof(IN_ADDR); -#else - addr->ipaddr_len = sizeof(struct in_addr); -#endif - addr->ipaddr_ptr = &addr->sa.sin.sin_addr; - addr->pool = pool; - addr->port = 80; -#ifdef WIN32 - memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, pAddr->sa_data, iplen); -#else - memcpy(&addr->sa.sin.sin_addr.s_addr, pAddr->sa_data, iplen); -#endif - addr->sa.sin.sin_family = pAddr->sa_family; - addr->sa.sin.sin_port = 80; - addr->salen = sizeof(addr->sa); - addr->servname = addr->hostname; + if (pAddr->sa_family == AF_INET) { + auto sin = (SOCKADDR_IN *)pAddr; + addr->addr_str_len = INET_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in_addr); + addr->ipaddr_ptr = &addr->sa.sin.sin_addr; + addr->sa.sin.sin_family = AF_INET; + addr->sa.sin.sin_port = sin->sin_port; /* keep network byte order */ + /* copy address */ + memcpy(&addr->sa.sin.sin_addr, &sin->sin_addr, sizeof(struct in_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin->sin_port); + } else if (pAddr->sa_family == AF_INET6) { + auto sin6 = (SOCKADDR_IN6 *)pAddr; + addr->addr_str_len = INET6_ADDRSTRLEN; + addr->ipaddr_len = sizeof(struct in6_addr); + addr->ipaddr_ptr = &addr->sa.sin6.sin6_addr; + addr->sa.sin6.sin6_family = AF_INET6; + addr->sa.sin6.sin6_port = sin6->sin6_port; + memcpy(&addr->sa.sin6.sin6_addr, &sin6->sin6_addr, sizeof(struct in6_addr)); + addr->salen = sizeof(addr->sa); + addr->port = ntohs(sin6->sin6_port); + } return addr; } From 98a1f9a9d6349327c14dcc37d78e35aa2d8e89c4 Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 25 Oct 2025 02:22:35 +0800 Subject: [PATCH 467/470] fix: pinning commit for some action --- .github/workflows/test-ci-windows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index f616b48bc6..c340d55b76 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -74,12 +74,12 @@ jobs: - name: Restore vcpkg cache id: vcpkg-cache - uses: TAServers/vcpkg-cache@v3 + uses: TAServers/vcpkg-cache@e848939f754daf406a06006be2e05eb5b17cc481 with: token: ${{ secrets.GITHUB_TOKEN }} prefix: vcpkg-iis-module-${{ matrix.arch }}/ - - uses: ammaraskar/msvc-problem-matcher@master + - uses: ammaraskar/msvc-problem-matcher@1ebcb382869bfdc2cc645e8a2a43b6d319ea1cc0 - name: Configure CMake for IIS Module env: From 326da02e920a71969e09daa835f66fc756565c8a Mon Sep 17 00:00:00 2001 From: A13501350 <18516149786@163.com> Date: Sat, 25 Oct 2025 17:53:13 +0800 Subject: [PATCH 468/470] fix: make SonarCloud happy --- .github/workflows/test-ci-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml index c340d55b76..fa27757d33 100644 --- a/.github/workflows/test-ci-windows.yml +++ b/.github/workflows/test-ci-windows.yml @@ -37,7 +37,7 @@ jobs: echo "APACHE_ROOT=C:\tools\Apache24" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Setup MSYS2 - uses: msys2/setup-msys2@v2 + uses: msys2/setup-msys2@fb197b72ce45fb24f17bf3f807a388985654d1f2 with: msystem: ${{ matrix.arch == 'x86' && 'MINGW32' || 'UCRT64' }} update: true From 0f62dd9959d1fd3d9621c13318abd31b9d111504 Mon Sep 17 00:00:00 2001 From: Ervin Hegedus Date: Tue, 28 Oct 2025 19:24:38 +0100 Subject: [PATCH 469/470] Fix libxml2 related deprecated issues --- apache2/msc_crypt.c | 20 ++++++++++++++------ apache2/msc_xml.h | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c index 6aeb30bb54..bd3061a3c6 100644 --- a/apache2/msc_crypt.c +++ b/apache2/msc_crypt.c @@ -1091,14 +1091,22 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { msr_log(msr, 4, "inject_hashed_response_body: Detected encoding type [%s].", encoding ? encoding : "(none)"); - if (handler == NULL) + if (handler == NULL) { handler = xmlFindCharEncodingHandler("UTF-8"); - if (handler == NULL) + encoding = apr_pstrdup(msr->mp, "UTF-8"); + } + if (handler == NULL) { handler = xmlFindCharEncodingHandler("ISO-8859-1"); - if (handler == NULL) + encoding = apr_pstrdup(msr->mp, "ISO-8859-1"); + } + if (handler == NULL) { handler = xmlFindCharEncodingHandler("HTML"); - if (handler == NULL) + encoding = apr_pstrdup(msr->mp, "HTML"); + } + if (handler == NULL) { handler = xmlFindCharEncodingHandler("ascii"); + encoding = apr_pstrdup(msr->mp, "ascii"); + } if(handler == NULL) { xmlFreeDoc(msr->crypto_html_tree); @@ -1106,11 +1114,11 @@ int inject_hashed_response_body(modsec_rec *msr, int elts) { } apr_table_unset(msr->r->headers_out,"Content-Type"); - new_ct = (char*)apr_psprintf(msr->mp, "text/html;%s",handler->name); + new_ct = (char*)apr_psprintf(msr->mp, "text/html;%s",encoding); apr_table_set(msr->r->err_headers_out,"Content-Type",new_ct); if (msr->txcfg->debuglog_level >= 4) - msr_log(msr, 4, "inject_hashed_response_body: Using content-type [%s].", handler->name); + msr_log(msr, 4, "inject_hashed_response_body: Using content-type [%s].", encoding); output_buf = xmlAllocOutputBuffer(handler); if (output_buf == NULL) { diff --git a/apache2/msc_xml.h b/apache2/msc_xml.h index dd232fba4d..73999443a2 100644 --- a/apache2/msc_xml.h +++ b/apache2/msc_xml.h @@ -20,7 +20,7 @@ typedef struct xml_data xml_data; #include "modsecurity.h" #include #include -#include +#include /* Structures */ From f23a64845afda26227658e8fda5e322544381ea7 Mon Sep 17 00:00:00 2001 From: weida Date: Sat, 1 Nov 2025 16:57:49 +0000 Subject: [PATCH 470/470] fix: yajl detection for source installations (#3457) --- build/find_yajl.m4 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build/find_yajl.m4 b/build/find_yajl.m4 index c3d4dcde7e..e0934e8496 100644 --- a/build/find_yajl.m4 +++ b/build/find_yajl.m4 @@ -89,10 +89,14 @@ else yajl_lib_path="${x}/" yajl_lib_name="yajl" break - else + elif test -e "${x}/lib/libyajl.${y}"; then + yajl_lib_path="${x}/lib/" + yajl_lib_name="yajl" + break + else yajl_lib_path="" yajl_lib_name="" - fi + fi done if test -n "$yajl_lib_path"; then break