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-for-version-3-x.md b/.github/ISSUE_TEMPLATE/bug-report-for-version-3-x.md
new file mode 100644
index 0000000000..58874dfb42
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug-report-for-version-3-x.md
@@ -0,0 +1,47 @@
+---
+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.
+
+---
+
+**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/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
+
+
diff --git a/.github/security2.conf b/.github/security2.conf
new file mode 100644
index 0000000000..d9051b007c
--- /dev/null
+++ b/.github/security2.conf
@@ -0,0 +1,8 @@
+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
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..8ba565f099
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,112 @@
+name: Quality Assurance
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ build-linux:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-22.04]
+ platform: [x32, x64]
+ compiler: [gcc, clang]
+ configure:
+ - {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: |
+ 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 --enable-assertions ${{ 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: 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: first check config (to get syntax errors)
+ run: sudo apachectl configtest
+ - name: start apache with module
+ run: sudo systemctl restart apache2.service
+ - name: Search for errors/warnings in error log
+ run: |
+ # '|| :' 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 "${errors}"
+ exit 1
+ - 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
+ - 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
+
+ test-linux:
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-22.04]
+ platform: [x32, x64]
+ compiler: [gcc, clang]
+ configure:
+ - {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: |
+ sudo apt-get update -y -qq
+ 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
+ - 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
diff --git a/.github/workflows/test-ci-windows.yml b/.github/workflows/test-ci-windows.yml
new file mode 100644
index 0000000000..fa27757d33
--- /dev/null
+++ b/.github/workflows/test-ci-windows.yml
@@ -0,0 +1,325 @@
+name: CI/CD for IIS Module
+
+on:
+ push:
+ pull_request:
+
+jobs:
+ build:
+ strategy:
+ matrix:
+ arch: [x64, x86]
+ config: [Release, RelWithDebInfo]
+ 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@fb197b72ce45fb24f17bf3f807a388985654d1f2
+ 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
+
+ make dll
+
+ 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
+ uses: TAServers/vcpkg-cache@e848939f754daf406a06006be2e05eb5b17cc481
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ prefix: vcpkg-iis-module-${{ matrix.arch }}/
+
+ - uses: ammaraskar/msvc-problem-matcher@1ebcb382869bfdc2cc645e8a2a43b6d319ea1cc0
+
+ - 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" `
+ -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"
+
+ - name: Build IIS Module
+ shell: pwsh
+ run: |
+ cmake --build "iis\build" --config ${{ matrix.config }}
+
+ - name: Upload artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ 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
+
+ - name: Download x64 artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: iis-module-x64-${{ matrix.config }}
+ path: iis/release/amd64/
+
+ - name: Download x86 artifacts
+ uses: actions/download-artifact@v4
+ with:
+ name: iis-module-x86-${{ matrix.config }}
+ path: iis/release/x86/
+
+ - 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"
+ 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\
+ 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-${{ 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
+
+ - name: Download MSI files
+ uses: actions/download-artifact@v4
+ with:
+ name: modsecurityiis-installers-${{ matrix.config }}
+ path: ${{ github.workspace }}/
+
+ - name: Install MSI
+ shell: pwsh
+ run: |
+ $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/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: |
+ $iisConfigDir = "C:\Program Files\ModSecurity IIS\"
+
+ 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
+ }
+
+ 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
+ }
+
+ Get-EventLog -LogName Application -Source ModSecurity | Format-List
+
+ - name: Install go-ftw
+ shell: pwsh
+ 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: |
+ $testRuleDir = "C:\Program Files\ModSecurity IIS\coreruleset\tests\regression\tests"
+ $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" 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/.gitignore b/.gitignore
new file mode 100644
index 0000000000..d8d6784f63
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,119 @@
+# 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
+
+# tests
+tests/regression/server_root/**
+tests/*.pl
+tests/*.trs
+tests/*.log
+
+
diff --git a/CHANGES b/CHANGES
index c51479a650..4cf9c09356 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,362 @@
-DD MMM YYYY - 2.9.2 - To be released
-------------------------------------
-
+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
+--------------------
+
+ * 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
+--------------------
+
+ * fix: DoS vulnerability
+ [PR from private repo - @theseion, @fzipi, @airween; fixed CVE-2025-48866]
+
+21 May 2025 - 2.9.9
+-------------------
+
+ * 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]
+ * 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
+ [PR #3257 - @marcstern]
+
+03 Sep 2024 - 2.9.8
+-------------------
+
+ * 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
+ [PR #3190 - @marcstern]
+ * Fixed assert() usage
+ [PR #3202 - @marcstern]
+ * 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
+ [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
+ [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 tmpname
+ [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 obsolete 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
+ [Issue #3072 - @twouters]
+ * 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
+ [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
+ [Issue #2357 - @marcstern, @martinhsv]
+ * Substitute two equals-equals operators in build
+ [Issue #2883 - @Polynomial-C]
+
+04 Jan 2023 - 2.9.7
+-------------------
+
+ * 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
+ [Issue #2843 - @Steve8291, @martinhsv]
+ * 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
+ [Issue #2815, #2834 - @marcstern, @martinhsv]
+ * 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
+ [Issue #2781 - @erkia]
+ * Use pkg-config to find libxml2 first
+ [Issue #2818 - @hughmcmaster]
+ * Support for PCRE2 in mlogc
+ [Issue #2737, #2827 - @martinhsv]
+ * Support for PCRE2
+ [Issue #2737 - @martinhsv]
+
+07 Sep 2022 - 2.9.6
+-------------------
+
+ * 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
+ [Issue #2794 - @marcstern, @martinhsv]
+ * IIS: Update dependencies for next planned release
+ [@martinhsv]
+ * 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
+ [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
+ [Issue #2735 - @marcstern, @martinhsv]
+ * 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
+ [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
+ [@martinhsv]
+
+22 Nov 2021 - 2.9.5
+-------------------
+
+ * Support configurable limit on depth of JSON parsing
+ [@theMiddleBlue, @airween, @dune73, @martinhsv]
+
+21 Jun 2021 - 2.9.4
+-------------------
+
+ * 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
+ [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
+ [Issue #2128 - @marcstern, @zimmerle]
+ * 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
+ [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
+ [Issue #1980 - @zimmerle, @airween]
+
+
+05 Dec 2018 - 2.9.3
+-------------------
+
+ * 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
+ [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
+ [p0pr0ck5, @victorhora]
+ * 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)
+ [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
+ [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
+ [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
+ [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
+ [Issue #1857 - @hsluoyz, @victorhora]
+ * 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
+ [Issue #1889 - Marc Stern]
+ * 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
+ [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
+ 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
+ [Issue #1771 - @Artistan]
+ * 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
+ [Issue #1366 - @allanbomsft]
+ * Fixes SecConnWriteStateLimit
+ [Issue #1545 - @nicjansma]
+ * 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
+ [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
+ [Issue #1510 - @marcstern]
+ * Adds missing headers
+ [Issue #1454 - @devnexen]
+
+
+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.
[Commit 51314 - @defanator]
* Updates libinjection to v3.10.0
@@ -42,6 +398,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
@@ -90,6 +447,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/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..a823585172
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# ModSecurity 2
+
+https://www.modsecurity.org/
+
+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 us here: modsecurity@owasp.org.
+
+## Documentation
+
+Please refer to: [the documentation folder](https://github.com/owasp-modsecurity/ModSecurity/tree/v2/master/doc) for the reference manual.
+
+## Sponsor Note
+
+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).
diff --git a/README_WINDOWS.TXT b/README_WINDOWS.TXT
deleted file mode 100644
index 94c2bc9db9..0000000000
--- a/README_WINDOWS.TXT
+++ /dev/null
@@ -1,192 +0,0 @@
-=====================================================================
-MOD_SECURITY 2.6 Command-line Build notes for Windows 4/2/2011
-by Tom Donovam
-=====================================================================
-
-PREREQUISITES:
-
- Microsoft Visual Studio C++ tested with Visual Studio 2008 (aka VC9)
-
- 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.
-
- PCRE Perl Compatible Regular Expression library from: http://www.pcre.org/ tested with PCRE v8.12
-
- 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
-
- 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)
-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 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 libxml2-2.7.7.tar.gz from ftp://xmlsoft.org/libxml2/
- untar it into C:\work\ creating C:\work\libxml2-2.7.7
-
- 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 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:
-
- 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
-
- Set an environment variable to the Apache source code directory:
-
- SET HTTPD_BUILD=C:\work\httpd-2.2.17
-
- 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.
-
- 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:
-
- IF EXIST %HTTPD_BUILD%\srclib\zlib\zlib.lib DEL %HTTPD_BUILD%\srclib\zlib\zlib.lib
-
-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)
-
- 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
-
- 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
- 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
-
-BUILD 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
-
- 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
-
-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:
-
- 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.
-
-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:
-
- # mod_security requires mod_unique_id
- LoadModule unique_id_module modules/mod_unique_id.so
-
- # mod_security
- LoadModule security2_module modules/mod_security2.so
-
- SecRuleEngine On
- SecDataDir logs
- Include conf/modsecurity_crs/*.conf
- Include conf/modsecurity_crs/base_rules/*.conf
- SecAuditEngine RelevantOnly
- SecAuditLogRelevantStatus "^(?:5|4\d[^4])"
- SecAuditLogType Serial
- SecAuditLogParts ABCDEFGHZ
- SecAuditLog logs/modsecurity.log
-
-
-
-==============================================================================================
-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
-
- # Path to Apache httpd installation
- BASE = C:\Apache2217
-
- # Paths to required libraries
- PCRE = C:\work\pcre-8.12
- CURL = C:\work\curl-7.21.4
-
- # Linking libraries
- LIBS = $(BASE)\lib\libapr-1.lib \
- $(BASE)\lib\libaprutil-1.lib \
- $(PCRE)\pcre.lib \
- $(CURL)\libcurl_imp.lib \
- wsock32.lib
-
-Build the mlogc.exe program:
-
- CD C:\work\mod_security_trunk\mlogc
- NMAKE -f Makefile.win
-
-Copy mlocg.exe to C:\Apache2217\bin\
-
-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:
-
- CollectorRoot "C:/Apache2217/logs"
- ConsoleURI "https://localhost:8888/rpc/auditLogReceiver"
- SensorUsername "test"
- SensorPassword "testtest"
- LogStorageDir "data"
- TransactionLog "mlogc-transaction.log"
- QueuePath "mlogc-queue.log"
- ErrorLog "mlogc-error.log"
- LockFile "mlogc.lck"
- KeepEntries 0
- ErrorLogLevel 2
- MaxConnections 10
- MaxWorkerRequests 1000
- TransactionDelay 50
- StartupDelay 5000
- 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:
-
- SecAuditLog |C:/Apache2217/bin/mlogc.bat
diff --git a/README_WINDOWS.md b/README_WINDOWS.md
new file mode 100644
index 0000000000..dcb7e0db3a
--- /dev/null
+++ b/README_WINDOWS.md
@@ -0,0 +1,194 @@
+
+## ModSecurity 2.x Command-line build notes for Windows
+
+by Tom Donovam, 4/2/2011
+
+
+## Prerequisites:
+
+Dependency | Tested with | Note
+----|------|----
+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
+
+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.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.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.9.4.tar.gz from ftp://xmlsoft.org/libxml2/
+ untar it into C:\work\ creating C:\work\libxml2-2.9.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.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:
+
+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
+
+3. Set an environment variable to the Apache source code directory:
+
+```
+ SET HTTPD_BUILD=C:\work\httpd-2.4.27
+```
+
+### Optional:
+
+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.
+
+```
+ SET INCLUDE=%INCLUDE%;%HTTPD_BUILD%\srclib\openssl\inc32;%HTTPD_BUILD%\srclib\zlib
+ SET LIB=%LIB%;%HTTPD_BUILD%\srclib\openssl\out32dll;%HTTPD_BUILD%\srclib\zlib
+```
+
+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
+```
+
+## Build
+
+### PCRE-8.40
+
+ CD C:\work\pcre-8.40
+ CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True
+ NMAKE
+
+### LibXML2-2.9.4
+
+ CD C:\work\libxml2-2.9.4\win32
+ CSCRIPT configure.js iconv=no vcmanifest=yes zlib=yes
+ NMAKE -f Makefile.msvc
+
+### Lua-5.3.4
+
+ 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.54.0
+
+ 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.9.x
+
+ CD C:\work\mod_security\apache2
+ 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:\Apache2427\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:\Apache2427\modules``:
+
+ C:\work\mod_security\apache2\mod_security2.so
+
+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:\Apache2427\conf\modsecurity_crs``
+
+Add configuration directives to your Apache conf\httpd.conf:
+
+ # mod_security requires mod_unique_id
+ LoadModule unique_id_module modules/mod_unique_id.so
+
+ # mod_security
+ LoadModule security2_module modules/mod_security2.so
+
+ SecRuleEngine On
+ SecDataDir logs
+ Include conf/modsecurity_crs/*.conf
+ Include conf/modsecurity_crs/base_rules/*.conf
+ SecAuditEngine RelevantOnly
+ SecAuditLogRelevantStatus "^(?:5|4\d[^4])"
+ SecAuditLogType Serial
+ SecAuditLogParts ABCDEFGHZ
+ SecAuditLog logs/modsecurity.log
+
+
+## Optional: Build and configure the ModSecurity-2.x MLOGC piped-logging program
+
+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:\Apache2427
+
+ # Paths to required libraries
+ PCRE = C:\work\pcre-8.40
+ CURL = C:\work\curl-7.54.0
+
+ # Linking libraries
+ LIBS = $(BASE)\lib\libapr-1.lib \
+ $(BASE)\lib\libaprutil-1.lib \
+ $(PCRE)\pcre.lib \
+ $(CURL)\libcurl_imp.lib \
+ wsock32.lib
+
+Build the ``mlogc.exe`` program:
+
+ CD C:\work\mod_security_trunk\mlogc
+ NMAKE -f Makefile.win
+
+Copy ``mlocg.exe`` to ``C:\Apache2427\bin\``
+
+Create a new command file ``C:\Apache2427\bin\mlogc.bat`` with one line:
+
+ C:\Apache2427\bin\mlogc.exe C:\Apache2427\conf\mlogc.conf
+
+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:/Apache2427/logs"
+ ConsoleURI "https://localhost:8888/rpc/auditLogReceiver"
+ SensorUsername "test"
+ SensorPassword "testtest"
+ LogStorageDir "data"
+ TransactionLog "mlogc-transaction.log"
+ QueuePath "mlogc-queue.log"
+ ErrorLog "mlogc-error.log"
+ LockFile "mlogc.lck"
+ KeepEntries 0
+ ErrorLogLevel 2
+ MaxConnections 10
+ MaxWorkerRequests 1000
+ TransactionDelay 50
+ StartupDelay 5000
+ 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:
+
+ SecAuditLog |C:/Apache2427/bin/mlogc.bat
diff --git a/apache2/Makefile.am b/apache2/Makefile.am
index e7bf787bdc..50246829bd 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,15 +51,16 @@ 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@ \
@CURL_LDADD@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDADD@ \
@LUA_LDADD@ \
@PCRE_LDADD@ \
+ @PCRE2_LDADD@ \
@YAJL_LDADD@
if AIX
@@ -67,10 +69,10 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -81,10 +83,10 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -95,10 +97,10 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -109,10 +111,10 @@ mod_security2_la_LDFLAGS = -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -123,10 +125,10 @@ 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@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -137,10 +139,10 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -151,10 +153,10 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
@@ -165,10 +167,10 @@ mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \
@APU_LDFLAGS@ \
@APXS_LDFLAGS@ \
@CURL_LDFLAGS@ \
- @LIBXML2_CFLAGS@ \
@LIBXML2_LDFLAGS@ \
@LUA_LDFLAGS@ \
@PCRE_LDFLAGS@ \
+ @PCRE2_LDFLAGS@ \
@YAJL_LDFLAGS@ \
@SSDEEP_LDFLAGS@
endif
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 ce97950f54..f410f40ed5 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
@@ -26,6 +26,9 @@
#include "msc_lua.h"
#endif
+#ifdef APLOG_USE_MODULE
+ APLOG_USE_MODULE(security2);
+#endif
/* -- Directory context creation and initialisation -- */
@@ -50,6 +53,8 @@ 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->arguments_limit = NOT_SET;
dcfg->resbody_access = NOT_SET;
dcfg->debuglog_name = NOT_SET_P;
@@ -161,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;
}
@@ -174,6 +180,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;
@@ -182,11 +191,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. */
@@ -234,7 +246,7 @@ 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. */
@@ -246,7 +258,7 @@ static void copy_rules_phase(apr_pool_t *mp,
} 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. */
@@ -272,18 +284,21 @@ 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)
{
- int ret = 0;
-
- if (parent_ruleset == NULL || child_ruleset == NULL ||
- exceptions_arr == NULL) {
- ret = -1;
- goto failed;
- }
-
+ 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, 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;
+ }
+
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,
@@ -294,9 +309,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;
}
/**
@@ -304,6 +316,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);
@@ -332,6 +346,10 @@ 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->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);
@@ -415,7 +433,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) {
@@ -442,7 +459,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,
@@ -625,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;
}
@@ -648,6 +666,8 @@ 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->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;
@@ -732,8 +752,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;
@@ -751,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;
}
@@ -760,15 +786,17 @@ 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;
- int offset = 0;
#ifdef DEBUG_CONF
ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool,
@@ -890,14 +918,14 @@ 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" */
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)
@@ -947,8 +975,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. */
@@ -993,9 +1020,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
@@ -1022,8 +1052,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) {
@@ -1045,11 +1074,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)) {
@@ -1071,11 +1103,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);
@@ -1097,9 +1125,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
@@ -1107,6 +1133,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 */
@@ -1117,9 +1144,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
@@ -1135,6 +1160,12 @@ 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, "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);
@@ -1143,6 +1174,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
if (strlen(p1) != 1) {
@@ -1157,6 +1196,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
if (strlen(p1) != 1) {
@@ -1170,6 +1217,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;
@@ -1186,6 +1236,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;
@@ -1223,6 +1276,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) {
@@ -1265,6 +1321,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) {
@@ -1278,9 +1337,16 @@ 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;
+#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);
+#endif
if (dcfg->auditlog_relevant_regex == NULL) {
return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1);
}
@@ -1291,6 +1357,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;
@@ -1307,6 +1376,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;
@@ -1323,10 +1395,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "default") == 0) {
dcfg->auditlog_dirperms = NOT_SET;
}
@@ -1345,10 +1423,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "default") == 0) {
dcfg->auditlog_fileperms = NOT_SET;
}
@@ -1367,6 +1451,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);
@@ -1377,6 +1464,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;
@@ -1391,6 +1481,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) {
@@ -1422,6 +1514,13 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
/* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */
@@ -1432,14 +1531,22 @@ 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, "cmd_content_injection: _dcfg is NULL");
+ return 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) {
@@ -1453,6 +1560,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;
@@ -1483,6 +1593,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);
@@ -1495,6 +1608,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);
@@ -1506,6 +1622,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;
@@ -1582,8 +1700,13 @@ 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)
{
- directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return 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, "cmd_disable_backend_compression: _dcfg is NULL");
+ return NULL;
+ }
+ directory_config* dcfg = (directory_config*)_dcfg;
dcfg->disable_backend_compression = flag;
return NULL;
}
@@ -1591,6 +1714,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;
@@ -1651,8 +1776,13 @@ 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, "cmd_stream_inbody_inspection: _dcfg is NULL");
+ return NULL;
+ }
directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return NULL;
dcfg->stream_inbody_inspection = flag;
return NULL;
}
@@ -1670,8 +1800,13 @@ 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, "cmd_stream_outbody_inspection: _dcfg is NULL");
+ return NULL;
+ }
directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return NULL;
dcfg->stream_outbody_inspection = flag;
return NULL;
}
@@ -1688,11 +1823,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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);
@@ -1707,15 +1848,28 @@ 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, ' ');
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,
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);
@@ -1772,11 +1926,16 @@ 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)
{
- directory_config *dcfg = (directory_config *)_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, "cmd_conn_read_state_limit: _dcfg is NULL");
+ return NULL;
+ }
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 " \
@@ -1800,6 +1959,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.");
@@ -1821,11 +1981,16 @@ 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)
{
- directory_config *dcfg = (directory_config *)_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, "cmd_conn_write_state_limit: _dcfg is NULL");
+ return NULL;
+ }
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 " \
@@ -1848,6 +2013,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.");
@@ -1860,11 +2026,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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);
@@ -1878,11 +2050,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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);
@@ -1896,11 +2074,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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);
@@ -1911,12 +2095,67 @@ 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)
+{
+ 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_request_body_json_depth_limit: _dcfg is NULL");
+ return NULL;
+ }
+ directory_config *dcfg = (directory_config *)_dcfg;
+ long int limit;
+
+ 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_arguments_limit(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_arguments_limit: _dcfg is NULL");
+ return NULL;
+ }
+ directory_config *dcfg = (directory_config *)_dcfg;
+ long int limit;
+
+ 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)
{
+ 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_request_body_access: _dcfg is NULL");
+ return 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;
@@ -1939,9 +2178,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1;
else
if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0;
@@ -1955,11 +2201,15 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
/* ENH Validate encoding */
-
dcfg->request_encoding = p1;
return NULL;
@@ -1968,9 +2218,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1;
else
if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0;
@@ -1983,6 +2240,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
long int limit;
@@ -2003,9 +2268,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL;
return NULL;
@@ -2033,9 +2305,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) {
dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL;
return NULL;
@@ -2053,6 +2332,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
char *p1 = apr_pstrdup(cmd->pool, _p1);
@@ -2071,9 +2358,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
+
dcfg->of_mime_types_cleared = 1;
if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) {
@@ -2097,10 +2389,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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");
}
@@ -2134,10 +2432,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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");
}
@@ -2169,10 +2473,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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");
}
@@ -2197,9 +2508,14 @@ 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)
{
- directory_config *dcfg = (directory_config *)_dcfg;
-
- if (dcfg == NULL) return NULL;
+ 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_sever_conn_filters_engine: _dcfg is NULL");
+ return NULL;
+ }
if (strcasecmp(p1, "on") == 0)
{
@@ -2224,10 +2540,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0)
{
dcfg->is_enabled = MODSEC_ENABLED;
@@ -2253,8 +2575,15 @@ 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)
{
- directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return NULL;
+ 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_remote_rules_fail: _dcfg is NULL");
+ return NULL;
+ }
+
if (strncasecmp(p1, "warn", 4) == 0)
{
remote_rules_fail_action = REMOTE_RULES_WARN_ON_FAIL;
@@ -2275,7 +2604,15 @@ 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;
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
#ifdef WITH_REMOTE_RULES
int crypto = 0;
@@ -2283,8 +2620,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)
{
@@ -2347,6 +2682,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;
}
@@ -2364,8 +2701,13 @@ 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, "cmd_rule_inheritance: _dcfg is NULL");
+ return NULL;
+ }
directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return NULL;
dcfg->rule_inheritance = flag;
return NULL;
}
@@ -2373,7 +2715,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
@@ -2385,9 +2729,20 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- 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;
@@ -2412,10 +2767,21 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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, "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));
- 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);
@@ -2437,10 +2803,17 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
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);
@@ -2462,6 +2835,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;
@@ -2484,6 +2859,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";
}
@@ -2493,10 +2870,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- 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);
@@ -2505,10 +2888,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- 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);
@@ -2518,10 +2907,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "default") == 0) {
dcfg->upload_file_limit = NOT_SET;
}
@@ -2535,10 +2930,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "default") == 0) {
dcfg->upload_filemode = NOT_SET;
}
@@ -2557,10 +2958,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0) {
dcfg->upload_keep_files = KEEP_FILES_ON;
} else
@@ -2579,10 +2986,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0)
{
dcfg->upload_validates_files = 1;
@@ -2602,6 +3015,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
/* ENH enforce format (letters, digits, ., _, -) */
@@ -2612,6 +3033,14 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
/* ENH enforce format (letters, digits, ., _, -) */
@@ -2632,9 +3061,15 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0) {
dcfg->xml_external_entity = 1;
}
@@ -2659,9 +3094,15 @@ 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);
+ // 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 (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0) {
dcfg->hash_is_enabled = HASH_ENABLED;
dcfg->hash_enforcement = HASH_ENABLED;
@@ -2676,7 +3117,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
@@ -2686,11 +3127,20 @@ 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);
+ // 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_param: _dcfg is NULL");
+ return NULL;
+ }
+ if (p1 == 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;
- if (dcfg == NULL) return NULL;
-
- if (p1 == NULL) return NULL;
dcfg->crypto_param_name = p1;
return NULL;
@@ -2708,12 +3158,26 @@ 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);
+ // 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_key: _dcfg is NULL");
+ return NULL;
+ }
+ if (_p1 == 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, "cmd_hash_key: _p2 is NULL");
+ return 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;
@@ -2724,16 +3188,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;
}
@@ -2751,6 +3212,19 @@ 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);
+ // 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_method_pm: _dcfg is NULL");
+ return NULL;
+ }
+ if (p1 == 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;
rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method));
const char *_p2 = apr_pstrdup(cmd->pool, p2);
@@ -2758,8 +3232,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;
@@ -2842,11 +3314,19 @@ 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);
+ // 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_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);
- if (dcfg == NULL) return NULL;
-
+
if (strcasecmp(p1, "HashHref") == 0) {
re->type = HASH_URL_HREF_HASH_RX;
re->param = _p2;
@@ -2909,11 +3389,20 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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, "cmd_httpBl_key: p1 is NULL");
+ return NULL;
+ }
directory_config *dcfg = (directory_config *)_dcfg;
- if (dcfg == NULL) return NULL;
-
- if (p1 == NULL) return NULL;
dcfg->httpBlkey = p1;
return NULL;
@@ -2924,6 +3413,13 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (p1 == NULL) {
+ ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_pcre_match_limit: p1 is NULL");
+ return NULL;
+ }
long val;
if (cmd->server->is_virtual) {
@@ -2943,6 +3439,13 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (p1 == NULL) {
+ ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, cmd->pool, "cmd_pcre_match_limit_recursion: p1 is NULL");
+ return NULL;
+ }
long val;
if (cmd->server->is_virtual) {
@@ -2965,11 +3468,22 @@ 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);
+ 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, "cmd_geo_lookup_db: _dcfg is NULL");
+ return NULL;
+ }
+ if (p1 == 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);
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;
}
@@ -2991,6 +3505,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);
@@ -3016,12 +3532,19 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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);
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) {
@@ -3051,11 +3574,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;
}
@@ -3068,10 +3592,16 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (_dcfg == 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;
- if (dcfg == NULL) return NULL;
-
if (strcasecmp(p1, "on") == 0)
dcfg->cache_trans = MODSEC_CACHE_ENABLED;
else if (strcasecmp(p1, "off") == 0)
@@ -3167,6 +3697,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 Success
+* \retval apr_psprintf On error
+*/
+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_parse_xml_into_args: _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 -- */
@@ -3544,6 +4102,22 @@ 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 (
+ "SecArgumentsLimit",
+ cmd_arguments_limit,
+ NULL,
+ CMD_SCOPE_ANY,
+ "maximum number of ARGS that ModSecurity will accept."
+ ),
+
AP_INIT_TAKE1 (
"SecRequestEncoding",
cmd_request_encoding,
@@ -3919,5 +4493,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/apache2_io.c b/apache2/apache2_io.c
index c14dd41318..8deeb01c9a 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
@@ -36,6 +40,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) {
@@ -85,10 +90,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 && 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 +113,36 @@ 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);
+ no_data = 0;
- 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);
+ 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);
+ }
- 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) {
@@ -143,6 +152,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.");
@@ -156,6 +166,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;
@@ -165,40 +179,42 @@ 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) {
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;
@@ -208,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
@@ -242,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) {
@@ -255,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 "
@@ -276,13 +284,19 @@ 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;
}
}
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 HTTP_INTERNAL_SERVER_ERROR;
+ }
+#endif
}
msr->reqbody_length += buflen;
@@ -299,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);
@@ -309,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;
}
}
@@ -328,8 +342,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 ").",
@@ -338,7 +351,13 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) {
msr->if_status = IF_STATUS_WANTS_TO_RUN;
- return 1;
+ if (rcbe == -5) {
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+ if (rcbe < 0) {
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ return APR_SUCCESS;
}
@@ -350,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. */
@@ -411,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.");
@@ -478,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);
@@ -519,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) {
@@ -545,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;
@@ -599,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) {
@@ -632,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';
}
@@ -990,6 +1018,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 24bba0cee9..e13c64b905 100644
--- a/apache2/apache2_util.c
+++ b/apache2/apache2_util.c
@@ -17,10 +17,16 @@
#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.
*/
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;
@@ -57,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;
@@ -95,7 +104,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) {
@@ -195,13 +209,12 @@ 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;
- char *remote = NULL;
- char *parse_remote = NULL;
- char *saved = NULL;
- char *str = NULL;
char str1[1024] = "";
char str2[1256] = "";
@@ -267,21 +280,33 @@ 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
+ 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
+ #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
/* 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);
}
}
@@ -294,6 +319,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);
@@ -307,6 +334,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);
@@ -321,6 +350,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 b6e98e9dcd..97c49646bc 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
@@ -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"
@@ -52,6 +46,10 @@
#include
#endif /* WITH_YAJL */
+#ifdef APLOG_USE_MODULE
+ APLOG_USE_MODULE(security2);
+#endif
+
/* ModSecurity structure */
msc_engine DSOLOCAL *modsecurity = NULL;
@@ -105,39 +103,52 @@ 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!");
}
+#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);
+#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,
+#ifndef WITH_PCRE
+ "ModSecurity: PCRE2 compiled version=\"%s\"; "
+#else
"ModSecurity: PCRE compiled version=\"%s\"; "
- "loaded version=\"%s\"", pcre_vrs, pcre_version());
+#endif
+ "loaded version=\"%s\"", pcre_vrs, pcre_loaded_vrs);
- if (strstr(pcre_version(),pcre_vrs) == NULL) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, "ModSecurity: Loaded PCRE do not match with compiled!");
+ if (strstr(pcre_loaded_vrs,pcre_vrs) == NULL) {
+ 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);
}
@@ -464,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);
}
@@ -480,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;
@@ -762,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) {
@@ -852,6 +868,9 @@ static int hook_request_early(request_rec *r) {
*/
msr = create_tx_context(r);
if (msr == NULL) return DECLINED;
+ if (msr->txcfg->debuglog_level >= 9) {
+ msr_log(msr, 9, "Context created after request failure.");
+ }
#ifdef REQUEST_EARLY
@@ -1013,56 +1032,15 @@ static int hook_request_late(request_rec *r) {
}
rc = read_request_body(msr, &my_error_msg);
- if (rc < 0) {
- 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
@@ -1139,17 +1117,12 @@ 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 && msr->txcfg->debuglog_level >= 9) {
+ msr_log(msr, 9, "Context created after request failure.");
}
}
if (msr == NULL) return;
@@ -1597,7 +1570,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;
}
}
diff --git a/apache2/modsecurity.c b/apache2/modsecurity.c
index dcdb48590c..29ec5167c6 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
@@ -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;
@@ -37,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.";
@@ -59,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);
@@ -114,80 +122,96 @@ msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) {
return msce;
}
-/**
- * Initialise the modsecurity engine. This function must be invoked
- * after configuration processing is complete as Apache needs to know the
- * username it is running as.
- */
-int modsecurity_init(msc_engine *msce, apr_pool_t *mp) {
- apr_status_t rc;
-
- /**
- * Notice that curl is initialized here but never cleaned up. First version
- * of this implementation curl was initialized and cleaned for every
- * utilization. Turns out that it was not only cleaning stuff that was
- * utilized by Curl but also other OpenSSL stuff that was utilized by
- * mod_ssl leading the SSL support to crash.
- */
-#ifdef WITH_CURL
- curl_global_init(CURL_GLOBAL_ALL);
-#endif
- /* Serial audit log mutext */
- rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp);
+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_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock");
- //return HTTP_INTERNAL_SERVER_ERROR;
+ ap_log_perror(APLOG_MARK, APLOG_ERR, rc, mp, " 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(msce->auditlog_lock);
+ rc = ap_unixd_set_global_mutex_perms(*lock);
#else
- rc = unixd_set_global_mutex_perms(msce->auditlog_lock);
+ rc = unixd_set_global_mutex_perms(*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;
+ ap_log_perror(APLOG_MARK, APLOG_ERR, rc, mp, " ModSecurity: Could not set permissions on global mutex");
return -1;
}
#endif /* SET_MUTEX_PERMS */
+#endif /* MSC_TEST */
+ return APR_SUCCESS;
+}
- rc = apr_global_mutex_create(&msce->geo_lock, NULL, APR_LOCK_DEFAULT, mp);
- if (rc != 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;
}
-#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) {
+ 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;
+}
+/**
+ * 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;
}
-#endif /* SET_MUTEX_PERMS */
-#ifdef GLOBAL_COLLECTION_LOCK
- rc = apr_global_mutex_create(&msce->dbm_lock, NULL, APR_LOCK_DEFAULT, mp);
- if (rc != APR_SUCCESS) {
- return -1;
- }
+ 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;
+}
-#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 */
+/**
+ * Initialise the modsecurity engine. This function must be invoked
+ * after configuration processing is complete as Apache needs to know the
+ * username it is running as.
+ */
+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->dbm_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
+ * utilization. Turns out that it was not only cleaning stuff that was
+ * utilized by Curl but also other OpenSSL stuff that was utilized by
+ * mod_ssl leading the SSL support to crash.
+ */
+#ifdef WITH_CURL
+ 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->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;
+#endif /* GLOBAL_COLLECTION_LOCK */
return 1;
}
@@ -314,6 +338,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)
@@ -322,6 +347,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;
}
@@ -525,6 +565,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];
@@ -543,7 +584,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;
+#ifndef WITH_PCRE
+ 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);
@@ -637,6 +682,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;
@@ -668,6 +714,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) {
@@ -754,6 +801,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/modsecurity.h b/apache2/modsecurity.h
index f170034c99..2894717031 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
@@ -95,6 +95,8 @@ 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 ARGUMENTS_LIMIT 1000
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
@@ -241,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 {
@@ -287,6 +293,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;
@@ -488,6 +498,8 @@ struct directory_config {
long int reqbody_inmemory_limit;
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;
@@ -635,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.
@@ -680,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 {
@@ -695,6 +709,11 @@ struct msc_parm {
int pad_2;
};
+/* 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 */
msc_engine DSOLOCAL *modsecurity_create(apr_pool_t *mp, int processing_mode);
diff --git a/apache2/msc_crypt.c b/apache2/msc_crypt.c
index cf6a4a7705..bd3061a3c6 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
@@ -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) {
@@ -66,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;
@@ -188,8 +185,15 @@ 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
+ 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];
@@ -341,6 +345,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;
@@ -381,7 +387,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);
+#ifndef WITH_PCRE
+ 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;
@@ -410,7 +420,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
+#ifndef WITH_PCRE
+ if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
+#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
+#endif
return 1;
}
}
@@ -436,7 +450,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);
+#ifndef WITH_PCRE
+ 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;
@@ -465,7 +483,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
+#ifndef WITH_PCRE
+ if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
+#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
+#endif
return 1;
}
}
@@ -491,7 +513,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);
+#ifndef WITH_PCRE
+ 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;
@@ -520,7 +546,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
+#ifndef WITH_PCRE
+ if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
+#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
+#endif
return 1;
}
}
@@ -546,7 +576,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);
+#ifndef WITH_PCRE
+ 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;
@@ -575,7 +609,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
+#ifndef WITH_PCRE
+ if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
+#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
+#endif
return 1;
}
}
@@ -601,7 +639,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);
+#ifndef WITH_PCRE
+ 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;
@@ -630,7 +672,11 @@ int do_hash_method(modsec_rec *msr, char *link, int type) {
msr_log(msr, 4, "%s.", error_msg);
return -1;
}
+#ifndef WITH_PCRE
+ if (rc != PCRE2_ERROR_NOMATCH) { /* Match. */
+#else
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
+#endif
return 1;
}
}
@@ -1006,6 +1052,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;
@@ -1031,31 +1078,35 @@ 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)
+ 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);
@@ -1063,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) {
@@ -1108,8 +1159,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));
@@ -1139,8 +1190,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));
@@ -1174,9 +1225,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);
@@ -1206,9 +1257,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);
@@ -1245,13 +1296,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) {
@@ -1260,8 +1311,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 +1326,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 +1351,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 +1369,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 +1384,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 +1409,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 +1425,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 +1440,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 +1465,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 +1494,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 +1510,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 +1535,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);
diff --git a/apache2/msc_geo.c b/apache2/msc_geo.c
index 134f40fa21..77f3403708 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"
@@ -43,7 +44,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 +74,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 +104,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 +134,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 {
@@ -240,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)) {
@@ -259,6 +265,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;
@@ -269,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;
@@ -315,11 +324,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 */
@@ -351,13 +356,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;
}
@@ -367,13 +366,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;
}
@@ -398,13 +391,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) {
@@ -493,13 +480,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/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
diff --git a/apache2/msc_json.c b/apache2/msc_json.c
index 0f9a4645e2..cae7bf4f70 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
@@ -16,8 +16,12 @@
#ifdef WITH_YAJL
+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;
/**
@@ -25,8 +29,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));
@@ -48,13 +51,26 @@ 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) {
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;
+ msr->json->yajl_error = apr_psprintf(msr->mp, "More than %ld JSON keys", msr->txcfg->arguments_limit);
+ 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);
@@ -74,6 +90,8 @@ 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);
+ assert(msr->json != NULL);
unsigned char *safe_key = (unsigned char *) NULL;
/**
@@ -105,6 +123,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);
}
@@ -115,6 +134,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"));
@@ -130,6 +150,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);
}
@@ -142,10 +163,75 @@ 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);
+ assert(msr->json != NULL);
+
+ 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);
+ }
+ 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);
+ }
+
+
+ return 1;
+}
+
+
+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;
+
+ /**
+ * 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;
+ }
+ msr->json->current_depth--;
+
+ return 1;
+}
+
/**
* Callback for a new hash, which indicates a new subtree, labeled as the current
* argument name, is being created
@@ -153,6 +239,8 @@ static int yajl_number(void *ctx, const char *value, size_t length)
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
@@ -171,6 +259,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);
@@ -186,6 +279,8 @@ static int yajl_start_map(void *ctx)
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;
/**
@@ -212,6 +307,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;
}
@@ -220,6 +316,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
*/
@@ -233,11 +331,10 @@ 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;
*error_msg = NULL;
msr_log(msr, 4, "JSON parser initialization");
@@ -250,6 +347,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
*
@@ -271,14 +371,25 @@ 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(msr->json != NULL);
+ assert(error_msg != NULL);
*error_msg = NULL;
+ base_offset=buf;
/* 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? */
- *error_msg = yajl_get_error(msr->json->handle, 0, buf, size);
+ if (msr->json->depth_limit_exceeded) {
+ *error_msg = "JSON depth limit exceeded";
+ } 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);
+ }
+ }
return -1;
}
@@ -289,16 +400,23 @@ 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) {
- char *json_data = (char *) NULL;
+ assert(msr != NULL);
+ assert(msr->json != NULL);
+ assert(error_msg != NULL);
- if (error_msg == NULL) return -1;
*error_msg = NULL;
/* 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? */
- *error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0);
+ if (msr->json->depth_limit_exceeded) {
+ *error_msg = "JSON depth limit exceeded";
+ } else {
+ 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;
}
@@ -309,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_json.h b/apache2/msc_json.h
index 02326ec03d..089dab4763 100644
--- a/apache2/msc_json.h
+++ b/apache2/msc_json.h
@@ -39,7 +39,9 @@ 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;
};
/* Functions */
diff --git a/apache2/msc_logging.c b/apache2/msc_logging.c
index c2274c7f57..8c7667ef5b 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;
@@ -230,10 +233,24 @@ 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 *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());
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", userinfo, tstr, uniqueid);
}
/**
@@ -391,6 +408,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;
@@ -506,6 +524,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;
@@ -524,6 +543,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);
@@ -544,6 +564,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;
@@ -632,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;
@@ -734,11 +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) {
- 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");
}
/**
@@ -878,7 +897,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. */
@@ -982,6 +1001,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;
}
@@ -1114,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) {
@@ -1165,7 +1183,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);
@@ -1444,14 +1462,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",
- get_apr_error(msr->mp, rc));
- }
-
+ msr_global_mutex_unlock(msr, msr->modsecurity->auditlog_lock, "Audit log");
return;
}
@@ -1521,6 +1533,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;
@@ -1621,11 +1634,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");
}
@@ -1739,7 +1748,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. */
@@ -1998,7 +2007,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 +2022,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
@@ -2209,7 +2218,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));
}
}
@@ -2224,14 +2233,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",
- get_apr_error(msr->mp, rc));
- }
-
+ msr_global_mutex_unlock(msr, msr->modsecurity->auditlog_lock, "Audit log");
return;
}
@@ -2301,6 +2304,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_lua.c b/apache2/msc_lua.c
index 51be1745b2..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) {
@@ -429,12 +433,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 +463,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");
diff --git a/apache2/msc_multipart.c b/apache2/msc_multipart.c
index 9bf327d2bc..dc24248de7 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
@@ -20,18 +20,22 @@
#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) {
+ assert(msr != NULL);
int i, len;
- if(msr == NULL)
- return;
-
if(msr->mpd == NULL)
return;
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++) {
@@ -78,6 +82,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 */
@@ -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);
@@ -248,9 +255,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. */
@@ -318,7 +326,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. */
@@ -372,12 +387,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.",
@@ -393,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++;
@@ -424,13 +465,16 @@ 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;
+
/* Preserve some bytes for later. */
if ( ((MULTIPART_BUF_SIZE - msr->mpd->bufleft) >= 1)
&& (*(p - 1) == '\n') )
@@ -596,6 +640,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;
@@ -620,6 +666,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 */
@@ -673,10 +720,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;
@@ -695,42 +746,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) {
- return 0;
- }
-
- /* Non-ASCII characters not allowed. */
- if (c > 126) {
+ 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;
}
- 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++;
}
@@ -765,7 +803,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));
@@ -929,6 +968,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) {
@@ -989,6 +1030,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;
@@ -1019,10 +1073,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;
@@ -1081,54 +1137,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;
@@ -1227,6 +1292,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)) {
@@ -1247,6 +1327,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;
@@ -1327,14 +1408,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);
@@ -1373,6 +1454,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_multipart.h b/apache2/msc_multipart.h
index a0f6a08ddf..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
@@ -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/msc_parsers.c b/apache2/msc_parsers.c
index 57f291ec2a..793549a5f6 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
@@ -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,8 @@ 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);
+ assert(invalid_count != NULL);
msc_arg *arg;
apr_size_t i, j;
char *value = NULL;
@@ -266,7 +273,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++;
@@ -340,12 +347,31 @@ 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);
+ 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),
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/apache2/msc_pcre.c b/apache2/msc_pcre.c
index 8534a20914..edaac3ff8f 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,18 +20,25 @@
*/
static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) {
if (regex != NULL) {
+#ifndef WITH_PCRE
+ 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);
-#else
- free(regex->pe);
-#endif
regex->pe = NULL;
}
if (regex->re != NULL) {
pcre_free(regex->re);
regex->re = NULL;
}
+#endif
}
return APR_SUCCESS;
@@ -48,6 +55,88 @@ 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)
+#ifndef WITH_PCRE
+{
+ 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;
+ }
+ PCRE2_UCHAR buffer[256];
+ // Get the error message from the error code
+ pcre2_get_error_message(error_number, buffer, sizeof(buffer));
+#ifdef DEBUG_CONF
+ * _errptr = apr_psprintf(pool, "%s - pattern = %s", buffer, pattern);
+#else
+ * _errptr = apr_pstrdup(pool, buffer);
+#endif
+ return NULL;
+ }
+
+#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;
+ 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;
@@ -75,11 +164,7 @@ void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options,
/* 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;
}
@@ -131,6 +216,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 +229,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 +239,52 @@ 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;
+#ifndef WITH_PCRE
+ {
+ 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);
+
+#ifdef WITH_PCRE_JIT
+ if (regex->jit_compile_rc == 0) {
+ 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, slen,
+ (PCRE2_SIZE)(startoffset), (PCRE2_NO_JIT | (uint32_t)options), match_data, regex->match_context);
+ }
+#else
+ 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) {
+ 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 +319,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)
{
+#ifndef WITH_PCRE
+ 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..e693236e3d 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;
+#ifndef WITH_PCRE
+#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,23 @@ 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 {
+#ifndef WITH_PCRE
+ pcre2_code *re;
+ pcre2_match_context *match_context;
+#ifdef WITH_PCRE_JIT
+ int jit_compile_rc;
+#endif
+
+#else
void *re;
void *pe;
+#endif
const char *pattern;
};
diff --git a/apache2/msc_release.h b/apache2/msc_release.h
index f2fe898d5d..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 "1"
+#define MODSEC_VERSION_MAINT "12"
#define MODSEC_VERSION_TYPE ""
#define MODSEC_VERSION_RELEASE ""
diff --git a/apache2/msc_remote_rules.c b/apache2/msc_remote_rules.c
index 8a6df9e0ab..a3cf688923 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
@@ -326,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);
@@ -714,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;
@@ -787,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_reqbody.c b/apache2/msc_reqbody.c
index a8411fa04d..0877c82598 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));
@@ -41,6 +42,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 +83,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 +166,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 +188,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 +318,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
@@ -396,13 +407,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 +423,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);
@@ -428,10 +439,19 @@ 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;
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;
@@ -443,8 +463,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);
@@ -452,35 +472,84 @@ 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)
+ if (msr->request_content_length > 0) {
+ // Use min of Content-Length and SecRequestBodyLimit
+ 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)
+ allocate_length = buflen;
+ }
+
+ allocated = (char*) calloc(allocate_length, sizeof(char));
+ if (allocated) {
+ msr->stream_input_data = allocated;
+ 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_length);
+ 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) {
+ // If this becomes a hotspot again, consider increasing by some percent extra each time, for fewer reallocs
+ allocate_length = msr->stream_input_length + buflen;
+
+ allocated = (char*) realloc(msr->stream_input_data, allocate_length);
+ if (allocated) {
+ msr->stream_input_data = allocated;
+ 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_length);
+ free(msr->stream_input_data);
+ msr->stream_input_data = NULL;
+ msr->stream_input_length = 0;
+ msr->stream_input_allocated_length = 0;
+ return -1;
+ }
+ }
}
+ // 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;
}
+
/**
* 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;
@@ -554,6 +623,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;
@@ -583,6 +654,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. */
@@ -596,6 +669,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;
@@ -637,7 +723,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;
@@ -680,6 +766,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) {
@@ -726,6 +814,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);
@@ -748,6 +837,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;
@@ -849,6 +940,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. */
@@ -884,15 +977,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/msc_status_engine.c b/apache2/msc_status_engine.c
index 834ecc3ed9..be4150bc23 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
@@ -19,6 +19,9 @@
#ifdef WIN32
#include
#include
+#else
+#include
+#include
#endif
#ifdef DARWIN
@@ -42,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,
@@ -157,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;
@@ -167,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],
@@ -176,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;
}
}
@@ -206,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;
@@ -220,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 );
@@ -263,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;
}
@@ -271,7 +276,6 @@ int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
free(pAdapterInfo);
#endif
-end:
return 0;
failed:
return -1;
@@ -280,7 +284,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;
@@ -314,9 +318,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:
@@ -342,8 +347,13 @@ int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len)
apr = APR_VERSION_STRING;
apr_loaded = apr_version_string();
+#ifndef WITH_PCRE
+ 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
@@ -360,7 +370,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);
@@ -496,4 +506,3 @@ int msc_status_engine_call (void) {
return ret;
}
-
diff --git a/apache2/msc_tree.c b/apache2/msc_tree.c
index c672bd5fd4..feabdd0e03 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
@@ -534,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;
@@ -573,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) {
@@ -619,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;
@@ -655,15 +662,22 @@ TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsig
}
node = CPTRetriveNode(msr, ipdata, ip_bitmask, node);
+ 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.");
}
@@ -699,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];
@@ -754,7 +770,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) {
@@ -780,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) {
@@ -815,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;
@@ -831,13 +849,14 @@ 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));
*(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) {
@@ -858,26 +877,23 @@ 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));
*(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) {
@@ -898,7 +914,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)
{
@@ -907,7 +923,7 @@ 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;
}
diff --git a/apache2/msc_util.c b/apache2/msc_util.c
index 33447ba0d0..471a98a80b 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
@@ -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"
@@ -100,82 +104,44 @@ 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;
- unsigned int d = 0, count = 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;
- *changed = 0;
+ assert(input != NULL);
- len = input_len * 7 + 1;
+ *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 (%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;
}
@@ -401,7 +281,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);
@@ -661,6 +542,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));
@@ -1123,10 +1005,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)apr_time_usec(now),
t.tm_gmtoff < 0 ? '-' : '+',
t.tm_gmtoff / (60 * 60), (t.tm_gmtoff / 60) % 60);
return apr_pstrdup(mp, tstr);
@@ -2370,6 +2254,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;
@@ -2378,6 +2263,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';
@@ -2424,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;
@@ -2442,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. */
}
}
@@ -2462,28 +2352,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;
- }
-
- memset(buf, '\0', len*sizeof(char));
+ if (buf == NULL) return -1;
- 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;
}
@@ -2622,10 +2500,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;
@@ -2695,6 +2570,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;
@@ -2706,26 +2585,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;
}
@@ -2783,6 +2662,9 @@ 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) {
+ return 0;
+ }
memset(mem->memory, '\0', sizeof(realsize + 1));
}
else
@@ -2832,3 +2714,24 @@ 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;
+}
+
+// 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;
+}
diff --git a/apache2/msc_util.h b/apache2/msc_util.h
index f7e1280f21..afff3e7f64 100644
--- a/apache2/msc_util.h
+++ b/apache2/msc_util.h
@@ -15,6 +15,7 @@
#ifndef _UTIL_H_
#define _UTIL_H_
+#include
#include
#include
@@ -164,6 +165,9 @@ 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);
+const char* id_log(msre_rule* rule);
+
int read_line(char *buff, int size, FILE *fp);
size_t msc_curl_write_memory_cb(void *contents, size_t size,
diff --git a/apache2/msc_xml.c b/apache2/msc_xml.c
index a31decb5e1..4f0e07ca05 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
@@ -14,6 +14,133 @@
#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;
+ 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;
+ xml_parser_state->depth++;
+ // 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;
+ 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) {
+ 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, xml_parser_state->currpathbufflen),
+ log_escape_ex(msr->mp,
+ (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 0) : xml_parser_state->currval),
+ 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);
+ 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 = xml_parser_state->currpathbufflen;
+ 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";
+
+ if (msr->txcfg->debuglog_level >= 9) {
+ msr_log(msr, 9, "Adding XML argument '%s' with value '%s'",
+ arg->name, arg->value);
+ }
+
+ 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 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 - 1;
+
+ 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) {
+
+ modsec_rec * msr = (modsec_rec *)ctx;
+ msc_xml_parser_state * xml_parser_state = msr->xml->xml_parser_state;
+
+ // 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);
+ 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.");
+ xmlStopParser((xmlParserCtxtPtr)msr->xml->parsing_ctx_arg);
+ }
+
+}
+
+
static xmlParserInputBufferPtr
xml_unload_external_entity(const char *URI, xmlCharEncoding enc) {
return NULL;
@@ -24,9 +151,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));
@@ -36,6 +164,34 @@ 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->currpathbufflen = 3; // "xml"
+ msr->xml->xml_parser_state->currval = NULL;
+ msr->xml->xml_parser_state->currvalbufflen = 0;
+ // 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;
}
@@ -59,14 +215,15 @@ 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
* 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. */
@@ -84,18 +241,52 @@ 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->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 to parse 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->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;
+ }
+ else {
+ *error_msg = apr_psprintf(msr->mp, "XML: Failed to parse document for ARGS.");
+ }
+ return -1;
+ }
+ }
+ if (msr->xml->xml_error) {
+ *error_msg = msr->xml->xml_error;
return -1;
}
}
@@ -107,27 +298,49 @@ 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. */
- 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->xml->parsing_ctx != NULL &&
+ msr->txcfg->parse_xml_into_args != MSC_XML_ARGS_ONLYARGS) {
+ /* 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. */
- 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 to parse document.");
+ return -1;
+ }
+ }
+
+ 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;
+ }
+ else {
+ *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;
+ return -1;
+ }
+ xmlFreeParserCtxt(msr->xml->parsing_ctx_arg);
+ msr->xml->parsing_ctx_arg = NULL;
}
+
}
return 1;
@@ -137,6 +350,27 @@ 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);
+ if (msr->xml->parsing_ctx->myDoc == msr->xml->doc) {
+ msr->xml->doc = NULL;
+ }
+ }
+ 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..73999443a2 100644
--- a/apache2/msc_xml.h
+++ b/apache2/msc_xml.h
@@ -20,15 +20,37 @@ 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;
+ size_t currvalbufflen;
+ 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;
+
+ /* additional 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/persist_dbm.c b/apache2/persist_dbm.c
index 597d5b8fc7..ba8475cc59 100644
--- a/apache2/persist_dbm.c
+++ b/apache2/persist_dbm.c
@@ -1,806 +1,800 @@
-/*
-* 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;
-
-
- 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, "/", 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;
-
- 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, "/", 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;
-
- 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, "/", msr->txcfg->webappid, "_", col_name, NULL);
- else
- dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", 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)
+{
+ assert(msr != NULL);
+ assert(blob != NULL);
+ 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)
+{
+ assert(msr != NULL);
+ assert(col_name != NULL);
+ 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 = 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);
+ if (rc != APR_SUCCESS) {
+ dbm = NULL;
+#ifdef GLOBAL_COLLECTION_LOCK
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#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
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#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 = 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);
+ 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
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#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
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#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
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#endif
+ }
+
+ return col;
+
+cleanup:
+
+ if ((existing_dbm == NULL) && dbm) {
+ apr_sdbm_close(dbm);
+#ifdef GLOBAL_COLLECTION_LOCK
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_retrieve_ex");
+#endif
+ }
+
+ return NULL;
+}
+
+/**
+ *
+ */
+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;
+
+ 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) {
+ assert(msr != NULL);
+ 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. */
+ 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. */
+ 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
+ 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));
+ 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);
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store");
+#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);
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store");
+#else
+ apr_sdbm_unlock(dbm);
+ apr_sdbm_close(dbm);
+#endif
+ }
+
+ return -1;
+ }
+
+#ifdef GLOBAL_COLLECTION_LOCK
+ apr_sdbm_close(dbm);
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collection_store");
+#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\", 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), value.dsize);
+ }
+
+ return 0;
+
+error:
+ return -1;
+}
+
+/**
+ *
+ */
+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;
+ 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 = 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,
+ CREATEMODE, msr->mp);
+ if (rc != APR_SUCCESS) {
+#ifdef GLOBAL_COLLECTION_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));
+ 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
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale");
+#endif
+ return 1;
+
+error:
+
+ if (dbm) {
+ apr_sdbm_close(dbm);
+#ifdef GLOBAL_COLLECTION_LOCK
+ msr_global_mutex_unlock(msr, msr->modsecurity->dbm_lock, "collections_remove_stale");
+#endif
+ }
+
+ return -1;
+}
\ No newline at end of file
diff --git a/apache2/re.c b/apache2/re.c
index abc6e4d5a5..d067c68419 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",
@@ -53,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;
@@ -60,25 +65,23 @@ 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)
+ if (var == NULL)
return 0;
- if(rule == NULL)
+ if (rule == NULL)
return 0;
- if(rule->actionset == NULL)
+ if (rule->actionset == NULL)
return 0;
- if(rule->actionset->id !=NULL) {
+ assert(exceptions != NULL);
+ {
myvar = apr_pstrdup(msr->mp, var->name);
c = strchr(myvar,':');
- if(c != NULL) {
+ if (c != NULL) {
myname = apr_strtok(myvar,":",&myvalue);
} else {
myname = myvar;
@@ -88,9 +91,9 @@ 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, 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);
@@ -100,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);
@@ -135,14 +138,14 @@ 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));
}
}
}
- if(match == 1)
+ if (match == 1)
return 1;
return 0;
@@ -160,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");
}
@@ -199,20 +202,22 @@ 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(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++) {
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(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 {
@@ -234,38 +239,36 @@ 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(ruleset != NULL);
msre_var **targets = NULL;
const char *current_targets = NULL;
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;
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;
@@ -281,56 +284,36 @@ 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);
- }
-
- name_len = strlen(name);
-
- if(value != NULL)
- value_len = strlen(value);
-
- 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);
+ 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;
}
-#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
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));
+ 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;
@@ -343,22 +326,16 @@ 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) {
- 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) {
+ if (msr) {
msr_log(msr, 9, "Successfully replaced variable");
}
#if !defined(MSC_TEST)
@@ -369,28 +346,24 @@ 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 varibale to replace");
- }
-#endif
+ my_error_msg = apr_psprintf(ruleset->mp, "Cannot find variable to replace");
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;
@@ -405,30 +378,18 @@ 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(msr) {
+ if (msr) {
msr_log(msr, 9, "Trying to append variable name [%s] value [%s]", name, value);
}
#if !defined(MSC_TEST)
@@ -440,45 +401,37 @@ 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) {
- 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;
} else {
- if(msr) {
+ if (msr) {
msr_log(msr, 9, "Skipping variable, already appended");
}
#if !defined(MSC_TEST)
@@ -492,11 +445,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)
@@ -508,26 +461,23 @@ 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 (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);
+ if (target != NULL) free(target);
+ return my_error_msg;
}
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)) {
@@ -564,7 +514,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),
@@ -615,7 +565,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) ? "" : "!",
@@ -633,7 +583,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;
@@ -860,6 +813,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;
@@ -940,6 +894,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)
{
+ // 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);
if (var == NULL) return NULL;
@@ -1458,6 +1415,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;
}
@@ -1470,6 +1428,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;
@@ -1488,6 +1447,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;
@@ -1532,6 +1493,8 @@ 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
@@ -1547,12 +1510,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;
@@ -1562,7 +1525,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);
}
}
@@ -1644,7 +1607,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);
@@ -1663,7 +1626,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);
@@ -1682,13 +1645,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));
@@ -1719,7 +1682,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 */
@@ -1734,7 +1697,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;
@@ -1753,11 +1716,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);
}
@@ -1814,12 +1777,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;
@@ -1827,8 +1790,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;
}
@@ -1852,7 +1815,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;
}
@@ -1889,17 +1852,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->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);
@@ -1929,17 +1886,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->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;
}
@@ -1975,6 +1926,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) {
@@ -2012,6 +1966,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;
@@ -2025,7 +1981,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 {
@@ -2068,6 +2024,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;
@@ -2077,15 +2034,18 @@ 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;
/* 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)) {
+ if (rule->actionset->id != NULL) {
int ruleid = atoi(rule->actionset->id);
if (rule_id_in_range(ruleid, re->param)) {
@@ -2120,7 +2080,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),
@@ -2197,6 +2157,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 = "";
@@ -2302,6 +2263,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;
@@ -2361,12 +2323,19 @@ 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);
+ // Normally useless code, left to be safe for the moment
+ if (error_msg == NULL) {
+ ap_log_perror(APLOG_MARK, APLOG_EMERG, 0, ruleset->mp, "msre_rule_create: error_msg is NULL");
+ return 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));
@@ -2493,6 +2462,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;
@@ -2515,6 +2486,10 @@ 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);
+ 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;
@@ -2528,6 +2503,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);
@@ -2599,6 +2575,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;
@@ -2639,7 +2623,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.",
@@ -2687,22 +2671,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);
}
@@ -2740,7 +2724,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);
@@ -2783,6 +2767,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;
@@ -3107,6 +3096,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. */
@@ -3327,6 +3318,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;
@@ -3364,6 +3357,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.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);
diff --git a/apache2/re_actions.c b/apache2/re_actions.c
index f81ddc87c7..febc4759e1 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;
@@ -51,6 +53,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;
@@ -92,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));
@@ -108,6 +113,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 +175,9 @@ 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(msr->txcfg != NULL);
+ assert(var != NULL);
char *data = NULL;
apr_array_header_t *arr = NULL;
char *p = NULL, *q = NULL, *t = NULL;
@@ -316,6 +325,8 @@ 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);
+ assert(msr->txcfg != NULL);
apr_table_t *table = NULL;
msc_string *var = NULL;
const char *var_name = NULL;
@@ -374,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;
}
@@ -383,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;
}
@@ -409,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;
}
@@ -418,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;
}
@@ -427,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;
}
@@ -436,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;
@@ -464,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;
}
@@ -473,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;
}
@@ -482,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;
}
@@ -491,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) {
@@ -518,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;
}
@@ -526,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;
}
@@ -534,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;
@@ -543,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;
}
@@ -551,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;
}
@@ -559,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;
@@ -568,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;
@@ -582,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;
}
@@ -590,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;
@@ -604,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;
@@ -619,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;
@@ -628,6 +674,10 @@ 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(rule != NULL);
+ assert(rule->actionset != NULL);
+ assert(action != NULL);
msc_string *var = NULL;
var = apr_pcalloc(mptmp, sizeof(msc_string));
@@ -651,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;
@@ -660,6 +712,9 @@ 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(rule != NULL);
+ assert(action != NULL);
msc_string *var = NULL;
var = apr_pcalloc(mptmp, sizeof(msc_string));
@@ -683,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;
@@ -698,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;
@@ -713,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;
}
@@ -722,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;
@@ -738,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;
@@ -762,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)
@@ -777,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",
@@ -788,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;
@@ -795,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;
@@ -953,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);
}
@@ -968,6 +1044,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;
@@ -1235,11 +1313,24 @@ 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);
}
- re = apr_pcalloc(msr->mp, sizeof(rule_exception));
- re->type = RULE_EXCEPTION_REMOVE_ID;
- re->param = (const char *)apr_pstrdup(msr->mp, p1);
- apr_table_addn(msr->removed_targets, apr_pstrdup(msr->mp, p2), (void *)re);
- return 1;
+ if (p2 == NULL) {
+ 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
if (strcasecmp(name, "ruleRemoveTargetByTag") == 0) {
rule_exception *re = NULL;
@@ -1247,27 +1338,26 @@ 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) {
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;
- }
-
- 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;
+ 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;
@@ -1275,35 +1365,59 @@ 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) {
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;
- 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;
+ } 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;
}
+ /* Should never happen, but log if it does. */
+ msr_log(msr, 1, "Internal Error: Unknown ctl action \"%s\".", name);
return -1;
}
/* 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;
@@ -1327,6 +1441,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;
@@ -1339,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;
}
}
@@ -1355,17 +1472,21 @@ 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;
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;
@@ -1400,21 +1521,27 @@ 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;
- if (strcasecmp(sargname, arg->name) == 0) {
+ assert(arg != NULL);
+ 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;
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;
@@ -1430,6 +1557,10 @@ 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(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;
}
@@ -1438,6 +1569,10 @@ 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(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;
}
@@ -1446,6 +1581,9 @@ 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);
+ assert(action->param != NULL);
char *data = apr_pstrdup(mptmp, action->param);
char *env_name = NULL, *env_value = NULL;
char *s = NULL;
@@ -1463,6 +1601,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);
}
@@ -1481,6 +1620,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) {
@@ -1501,6 +1641,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);
@@ -1519,6 +1660,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;
@@ -1540,9 +1684,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;
}
@@ -1702,6 +1850,9 @@ 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);
+ assert(action->param != NULL);
char *data = apr_pstrdup(mptmp, action->param);
char *var_name = NULL, *var_value = NULL;
char *s = NULL;
@@ -1717,7 +1868,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);
@@ -1727,6 +1878,9 @@ 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);
+ assert(action->param != NULL);
char *data = apr_pstrdup(mptmp, action->param);
char *col_name = NULL, *var_name = NULL, *var_value = NULL;
char *s = NULL;
@@ -1824,6 +1978,9 @@ 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);
+ assert(action->param != NULL);
char *data = apr_pstrdup(mptmp, action->param);
char *col_name = NULL, *var_name = NULL, *var_value = NULL;
char *s = NULL;
@@ -1958,6 +2115,10 @@ 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(msr->collections != NULL);
+ assert(msr->txcfg != NULL);
+ assert(real_col_name != NULL);
apr_table_t *table = NULL;
msc_string *var = NULL;
@@ -1971,7 +2132,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. */
@@ -2092,6 +2252,9 @@ 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);
+ assert(action->param != NULL);
char *data = apr_pstrdup(msr->mp, action->param);
char *col_name = NULL, *col_key = NULL;
unsigned int col_key_len;
@@ -2123,6 +2286,9 @@ 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);
+ assert(action->param != NULL);
msc_string *var = NULL;
char *real_col_name = NULL, *col_key = NULL;
unsigned int col_key_len;
@@ -2147,6 +2313,9 @@ 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);
+ assert(action->param != NULL);
msc_string *var = NULL;
char *real_col_name = NULL, *col_key = NULL;
unsigned int col_key_len;
@@ -2171,6 +2340,9 @@ 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);
+ assert(action->param != NULL);
msc_string *var = NULL;
char *real_col_name = NULL, *col_key = NULL;
unsigned int col_key_len;
@@ -2192,6 +2364,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;
@@ -2219,7 +2393,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;
@@ -2247,6 +2423,9 @@ 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);
+ assert(action->param != NULL);
msc_string *var = NULL;
/* Expand any macros in the text */
@@ -2267,6 +2446,9 @@ 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);
+ 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 e54a540700..aa678c0ab5 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-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
@@ -37,6 +37,27 @@
#include "libinjection/libinjection.h"
+#ifdef WITH_PCRE_STUDY
+#ifdef WITH_PCRE_JIT
+#ifndef WITH_PCRE
+/**
+ * @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;
+}
+#endif
+#endif
+#endif
/**
*
@@ -44,6 +65,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 +81,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);
}
@@ -70,6 +94,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 +106,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. */
@@ -99,13 +125,17 @@ 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);
+ // 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, "msre_op_ipmatch_param_init: error_msg is NULL");
+ return -1;
+ }
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);
@@ -131,13 +161,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.");
@@ -171,6 +201,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;
@@ -258,14 +290,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)
{
@@ -298,6 +330,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;
@@ -330,6 +364,14 @@ 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);
+ // 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, "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
@@ -347,7 +389,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;
@@ -469,8 +510,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 +536,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 ) {
@@ -604,24 +656,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';
@@ -629,21 +672,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) {
- 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;
-
+#ifdef MSC_LARGE_STREAM_INPUT
+ 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;
- memset(msr->stream_input_data, 0x0, size+1);
-
+#ifdef MSC_LARGE_STREAM_INPUT
+ msr->stream_input_allocated_length = size;
+#endif
msr->if_stream_changed = 1;
memcpy(msr->stream_input_data, data, size);
@@ -671,13 +713,15 @@ 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;
const char *pattern = rule->op_param;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int rc, jit;
+ int rc, jit = 0;
#endif
#endif
@@ -686,7 +730,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);
+#ifndef WITH_PCRE
+ 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);
@@ -695,7 +744,11 @@ static int msre_op_validateHash_param_init(msre_rule *rule, char **error_msg) {
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #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\"] - "
@@ -731,24 +784,30 @@ 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;
+ int options = 0;
unsigned int target_length;
char *my_error_msg = NULL;
int ovector[33];
int rc;
- const char *pattern = NULL;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int jit;
+ int jit = 0;
#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)
@@ -770,15 +829,20 @@ 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);
+ 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);
}
- regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr,
+#ifndef WITH_PCRE
+ 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(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;
}
@@ -786,9 +850,13 @@ 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) {
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #else
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
+ #endif
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)",
@@ -820,7 +888,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);
+#ifndef WITH_PCRE
+ 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;
@@ -850,7 +922,11 @@ static int msre_op_validateHash_execute(modsec_rec *msr, msre_rule *rule, msre_v
return -1;
}
+#ifndef WITH_PCRE
+ 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;
@@ -914,13 +990,15 @@ 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;
const char *pattern = rule->op_param;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int rc, jit;
+ int rc, jit = 0;
#endif
#endif
@@ -929,7 +1007,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);
+#ifndef WITH_PCRE
+ 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);
@@ -938,7 +1021,11 @@ static int msre_op_rx_param_init(msre_rule *rule, char **error_msg) {
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #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\"] - "
@@ -963,11 +1050,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;
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;
+ int options = 0;
unsigned int target_length;
char *my_error_msg = NULL;
int ovector[33];
@@ -976,16 +1073,14 @@ 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
- int jit;
+ int jit = 0;
#endif
#endif
-
- if (error_msg == NULL) return -1;
*error_msg = NULL;
if (regex == NULL) {
@@ -1004,14 +1099,19 @@ 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);
}
- regex = msc_pregcomp_ex(rule->ruleset->mp, pattern, PCRE_DOTALL | PCRE_DOLLAR_ENDONLY, &errptr, &erroffset, msc_pcre_match_limit, msc_pcre_match_limit_recursion);
+#ifndef WITH_PCRE
+ options = PCRE2_DOTALL | PCRE2_DOLLAR_ENDONLY;
+#else
+ 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(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;
}
@@ -1019,9 +1119,13 @@ 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) {
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #else
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
+ #endif
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)",
@@ -1051,20 +1155,27 @@ 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? */
- 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->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)
+ 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;
+ }
+ else capture = 0;
/* Show when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 6) {
int capcount = 0;
+#ifndef WITH_PCRE
+ 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.");
@@ -1076,7 +1187,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);
+#ifndef WITH_PCRE
+ 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;
@@ -1167,7 +1282,11 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
}
}
+#ifndef WITH_PCRE
+ 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 : ""));
@@ -1190,6 +1309,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;
@@ -1228,6 +1350,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;
@@ -1387,6 +1512,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;
@@ -1396,7 +1526,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)
{
@@ -1468,18 +1600,17 @@ 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;
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;
@@ -1490,8 +1621,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;
}
@@ -1506,7 +1636,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;
@@ -1573,14 +1703,15 @@ 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];
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)
@@ -1588,7 +1719,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);
@@ -1610,15 +1741,23 @@ 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;
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);
+#ifndef WITH_PCRE
+ 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",
@@ -1644,10 +1783,15 @@ 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];
unsigned int offset = 0;
+ int options = 0;
gsb_db *gsb = msr->txcfg->gsb;
const char *match = NULL;
unsigned int match_length;
@@ -1675,7 +1819,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.";
@@ -1686,22 +1830,27 @@ 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)
+#ifndef WITH_PCRE
+ 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)
{
- 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);
@@ -1723,7 +1872,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)
@@ -1735,7 +1884,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);
@@ -1748,7 +1897,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)
@@ -1761,7 +1910,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);
@@ -1776,7 +1925,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));
@@ -1787,7 +1936,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)
@@ -1809,7 +1958,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)
@@ -1820,13 +1969,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);
@@ -1835,7 +1984,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)
@@ -1862,7 +2011,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') {
@@ -1887,7 +2036,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));
@@ -1897,7 +2046,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)
@@ -1917,7 +2066,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)
@@ -1927,13 +2076,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);
@@ -1941,7 +2090,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)
@@ -1977,6 +2126,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;
@@ -1984,6 +2137,8 @@ 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;
+ *error_msg = NULL;
+
str->value = (char *)rule->op_param;
if (str->value == NULL) {
@@ -1993,9 +2148,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;
@@ -2047,15 +2199,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;
@@ -2126,7 +2285,12 @@ 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(error_msg != NULL);
char fingerprint[8];
int issqli;
int capture;
@@ -2158,12 +2322,20 @@ 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(var != NULL);
+ assert(error_msg != NULL);
+ 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) {
@@ -2182,16 +2354,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;
@@ -2199,7 +2378,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);
@@ -2277,14 +2455,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;
@@ -2292,7 +2477,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);
@@ -2333,14 +2517,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;
@@ -2396,14 +2587,26 @@ 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);
+ 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, "msre_op_endsWith_execute: error_msg is NULL");
+ return -1;
+ }
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;
@@ -2411,7 +2614,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);
@@ -2459,12 +2661,19 @@ 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);
+ // 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, "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;
unsigned short int op_len;
- if (error_msg == NULL) return -1;
*error_msg = NULL;
op_len = strlen(pattern);
@@ -2488,12 +2697,20 @@ 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);
+ // 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, "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;
const char *rc;
- if (error_msg == NULL) return -1;
*error_msg = NULL;
if (compiled_pattern == NULL) {
@@ -2536,6 +2753,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;
@@ -2606,6 +2827,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;
@@ -2673,6 +2898,7 @@ static int msre_op_validateSchema_execute(modsec_rec *msr, msre_rule *rule, msre
xmlSchemaFree(schema);
xmlSchemaFreeValidCtxt(validCtx);
+ xmlSchemaFreeParserCtxt(parserCtx);
return 0;
}
@@ -2683,6 +2909,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;
@@ -2716,15 +2943,24 @@ 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;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
+#ifndef WITH_PCRE
+ 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);
@@ -2737,6 +2973,11 @@ 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;
const char *target;
unsigned int target_length;
@@ -2745,17 +2986,17 @@ 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;
msc_parm *mparm = NULL;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int jit;
+ int jit = 0;
#endif
#endif
- if (error_msg == NULL) return -1;
*error_msg = NULL;
if (regex == NULL) {
@@ -2763,14 +3004,20 @@ 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
#ifdef WITH_PCRE_JIT
if (msr->txcfg->debuglog_level >= 4) {
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #else
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
+ #endif
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)",
@@ -2804,10 +3051,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);
+#ifndef WITH_PCRE
+ 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. */
+#ifndef WITH_PCRE
+ if (rc == PCRE2_ERROR_NOMATCH) {
+#else
if (rc == PCRE_ERROR_NOMATCH) {
+#endif
break;
}
@@ -2844,7 +3100,6 @@ static int msre_op_verifyCC_execute(modsec_rec *msr, msre_rule *rule, msre_var *
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));
@@ -2924,7 +3179,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];
@@ -3012,15 +3267,27 @@ 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);
+ if (error_msg == 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;
int erroffset;
+ int options = 0;
msc_regex_t *regex;
- if (error_msg == NULL) return -1;
*error_msg = NULL;
+#ifndef WITH_PCRE
+ 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);
@@ -3045,6 +3312,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;
@@ -3053,18 +3325,17 @@ 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;
msc_parm *mparm = NULL;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int jit;
+ int jit = 0;
#endif
#endif
-
- if (error_msg == NULL) return -1;
*error_msg = NULL;
if (regex == NULL) {
@@ -3072,14 +3343,20 @@ 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
#ifdef WITH_PCRE_JIT
if (msr->txcfg->debuglog_level >= 4) {
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #else
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
+ #endif
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)",
@@ -3112,10 +3389,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);
+#ifndef WITH_PCRE
+ 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. */
+#ifndef WITH_PCRE
+ if (rc == PCRE2_ERROR_NOMATCH) {
+#else
if (rc == PCRE_ERROR_NOMATCH) {
+#endif
break;
}
@@ -3126,11 +3412,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);
@@ -3149,12 +3435,12 @@ static int msre_op_verifyCPF_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;
@@ -3163,33 +3449,34 @@ static int msre_op_verifyCPF_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));
}
- 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);
}
}
@@ -3197,7 +3484,7 @@ static int msre_op_verifyCPF_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);
@@ -3232,6 +3519,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;
@@ -3304,15 +3593,24 @@ 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;
msc_regex_t *regex;
if (error_msg == NULL) return -1;
*error_msg = NULL;
+#ifndef WITH_PCRE
+ 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);
@@ -3337,6 +3635,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;
@@ -3345,13 +3648,14 @@ 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;
msc_parm *mparm = NULL;
#ifdef WITH_PCRE_STUDY
#ifdef WITH_PCRE_JIT
- int jit;
+ int jit = 0;
#endif
#endif
@@ -3364,14 +3668,20 @@ 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
#ifdef WITH_PCRE_JIT
if (msr->txcfg->debuglog_level >= 4) {
+ #ifndef WITH_PCRE
+ msc_op_set_jitrc(regex, &rc, &jit);
+ #else
rc = msc_fullinfo(regex, PCRE_INFO_JIT, &jit);
+ #endif
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)",
@@ -3404,10 +3714,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);
+#ifndef WITH_PCRE
+ 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. */
+#ifndef WITH_PCRE
+ if (rc == PCRE2_ERROR_NOMATCH) {
+#else
if (rc == PCRE_ERROR_NOMATCH) {
+#endif
break;
}
@@ -3519,6 +3838,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;
@@ -3645,6 +3967,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;
@@ -3653,10 +3980,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. */
@@ -3826,6 +4154,13 @@ 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);
+ if (error_msg == 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
struct fuzzy_hash_param_data *param_data;
struct fuzzy_hash_chunk *chunk, *t;
@@ -3846,11 +4181,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
@@ -3933,24 +4263,22 @@ 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
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;
@@ -3970,7 +4298,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;
@@ -3984,9 +4312,15 @@ 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);
+ if (error_msg == 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;
- if (error_msg == NULL) return -1;
*error_msg = NULL;
if ((filename == NULL)||(is_empty_string(filename))) {
@@ -4025,7 +4359,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) {
@@ -4086,6 +4423,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;
@@ -4149,10 +4489,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) {
@@ -4223,6 +4566,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 :
@@ -4310,7 +4656,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) */
@@ -4343,6 +4689,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;
@@ -4400,6 +4749,10 @@ 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(var != NULL);
+ assert(error_msg != NULL);
msc_string str;
int left, right;
char *target = NULL;
@@ -4438,6 +4791,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;
@@ -4481,16 +4838,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)) {
@@ -4524,6 +4879,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;
@@ -4567,6 +4926,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;
@@ -4576,7 +4939,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 c69085feef..c4c4b0d895 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
@@ -12,6 +12,7 @@
* directly using the email address security@modsecurity.org.
*/
+#include
#include "http_core.h"
#include "modsecurity.h"
@@ -21,12 +22,18 @@
#include "libxml/xpathInternals.h"
+#ifndef WITH_PCRE
+#define PCRE_ERROR_NOMATCH PCRE2_ERROR_NOMATCH
+#endif
/**
* Generates a variable from a string and a length.
*/
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;
@@ -54,6 +61,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;
@@ -64,12 +74,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);
+#ifndef WITH_PCRE
+ 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);
@@ -90,6 +106,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;
@@ -99,6 +119,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. */
@@ -107,8 +128,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;
}
@@ -135,6 +155,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;
@@ -145,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;
}
@@ -162,6 +187,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;
@@ -170,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. */
@@ -177,8 +207,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;
}
@@ -205,6 +234,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;
@@ -214,6 +247,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 */
@@ -225,8 +259,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;
}
@@ -253,6 +286,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;
@@ -261,6 +298,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 */
@@ -271,8 +309,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;
}
@@ -299,6 +336,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;
@@ -308,6 +349,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 */
@@ -319,8 +361,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;
}
@@ -347,6 +388,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;
@@ -355,6 +400,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 */
@@ -365,8 +411,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;
}
@@ -393,10 +438,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;
@@ -428,13 +477,14 @@ 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);
+ assert(var != NULL);
if (var->param == NULL) {
return apr_psprintf(ruleset->mp, "Parameter required for ENV.");
}
@@ -449,6 +499,9 @@ 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(msr->r != 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);
@@ -461,6 +514,8 @@ 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);
+ assert(msr->r != NULL);
return var_simple_generate(var, vartab, mptmp, msr->r->unparsed_uri);
}
@@ -469,6 +524,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);
@@ -483,10 +540,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);
}
@@ -496,7 +561,14 @@ 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);
+ 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");
+ return -1;
+ }
if (msr->msc_reqbody_processor == NULL) {
rvar->value = apr_pstrdup(mptmp, "");
@@ -515,9 +587,21 @@ 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(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);
@@ -529,7 +613,15 @@ 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);
+ 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");
+ return -1;
+ }
rvar->value = apr_psprintf(mptmp, "%d", msr->msc_reqbody_error);
rvar->value_len = strlen(rvar->value);
@@ -543,7 +635,15 @@ 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(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, "");
@@ -561,6 +661,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;
@@ -572,6 +674,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;
@@ -652,22 +761,35 @@ 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) {
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);
+ xmlFree(content);
+ content = NULL;
count++;
}
}
+var_xml_generate_Error:
+ if (content != NULL) xmlFree(content);
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
@@ -679,6 +801,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;
@@ -689,7 +816,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);
@@ -704,6 +839,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
@@ -713,9 +849,12 @@ 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) {
+ 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);
}
@@ -730,6 +869,8 @@ 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);
+ 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);
@@ -740,6 +881,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);
}
@@ -749,6 +891,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);
}
@@ -757,14 +900,20 @@ 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;
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. */
@@ -773,8 +922,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;
}
@@ -783,10 +931,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++;
@@ -801,14 +957,20 @@ 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;
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. */
@@ -817,8 +979,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;
}
@@ -845,6 +1006,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));
}
@@ -854,6 +1016,11 @@ 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(msr->collections != 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,9 +1030,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. */
@@ -874,8 +1043,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;
}
@@ -902,6 +1070,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,
@@ -914,6 +1084,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,
@@ -926,6 +1098,11 @@ 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(msr->collections != 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;
@@ -938,6 +1115,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. */
@@ -946,8 +1124,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;
}
@@ -956,6 +1133,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;
@@ -974,6 +1155,11 @@ 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(msr->collections != 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;
@@ -986,6 +1172,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. */
@@ -994,8 +1181,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;
}
@@ -1004,10 +1190,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++;
@@ -1022,6 +1216,11 @@ 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(msr->collections != 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;
@@ -1034,6 +1233,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. */
@@ -1042,8 +1242,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;
}
@@ -1070,6 +1269,11 @@ 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(msr->collections != 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;
@@ -1082,6 +1286,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. */
@@ -1090,8 +1295,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;
}
@@ -1100,6 +1304,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;
@@ -1118,44 +1326,32 @@ 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;
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++)
- {
- 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. */
@@ -1164,28 +1360,30 @@ 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;
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) {
+ 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));
@@ -1200,6 +1398,7 @@ static int var_files_tmp_contents_generate(modsec_rec *msr, msre_var *var,
}
}
+files_tmp_content_not_enough_mem:
return count;
}
@@ -1209,13 +1408,19 @@ 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;
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;
@@ -1224,8 +1429,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;
}
@@ -1254,13 +1458,19 @@ 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;
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;
@@ -1269,8 +1479,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;
}
@@ -1299,13 +1508,19 @@ 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;
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;
@@ -1314,8 +1529,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;
}
@@ -1344,15 +1558,25 @@ 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;
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) {
+ msr_log(msr, 1, "FILES_NAMES: Memory allocation error");
+ return count;
+ }
rvar->value = parts[i]->name;
rvar->value_len = strlen(rvar->value);
@@ -1372,6 +1596,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;
@@ -1380,6 +1607,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;
}
@@ -1387,6 +1615,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);
@@ -1394,6 +1626,59 @@ 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)
+{
+ assert(msr != NULL);
+ assert(var != NULL);
+ assert(vartab != NULL);
+ assert(mptmp != NULL);
+ multipart_part **parts = NULL;
+ 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. */
+ 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) >= 0) 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) {
+ 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++;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
/* MODSEC_BUILD */
static int var_modsec_build_generate(modsec_rec *msr, msre_var *var, msre_rule *rule,
@@ -1407,6 +1692,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);
}
@@ -1415,6 +1701,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);
}
@@ -1423,6 +1710,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 {
@@ -1435,6 +1723,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 {
@@ -1447,6 +1736,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 {
@@ -1459,6 +1749,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 {
@@ -1471,6 +1762,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 {
@@ -1483,6 +1775,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 {
@@ -1495,6 +1788,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 {
@@ -1507,6 +1801,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 {
@@ -1519,6 +1814,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 {
@@ -1531,6 +1827,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 {
@@ -1543,6 +1840,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 {
@@ -1555,6 +1853,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 {
@@ -1567,6 +1866,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 {
@@ -1579,6 +1879,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)
@@ -1606,6 +1907,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 {
@@ -1618,6 +1920,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 {
@@ -1630,6 +1933,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 {
@@ -1642,6 +1946,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 {
@@ -1650,12 +1955,15 @@ 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;
}
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
@@ -1668,6 +1976,9 @@ 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(var != NULL);
+ assert(vartab != NULL);
+ assert(mptmp != NULL);
msre_var *rvar = NULL;
rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
@@ -1684,6 +1995,9 @@ 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(var != NULL);
+ assert(vartab != NULL);
+ assert(mptmp != NULL);
msre_var *rvar = NULL;
rvar = apr_pmemdup(mptmp, var, sizeof(msre_var));
@@ -1708,6 +2022,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);
}
@@ -1716,6 +2031,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);
}
@@ -1724,6 +2040,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);
}
@@ -1732,6 +2049,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);
}
@@ -1740,6 +2058,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);
}
@@ -1748,6 +2067,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);
}
@@ -1756,6 +2076,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);
}
@@ -1764,6 +2085,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);
}
@@ -1772,6 +2094,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);
}
@@ -1781,11 +2104,16 @@ 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;
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;
@@ -1795,8 +2123,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;
}
@@ -1824,9 +2151,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);
@@ -1840,6 +2174,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;
@@ -1847,10 +2185,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);
@@ -1862,6 +2208,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;
@@ -1869,9 +2219,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);
@@ -1883,6 +2241,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;
@@ -1890,7 +2252,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);
@@ -1902,6 +2272,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;
@@ -1909,7 +2283,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);
@@ -1921,6 +2303,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;
@@ -1928,7 +2314,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);
@@ -1939,6 +2333,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;
@@ -1946,7 +2344,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);
@@ -1958,6 +2364,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;
@@ -1965,7 +2375,16 @@ 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);
+ 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);
@@ -1977,6 +2396,10 @@ 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(var != NULL);
+ assert(vartab != NULL);
+ assert(mptmp != NULL);
msre_var *rvar = NULL;
struct tm *tm;
time_t tc;
@@ -1984,7 +2407,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);
@@ -1996,12 +2427,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);
@@ -2013,6 +2456,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);
}
@@ -2021,6 +2465,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);
}
@@ -2030,6 +2476,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;
@@ -2056,7 +2506,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;
@@ -2092,6 +2542,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;
@@ -2110,6 +2564,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);
@@ -2122,6 +2577,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);
}
@@ -2131,6 +2587,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;
@@ -2140,14 +2600,14 @@ 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;
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;
}
@@ -2158,6 +2618,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",
@@ -2191,23 +2656,28 @@ 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;
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;
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;
}
@@ -2218,6 +2688,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",
@@ -2251,11 +2726,16 @@ 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;
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;
@@ -2263,10 +2743,10 @@ 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,
- 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;
}
@@ -2275,11 +2755,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++;
@@ -2294,11 +2782,16 @@ 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;
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;
@@ -2306,10 +2799,10 @@ 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,
- 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;
}
@@ -2318,11 +2811,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++;
@@ -2337,11 +2838,16 @@ 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;
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;
@@ -2349,10 +2855,10 @@ 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,
- 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;
}
@@ -2361,11 +2867,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++;
@@ -2380,11 +2894,16 @@ 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;
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;
@@ -2392,10 +2911,10 @@ 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,
- 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;
}
@@ -2404,11 +2923,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++;
@@ -2423,6 +2950,8 @@ 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);
+ assert(msr->r != NULL);
return var_simple_generate(var, vartab, mptmp, msr->r->parsed_uri.path);
}
@@ -2431,6 +2960,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);
}
@@ -2439,6 +2969,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);
}
@@ -2447,6 +2978,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);
}
@@ -2455,6 +2987,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);
}
@@ -2463,6 +2996,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);
}
@@ -2471,7 +3005,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);
}
@@ -2480,6 +3019,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);
}
@@ -2489,6 +3030,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);
}
@@ -2498,7 +3041,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);
}
@@ -2507,6 +3056,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);
@@ -2519,6 +3071,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);
}
@@ -2528,6 +3083,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);
}
@@ -2537,6 +3095,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);
@@ -2549,6 +3110,8 @@ 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);
+ assert(msr->r != NULL);
char *value = msr->r->ap_auth_type;
return var_simple_generate(var, vartab, mptmp, value);
}
@@ -2558,6 +3121,9 @@ 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);
+ assert(msr->r != NULL);
+ assert(mptmp != NULL);
const char *value = msr->r->path_info;
return var_simple_generate(var, vartab, mptmp, value);
}
@@ -2567,6 +3133,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);
@@ -2580,6 +3147,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);
@@ -2593,6 +3161,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);
@@ -2606,6 +3175,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;
@@ -2613,6 +3186,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;
@@ -2620,10 +3194,10 @@ 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,
- 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;
}
@@ -2632,11 +3206,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++;
@@ -2651,11 +3233,16 @@ 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;
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;
@@ -2663,10 +3250,10 @@ 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,
- 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;
}
@@ -2675,11 +3262,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++;
@@ -2694,6 +3289,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);
}
@@ -2703,6 +3299,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);
}
@@ -2712,6 +3309,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);
}
@@ -2721,6 +3319,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);
}
@@ -2729,6 +3329,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);
}
@@ -2738,6 +3340,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);
}
@@ -2747,6 +3350,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);
}
@@ -2756,6 +3360,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);
}
@@ -2770,6 +3376,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;
@@ -2790,6 +3397,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,
@@ -2956,6 +3564,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/build/compile b/build/compile
index 1b1d232169..49b3d05fde 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=2024-06-19.01; # UTC
-# Copyright (C) 1999, 2000, 2003, 2004, 2005 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
@@ -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,35 +28,244 @@ 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 | *.lo | *.[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 .
+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...
+ ;;
esac
ofile=
cfile=
-eat=
for arg
do
@@ -66,8 +274,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 +302,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 +332,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 +343,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 3310e40494..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"])
@@ -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
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 f5da40a327..9b222f67fc 100644
--- a/build/find_pcre.m4
+++ b/build/find_pcre.m4
@@ -17,74 +17,76 @@ 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"])
+ [with_pcre="no"])
-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"
+if test "x${with_pcre}" = "x" || test "x${with_pcre}" = "xno"; then
+ AC_MSG_NOTICE([pcre not specified; omitting check for pcre])
else
- test_paths="${with_pcre}"
-fi
-
-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
- fi
+ AC_MSG_CHECKING([for libpcre config script])
- 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.])
- ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2)
-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}])
+ PCRE_CFLAGS="-DWITH_PCRE ${PCRE_CFLAGS}"
+ ifelse([$1], , , $1)
+ fi
+fi
])
diff --git a/build/find_pcre2.m4 b/build/find_pcre2.m4
new file mode 100644
index 0000000000..58cb79c442
--- /dev/null
+++ b/build/find_pcre2.m4
@@ -0,0 +1,93 @@
+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,
+ [AS_HELP_STRING([--with-pcre2=PATH],[Path to pcre2 prefix or config script])],
+ [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}"])
+
+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
+ 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.])
+ ifelse([$2], , AC_MSG_ERROR([pcre2 library is required]), $2)
+ else
+ AC_MSG_NOTICE([using pcre2 v${PCRE2_VERSION}])
+ PCRE2_CFLAGS="${PCRE2_CFLAGS}"
+ ifelse([$1], , , $1)
+ fi
+fi
+])
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_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/build/find_yajl.m4 b/build/find_yajl.m4
index 132a8a8a90..e0934e8496 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}"],
@@ -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
diff --git a/configure.ac b/configure.ac
index 3180547cc5..7103729163 100644
--- a/configure.ac
+++ b/configure.ac
@@ -30,9 +30,9 @@ 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
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.
@@ -244,7 +244,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
@@ -305,6 +305,22 @@ if test "$build_docs" -eq 1; then
fi
+# Add assert() usage
+
+AC_ARG_ENABLE(assertions,
+ AS_HELP_STRING([--enable-assertions],
+ [Turn on assertions checks (undefine NDEBUG, define _GLIBCXX_ASSERTIONS & _FORTIFY_SOURCE)]),
+[
+ if test "${enableval}" = "yes"; then
+ assertions='-UNDEBUG -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS'
+ else
+ assertions='-DNDEBUG'
+ fi
+],
+[
+ assertions='-DNDEBUG'
+])
+
# Add PCRE Studying
AC_ARG_ENABLE(pcre-study,
@@ -690,6 +706,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 +844,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 $large_stream_input $assertions"
APXS_WRAPPER=build/apxs-wrapper
APXS_EXTRA_CFLAGS=""
@@ -849,6 +881,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()
@@ -871,13 +904,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"
],
@@ -888,7 +921,7 @@ AC_TRY_COMPILE(
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"
@@ -913,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])
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
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/.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
new file mode 100644
index 0000000000..fe5e1d0f51
--- /dev/null
+++ b/iis/CMakeLists.txt
@@ -0,0 +1,348 @@
+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)
+find_package(APR CONFIG REQUIRED)
+
+set(IIS_MODULE_NAME "modsecurityiis")
+
+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
+)
+
+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
+)
+
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(ARCHITECTURE "x64")
+else()
+ set(ARCHITECTURE "x86")
+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}
+)
+
+# 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}
+ PROPERTIES GENERATED TRUE
+)
+
+add_library(${IIS_MODULE_NAME} SHARED
+ ${IIS_APACHE_SOURCES}
+ ${IIS_STANDALONE_SOURCES}
+ ${IIS_MODULE_SOURCES}
+)
+
+# Set the output name and extension
+set_target_properties(${IIS_MODULE_NAME} PROPERTIES
+ OUTPUT_NAME ${IIS_MODULE_NAME}
+ PREFIX ""
+ SUFFIX ".dll"
+)
+
+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}
+)
+
+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()
+
+ 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
+ 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"
+ )
+
+ add_library(Apache::apriconv SHARED IMPORTED)
+ set_target_properties(Apache::apriconv 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
+ )
+endif()
+
+set(MODSECURITY_VERSION_FLAG "VERSION_IIS") # Define the version flag string
+target_compile_definitions(${IIS_MODULE_NAME} PRIVATE
+ inline=APR_INLINE
+ AP_DECLARE_STATIC
+ WITH_CURL
+ WITH_REMOTE_RULES
+ MSC_LARGE_STREAM_INPUT
+ WITH_YAJL
+ ${MODSECURITY_VERSION_FLAG}
+)
+
+option(WITH_LUA "Enable Lua support" OFF)
+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()
+
+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"
+ NO_DEFAULT_PATH
+ )
+ find_library(YAJL_LIBRARY NAMES yajl
+ PATHS "${CMAKE_CURRENT_SOURCE_DIR}/build/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. 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)
+ endif()
+endif()
+
+option(WITH_SSDEEP "Enable SSDEEP support" OFF)
+if(WITH_SSDEEP)
+
+ 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)
+
+ find_path(SSDEEP_INCLUDE_DIR fuzzy.h
+ PATHS "${SSDEEP_ROOT}"
+ NO_DEFAULT_PATH
+ )
+
+ if(SSDEEP_INCLUDE_DIR)
+ target_compile_definitions(${IIS_MODULE_NAME} PRIVATE WITH_SSDEEP)
+ target_include_directories(${IIS_MODULE_NAME} PRIVATE ${SSDEEP_INCLUDE_DIR})
+
+ 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")
+ set(SSDEEP_GENERATED_dll "${CMAKE_CURRENT_BINARY_DIR}/fuzzy.dll")
+
+ 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)
+
+ add_custom_target(generate_ssdeep_lib ALL
+ DEPENDS ${SSDEEP_GENERATED_LIB}
+ COMMENT "Ensuring ssdeep lib is generated"
+ )
+
+ add_dependencies(${IIS_MODULE_NAME} generate_ssdeep_lib)
+
+ 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 "fuzzy.h not found at ${SSDEEP_INCLUDE_DIR}. Disabling SSDEEP support.")
+ set(WITH_SSDEEP OFF CACHE BOOL "Enable SSDEEP support" FORCE)
+ endif()
+ endif()
+endif()
+
+if(MSVC)
+ target_compile_options(${IIS_MODULE_NAME} PRIVATE
+ /nologo
+ /W3
+ /wd4244
+ /wd4018
+ )
+endif()
+
+target_link_libraries(${IIS_MODULE_NAME} PRIVATE
+ LibXml2::LibXml2
+ PCRE2::8BIT
+ CURL::libcurl
+ ws2_32
+ iphlpapi
+)
+
+if(APACHE_ROOT)
+ target_link_libraries(${IIS_MODULE_NAME} PRIVATE
+ 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.")
+endif()
+
+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::fuzzy)
+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"
+ $
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${APACHE_ROOT}/bin/libapriconv-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}/fuzzy.dll")
+ add_custom_command(TARGET ${IIS_MODULE_NAME} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${SSDEEP_ROOT}/fuzzy.dll"
+ $
+ COMMENT "Copying SSDEEP DLL to output 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"
+ "${APACHE_ROOT}/bin/libapriconv-1.dll"
+ DESTINATION .
+ )
+endif()
+
+if(WITH_SSDEEP AND SSDEEP_ROOT AND EXISTS "${SSDEEP_ROOT}/fuzzy.dll")
+ install(FILES
+ "${SSDEEP_ROOT}/fuzzy.dll"
+ DESTINATION .
+ )
+endif()
+
+# Also install the PDB file if it's generated
+install(FILES $ DESTINATION . OPTIONAL)
\ No newline at end of file
diff --git a/iis/Makefile.win b/iis/Makefile.win
index 8c2cdbd7ee..04df4fb430 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,16 +75,18 @@ 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 \
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/build_dependencies.bat b/iis/build_dependencies.bat
old mode 100644
new mode 100755
index fc0d6095d6..e131cd15cd
--- 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,23 +6,28 @@
@set OUTPUT_DIR=%cd%\dependencies\release_files
@set SOURCE_DIR=%USERPROFILE%\Downloads
-:: Aditional paths.
-@set PATH=%PATH%;c:\work\cmake-2.8.7-win32-x86\bin;"c:\program files\7-zip"
+:: Dependencies
+@set CMAKE=cmake-3.12.4-win32-x86.zip
+@set PCRE=pcre-8.45.zip
+@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.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
+
+@set CMAKE_DIR=%WORK_DIR%\%CMAKE:~0,-4%\bin
-@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
+:: Aditional paths.
+@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.
@@ -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
@@ -53,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
@@ -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..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-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-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-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-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-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/build_msi.bat b/iis/build_msi.bat
index 0ea7d369fe..d3c020fdd7 100644
--- a/iis/build_msi.bat
+++ b/iis/build_msi.bat
@@ -1,20 +1,20 @@
-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*
-"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/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%
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_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/dependencies/build_pcre.bat b/iis/dependencies/build_pcre.bat
index 9d728a4042..d2cbcce0f9 100644
--- a/iis/dependencies/build_pcre.bat
+++ b/iis/dependencies/build_pcre.bat
@@ -1,32 +1,45 @@
-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... 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"
-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%"
-
+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_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 33ebc234ac..f5c6eff078 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
@@ -20,15 +22,20 @@ 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%"
+
+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
-@echo File not found: "%SOURCE_DIR%\%PCRE%"
+@echo File not found: "%SOURCE_DIR%\%YAJL%"
@goto failed
:build_failed
diff --git a/iis/dependencies/howto.txt b/iis/dependencies/howto.txt
index 1505a5f95d..830851f95a 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/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)
+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..dd0773aad2
--- /dev/null
+++ b/iis/download_files.bat
@@ -0,0 +1,39 @@
+@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.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 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://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
+
+: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
+
diff --git a/iis/installer.wxs b/iis/installer.wxs
index 015c9351f8..3f17443327 100644
--- a/iis/installer.wxs
+++ b/iis/installer.wxs
@@ -7,9 +7,9 @@
lightArgs:
-->
-
+
-
+
@@ -17,17 +17,19 @@
-
+
-
+
+
+
@@ -87,24 +89,28 @@
+
+
-
+
+
-
- VersionNT64
-
- NOT VersionNT64
-
-
-
-
-
+
+
+ VersionNT64
+
+ NOT VersionNT64
+
+
+
+
+
@@ -121,7 +127,7 @@
-
+
@@ -129,224 +135,37 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
+
@@ -355,37 +174,14 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -398,56 +194,16 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -455,33 +211,36 @@
-
+
-
+
+
+
-
+
+
-
+
@@ -571,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
@@ -608,12 +367,12 @@
-
+
-
+
@@ -623,45 +382,45 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
\ No newline at end of file
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 607fdf0a6d..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,7 +32,6 @@
#include "api.h"
#include "moduleconfig.h"
-#include "winsock2.h"
class REQUEST_STORED_CONTEXT : public IHttpStoredContext
{
@@ -84,67 +85,71 @@ class REQUEST_STORED_CONTEXT : public IHttpStoredContext
ULONGLONG m_pResponsePosition;
};
+
//----------------------------------------------------------------------------
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;
}
@@ -286,6 +291,7 @@ REQUEST_STORED_CONTEXT *RetrieveIISContext(request_rec *r)
return NULL;
}
+
HRESULT CMyHttpModule::ReadFileChunk(HTTP_DATA_CHUNK *chunk, char *buf)
{
OVERLAPPED ovl;
@@ -752,11 +758,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;
@@ -769,55 +771,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;
}
@@ -1072,7 +1061,9 @@ CMyHttpModule::OnBeginRequest(
#endif
c->remote_host = NULL;
+ LeaveCriticalSection(&m_csLock);
int status = modsecProcessRequest(r);
+ EnterCriticalSection(&m_csLock);
if(status != DECLINED)
{
@@ -1093,42 +1084,43 @@ 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);
+ REQUEST_STORED_CONTEXT *rsc = RetrieveIISContext(r);
- *readcnt = 0;
+ *readcnt = 0;
- if(rsc == NULL)
- {
- *is_eos = 1;
- return APR_SUCCESS;
- }
+ if (rsc == NULL)
+ {
+ *is_eos = 1;
+ return APR_SUCCESS;
+ }
- IHttpContext *pHttpContext = rsc->m_pHttpContext;
- IHttpRequest *pRequest = pHttpContext->GetRequest();
+ IHttpContext *pHttpContext = rsc->m_pHttpContext;
+ IHttpRequest *pRequest = pHttpContext->GetRequest();
- if(pRequest->GetRemainingEntityBytes() == 0)
- {
- *is_eos = 1;
- return APR_SUCCESS;
- }
+ if (pRequest->GetRemainingEntityBytes() == 0)
+ {
+ *is_eos = 1;
+ return APR_SUCCESS;
+ }
- HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
+ HRESULT hr = pRequest->ReadEntityBody(buf, length, false, (DWORD *)readcnt, NULL);
- if (FAILED(hr))
+ if (FAILED(hr))
{
// End of data is okay.
- if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
+ if (ERROR_HANDLE_EOF != (hr & 0x0000FFFF))
{
// Set the error status.
- rsc->m_pProvider->SetErrorStatus( hr );
+ 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)
diff --git a/iis/vcpkg.json b/iis/vcpkg.json
new file mode 100644
index 0000000000..3abb499b35
--- /dev/null
+++ b/iis/vcpkg.json
@@ -0,0 +1,10 @@
+{
+ "dependencies": [
+ "curl",
+ "libxml2",
+ "lua",
+ "pcre2",
+ "yajl",
+ "apr"
+ ]
+}
\ No newline at end of file
diff --git a/iis/wix/modsecurity.conf b/iis/wix/modsecurity.conf
index 60f09129e1..fcce635963 100644
--- a/iis/wix/modsecurity.conf
+++ b/iis/wix/modsecurity.conf
@@ -16,11 +16,14 @@ 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
#
-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 +43,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 +113,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 +154,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 +174,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,20 +184,20 @@ 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\logs\modsec_audit.log
# Specify the path for concurrent audit logging.
-#SecAuditLogStorageDir c:\inetpub\log\
+#SecAuditLogStorageDir c:\inetpub\logs\
# -- Miscellaneous -----------------------------------------------------------
@@ -216,8 +219,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/modsecurity_iis.conf b/iis/wix/modsecurity_iis.conf
index 85d20ba74f..a18a4a6bca 100644
--- a/iis/wix/modsecurity_iis.conf
+++ b/iis/wix/modsecurity_iis.conf
@@ -1,3 +1 @@
Include modsecurity.conf
-Include modsecurity_crs_10_setup.conf
-Include owasp_crs\base_rules\*.conf
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)
+
+
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 e650452dc4..7a9edaa12b 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
+#ifndef WITH_PCRE
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include
+#else
#include
+#endif
#include
#include
#include
@@ -96,7 +101,7 @@ do { \
static const char logline_pattern[] =
"^(\\S+)"
"\\ (\\S+)\\ (\\S+)\\ (\\S+)"
- "\\ \\[([^:]+):(\\d+:\\d+:\\d+)\\ ([^\\]]+)\\]"
+ "\\ \\[([^:]+):(\\d+:\\d+:\\d+(?:[.]\\d+)?)\\ ([^\\]]+)\\]"
"\\ \"(.*)\""
"\\ (\\d+)\\ (\\S+)"
"\\ \"(.*)\"\\ \"(.*)\""
@@ -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;
+#ifndef WITH_PCRE
+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;
+#ifndef WITH_PCRE
+ 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);
}
+#ifndef WITH_PCRE
+ 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);
+#ifndef WITH_PCRE
+ 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];
+#ifndef WITH_PCRE
+ 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++;
}
+#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);
+ 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) {
+#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);
+#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\"; "
+#ifndef WITH_PCRE
+ "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());
diff --git a/modsecurity.conf-recommended b/modsecurity.conf-recommended
index 728afc1afd..e120daef88 100644
--- a/modsecurity.conf-recommended
+++ b/modsecurity.conf-recommended
@@ -19,16 +19,23 @@ 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/[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
@@ -39,7 +46,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
@@ -51,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)
@@ -97,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 --------------------------------------------------
@@ -222,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
diff --git a/standalone/config.c b/standalone/config.c
index 800d5b4344..6133e7d7e8 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
@@ -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);
@@ -1201,3 +1202,4 @@ const char *process_command_config(server_rec *s,
return errmsg;
}
+
diff --git a/standalone/regex.c b/standalone/regex.c
index 495a18eb97..cdc79059fe 100644
--- a/standalone/regex.c
+++ b/standalone/regex.c
@@ -1,162 +1,242 @@
-/*
-* 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)
+{
+#ifndef WITH_PCRE
+(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;
+
+#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;
+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 // otherwise use PCRE
+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;
+
+#ifndef WITH_PCRE
+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;
+ }
+ }
+
+#ifndef WITH_PCRE
+{
+ 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);
+ }
+ /*
+ 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),
+ 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)
+ {
+#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;
+ 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;
+ }
+ }
+}
+
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 8ffc3bb3db..181a5aa7ed 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@
@@ -76,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
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/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,
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/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/regression/config/10-request-directives.t b/tests/regression/config/10-request-directives.t
index 42094e11b1..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(
@@ -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",
+ ),
+},
+
diff --git a/tests/regression/misc/00-multipart-parser.t b/tests/regression/misc/00-multipart-parser.t
index de39bf0864..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",
@@ -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",
@@ -1081,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",
@@ -1177,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",
@@ -1223,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",
@@ -1314,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",
@@ -1331,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--
),
),
),
@@ -1366,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$/,
@@ -1811,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--
+ ),
+ ),
+ ),
+},
+
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",
),
},
diff --git a/tests/regression/misc/20-status-engine.t b/tests/regression/misc/20-status-engine.t
deleted file mode 100644
index a8ec6f3e03..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 93acd7316d..0000000000
--- a/tests/regression/misc/40-secRemoteRules.t.in
+++ /dev/null
@@ -1,43 +0,0 @@
-### 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')--"
- ),
-},
-
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 effe97bf32..0000000000
--- a/tests/regression/misc/50-ipmatchfromfile-external.t.in
+++ /dev/null
@@ -1,71 +0,0 @@
-### 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./, 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 bfa4038a4a..0000000000
--- a/tests/regression/misc/60-pmfromfile-external.t.in
+++ /dev/null
@@ -1,84 +0,0 @@
-### 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./, 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/rule/10-xml.t b/tests/regression/rule/10-xml.t
index ea9d6ad99a..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",
@@ -394,7 +396,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 e75f89c154..9c17817503 100644
--- a/tests/regression/rule/15-json.t
+++ b/tests/regression/rule/15-json.t
@@ -35,5 +35,229 @@
),
),
),
+},
+{
+ 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"
+ }
+ ]
+ ),
+ ),
+ ),
+},
+{
+ 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"}}}}
+ }
+ ),
+ ),
+ ),
+},
+{
+ 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
+ ),
+ ),
+ ),
}
+
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)
+
+
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
#{
diff --git a/tests/run-regression-tests.pl.in b/tests/run-regression-tests.pl.in
index 40e885f0eb..d8db033040 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,13 +125,14 @@ 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},
HTTPD_CONF => $opt{C},
HTDOCS => $opt{H},
USER_AGENT => $UA_NAME,
+ RUNASUSER => $ENV{USER} || $ENV{LOGNAME} || $ENV{USERNAME} || 'unknown',
);
#dbg("OPTIONS: ", \%opt);
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