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/.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 031648e4d5..4cf9c09356 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,507 @@ -DD mmm YYYY - X.Y.Z (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 + [Issue #1412 - @client9, @zimmerle and @bjdijk] + * Avoid log flood while using SecConnEngine + [Issue #1436 - @victorhora] + * Make url path absolute for SecHashEngine only when it is relative + in the first place. + [Issue #752, #1071 - @hideaki] + * Fix the hex digit size for SHA1 on msc_crypt implementation. + [Issue #1354 - @zimmerle and @parthasarathi204] + * Avoid to flush xml buffer while assembling the injected html. + [Issue #742 - @zimmerle] + * Avoid additional operator invokation if last transform of a multimatch + doesn't modify the input + [Issue #1086, #1087 - Daniel Stelter-Gliese] + * Adds a sanity check before use ctl:ruleRemoveTargetByTag. + [Issue #1353 - @LukeP21 and @zimmerle] + * Uses an optional global lock while manipulating collections. + [Issues #1224 - @mturk and @zimmerle] + * Fix collection naming problem while merging collections. + [Issue #1274 - Coty Sutherland and @zimmerle] + * Fix --enable-docs adding missing Makefile, modifying autoconf and filenames + [Issue #1322 - @victorhora] + * Change from using rand() to thread-safe ap_random_pick. + [Issue #1289 - Robert Bost] + * Cosmetics: added comments on odd looking code to prevent future + scrutiny + [Issue #1279 - Coty Sutherland] + * {dis|en}able-server-context-logging: Option to disable logging of + server info (log producer, sanitized objects, ...) in audit log. + [Issue #1069 - Marc Stern] + * Allow drop to work with mod_http2 + [Issue #1308, #992 - @bazzadp] + * Fix SecConn(Read|Write)StateLimit on Apache 2.4 + [Issue #1340, #1337, #786 - Sander Hoentjen] + * {dis|en}able-stopwatch-logging: Option to disable logging of stopwatches + in audit log. + [Issue #1067 - Marc Stern] + * {dis|en}able-dechunk-logging: Option to disable logging of + dechunking in audit log when log level < 9. + [Issue #1068 - Marc Stern] + * Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4 + [ModSecurity team] + * {dis|en}able-handler-logging: Option to disable logging of Apache handler + in audit log + [Issue #1070, #1381 - Marc Stern] + * {dis|en}able-collection-delete-problem-logging: Option to disable logging of + collection delete problem in audit log when log level < 9. + [Issue #1380 - Marc Stern] + * Adds rule id in logs whenever a rule fail. + [Issue #1379, #391 - Marc Stern] + * {dis|en}able-server-logging: Option to disable logging of + "Server" in audit log when log level < 9. + [Issue #1070 - Marc Stern] + * {dis|en}able-filename-logging: Option to disable logging of filename + in audit log. + [Issue #1065 - Marc Stern] + * Reads fuzzy hash databases on init + [Issue #1339 - Robert Paprocki and @Rendername] + * Changes the configuration to recognize soap+xml as XML + [Issue #1374 - @emphazer and Chaim Sanders] + * Fix building with nginx >= 1.11.11 + [Issue #1373, #1359 - Andrei Belov and Thomas Deutschmann] + * Using Czechia instea of Czech Republic + [Issue #1258 - Michael Kjeldsen] + * {dis|en}able-rule-id-validation: Option to disable rule id validation + [Issue #1150 - Marc Stern and ModSecurity team] + * JSON Log: Append a newline to concurrent JSON audit logs + [Issue #1233 - Robert Paprocki] + * JSON Log: Don't unnecessarily rename request body parts in cleanup + [Issue #1223 - Robert Paprocki] + * Fix error message inside audit logs + [Issue #1216 and #1073 - Armin Abfalterer] + * Remove port from IPV4 address when running under IIS. + [Issue #1220, #1109 and #734 - Robert Culyer] + * Remove logdata and msg fields from JSON audit log rule. + [Issue #1190 and #1174 - Robert Paprocki] + * Better handle the json parser cleanup + [Issue #1204 - Ephraim Vider] + * Fix status failing to report in Nginx auditlogs + [Issue #977, #1171 - @charlymps and Chaim Sanders] + * Fix file upload JSON audit log entry + [Issue #1181 and #1173 - Robert Paprocki and Christian Folini] + * configure: Fix detection whether libcurl is linked against gnutls and, + move verbose_output declaration up to the beginning. + [Issue #1158 - Thomas Deutschmann (@Whissi)] + * 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 +------------------- + + * No changes. + +03 Feb 2016 - 2.9.1-RC1 +----------------------- + * Added support to generate audit logs in JSON format. + [Issue #914, #897, #656 - Robert Paprocki] + * Creating AuditLog serial file (or parallel index) respecting the + permission configured with SecAuditLogFileMode. Previously, it was + used only to save the transactions while in parallel mode. + [Issue #852 - @littlecho and ModSecurity team] + * Checking for hashing injection response, to report in case of failure. + [Issue #1041 - ModSecurity team] + * Stop buffering when the request is larger than SecRequestBodyLimit + in ProcessPartial mode + [Issue #709, #705, #728 - Justin Gerace and ModSecurity team] + * Extended Lua support to include version 5.3 + [Issue #837, #762, #814 - Athmane Madjoudj and ModSecurity team] + * mlogc: Allows user to choose between TLS versions (TLSProtocol option + introduced). + [Issue #881 - Ishwor Gurung] + * Allows mod_proxy's "nocanon" behavior to be specified in proxy actions + [Issue #1031, #961, #763 - Mario D. Santana and ModSecurity team] + * Refactoring conditional #if/#defs directives. + [Issue #996 - Wesley M and ModSecurity team] + * mlogc-batch-load.pl.in: fix searching SecAuditLogStorageDir + files with Apache 2.4 + [Issue #775 - Elia Pinto] + * Understands IIS 10 as compatible on Windows installer. + [Issue #931 - Anton Serbulov, Pavel Vasilevich and ModSecurity team] + * Fix apache logging limitation by using correct Apache call. + [Issue #840 - Christian Folini] + * Fix apr_crypto.h check on 32-bit Linux platform + [Issue #882, #883 - Kurt Newman] + * Fix variable resolution duration (Content of the DURATION variable). + [Issue #662 - Andrew Elble] + * Fix crash while adding empty keys to persistent collections. + [Issue #927 - Eugene Alekseev, Marc Stern and ModSecurity team] + * Remove misguided call to srand() + [Issues #778, #781 and #836 - Michael Bunk, @gilperon] * Fix compilation problem while ssdeep is installed in non-standard location. - [Issude #872 - Kurt Newman] + [Issue #872 - Kurt Newman] * Fix invalid storage reference by apr_psprintf at msc_crypt.c [Issue #609 - Jeff Trawick] diff --git a/LICENSE b/LICENSE index 261eeb9e9f..9135230d95 100644 --- a/LICENSE +++ b/LICENSE @@ -175,18 +175,7 @@ END OF TERMS AND CONDITIONS - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] + Copyright 2016 ModSecurity Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.TXT b/README.TXT deleted file mode 100644 index 9442e83a2f..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/projects/commercial/rules/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 bfbcb83468..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; @@ -73,6 +78,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) /* audit log variables */ dcfg->auditlog_flag = NOT_SET; dcfg->auditlog_type = NOT_SET; + #ifdef WITH_YAJL + dcfg->auditlog_format = NOT_SET; + #endif dcfg->max_rule_time = NOT_SET; dcfg->auditlog_dirperms = NOT_SET; dcfg->auditlog_fileperms = NOT_SET; @@ -158,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; } @@ -171,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; @@ -179,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. */ @@ -231,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. */ @@ -243,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. */ @@ -269,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, @@ -291,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; } /** @@ -301,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); @@ -329,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); @@ -412,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) { @@ -439,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, @@ -503,6 +522,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->auditlog2_fd = parent->auditlog2_fd; merged->auditlog2_name = parent->auditlog2_name; } + #ifdef WITH_YAJL + merged->auditlog_format = (child->auditlog_format == NOT_SET + ? parent->auditlog_format : child->auditlog_format); + #endif merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P ? parent->auditlog_storage_dir : child->auditlog_storage_dir); merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P @@ -618,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; } @@ -641,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; @@ -667,6 +694,9 @@ void init_directory_config(directory_config *dcfg) /* audit log variables */ if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + #ifdef WITH_YAJL + if (dcfg->auditlog_format == NOT_SET) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; + #endif if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0; if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; @@ -722,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; @@ -741,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; } @@ -750,12 +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; - int offset = 0; + assert(modsecurity != NULL); + int type_with_lua = 1; + int type_rule; + int rule_actionset; #ifdef DEBUG_CONF ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, @@ -786,26 +827,27 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, return my_error_msg; } - /* Rules must have uniq ID */ - if ( +#ifndef ALLOW_ID_NOT_UNIQUE + /* Rules must have uniq ID */ + type_rule = (dcfg->tmp_chain_starter == NULL); #if defined(WITH_LUA) - type != RULE_TYPE_LUA && + type_rule = (type != RULE_TYPE_LUA && type_rule); #endif - (dcfg->tmp_chain_starter == NULL)) + if (type_rule) if(rule->actionset == NULL) return "ModSecurity: Rules must have at least id action"; if(rule->actionset != NULL && (dcfg->tmp_chain_starter == NULL)) { - if(rule->actionset->id == NOT_SET_P + rule_actionset = (rule->actionset->id == NOT_SET_P); #if defined(WITH_LUA) - && (type != RULE_TYPE_LUA) + rule_actionset = (rule_actionset && (type != RULE_TYPE_LUA)); #endif - ) - return "ModSecurity: No action id present within the rule"; + if (rule_actionset) + return "ModSecurity: No action id present within the rule"; #if defined(WITH_LUA) - if(type != RULE_TYPE_LUA) + type_with_lua = (type != RULE_TYPE_LUA); #endif - { + if (type_with_lua){ rid = apr_hash_get(dcfg->rule_id_htab, rule->actionset->id, APR_HASH_KEY_STRING); if(rid != NULL) { return "ModSecurity: Found another rule with the same id"; @@ -818,6 +860,7 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, // return "ModSecurity: Found another rule with the same id"; } } +#endif /* Create default actionset if one does not already exist. */ if (dcfg->tmp_default_actionset == NULL) { @@ -875,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) @@ -932,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. */ @@ -978,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 @@ -1007,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) { @@ -1030,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)) { @@ -1056,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); @@ -1082,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 @@ -1092,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 */ @@ -1102,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 @@ -1120,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); @@ -1128,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) { @@ -1142,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) { @@ -1155,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; @@ -1171,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; @@ -1189,10 +1257,13 @@ static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) else { const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog_name); apr_status_t rc; - + + if (dcfg->auditlog_fileperms == NOT_SET) { + dcfg->auditlog_fileperms = CREATEMODE; + } rc = apr_file_open(&dcfg->auditlog_fd, file_name, APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, - CREATEMODE, cmd->pool); + dcfg->auditlog_fileperms, cmd->pool); if (rc != APR_SUCCESS) { return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s", @@ -1205,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) { @@ -1228,9 +1302,12 @@ static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) const char *file_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name); apr_status_t rc; + if (dcfg->auditlog_fileperms == NOT_SET) { + dcfg->auditlog_fileperms = CREATEMODE; + } rc = apr_file_open(&dcfg->auditlog2_fd, file_name, APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, - CREATEMODE, cmd->pool); + dcfg->auditlog_fileperms, cmd->pool); if (rc != APR_SUCCESS) { return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s", @@ -1244,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) { @@ -1257,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); } @@ -1270,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; @@ -1282,13 +1372,39 @@ static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, return NULL; } +#ifdef WITH_YAJL +static const char *cmd_audit_log_mode(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + assert(cmd != NULL); + assert(_dcfg != NULL); + assert(p1 != NULL); + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "JSON") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_JSON; + else + if (strcasecmp(p1, "Native") == 0) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditLogFormat: %s", p1); + + return NULL; +} +#endif + 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; } @@ -1307,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; } @@ -1329,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); @@ -1339,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; @@ -1353,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) { @@ -1384,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. */ @@ -1394,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) { @@ -1415,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; @@ -1445,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); @@ -1457,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); @@ -1468,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; @@ -1544,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; } @@ -1553,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; @@ -1613,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; } @@ -1632,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; } @@ -1650,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); @@ -1666,18 +1845,31 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, } char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, - TreeRoot **whitelist, TreeRoot **suspicious_list, + TreeRoot **whitelist, TreeRoot **suspicious_list, const char *filename) { + 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); @@ -1734,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 " \ @@ -1753,7 +1950,7 @@ static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, if (param) return param; } - + conn_read_state_limit = limit; return NULL; @@ -1762,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."); @@ -1783,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 " \ @@ -1810,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."); @@ -1822,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); @@ -1840,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); @@ -1858,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); @@ -1873,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; @@ -1901,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; @@ -1917,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; @@ -1930,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; @@ -1945,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; @@ -1965,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; @@ -1995,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; @@ -2015,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); @@ -2033,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)) { @@ -2059,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"); } @@ -2096,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"); } @@ -2131,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"); } @@ -2159,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) { @@ -2186,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; @@ -2215,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; @@ -2237,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; @@ -2245,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) { @@ -2309,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; } @@ -2326,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; } @@ -2335,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 @@ -2347,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; @@ -2374,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); @@ -2399,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); @@ -2424,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; @@ -2446,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"; } @@ -2455,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); @@ -2467,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); @@ -2480,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; } @@ -2497,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; } @@ -2519,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 @@ -2541,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; @@ -2564,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, ., _, -) */ @@ -2574,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, ., _, -) */ @@ -2594,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; } @@ -2621,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; @@ -2638,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 @@ -2648,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; @@ -2670,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; @@ -2686,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; } @@ -2713,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); @@ -2720,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; @@ -2804,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; @@ -2871,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; @@ -2886,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) { @@ -2905,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) { @@ -2927,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; } @@ -2953,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); @@ -2978,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) { @@ -3013,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; } @@ -3030,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) @@ -3129,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 -- */ @@ -3223,6 +3819,16 @@ const command_rec module_directives[] = { "whether to use the old audit log format (Serial) or new (Concurrent)" ), +#ifdef WITH_YAJL + AP_INIT_TAKE1 ( + "SecAuditLogFormat", + cmd_audit_log_mode, + NULL, + CMD_SCOPE_ANY, + "whether to emit audit log data in native format or JSON" + ), +#endif + AP_INIT_TAKE1 ( "SecAuditLogStorageDir", cmd_audit_log_storage_dir, @@ -3496,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, @@ -3871,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 88f1903183..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,44 +113,50 @@ 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) { modsecurity_request_body_retrieve_end(msr); - bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); - if (bucket == NULL) return APR_EGENERAL; - APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + if (msr->if_seen_eos) { + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + no_data = 0; - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Input filter: Sent EOS."); + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Sent EOS."); + } } /* We're done */ @@ -154,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; @@ -163,39 +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 seen_eos; + 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; } - seen_eos = 0; + finished_reading = 0; + msr->if_seen_eos = 0; bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc); - if (bb_in == NULL) return -1; + if (bb_in == NULL) { + return HTTP_INTERNAL_SERVER_ERROR; + } do { apr_status_t rc; @@ -205,22 +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_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 @@ -236,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) { @@ -249,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 " @@ -270,25 +284,36 @@ 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; if (buflen != 0) { int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg); + + if (msr->reqbody_length > (apr_size_t)msr->txcfg->reqbody_limit && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) { + finished_reading = 1; + } + if (rcbs < 0) { if (rcbs == -5) { if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { *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); @@ -298,26 +323,26 @@ 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; } } if (APR_BUCKET_IS_EOS(bucket)) { - seen_eos = 1; + finished_reading = 1; + msr->if_seen_eos = 1; } } apr_brigade_cleanup(bb_in); - } while(!seen_eos); + } while(!finished_reading); - // TODO: Why ignore the return code here? - modsecurity_request_body_end(msr, error_msg); + 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 ").", @@ -326,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; } @@ -338,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. */ @@ -399,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."); @@ -466,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); @@ -507,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) { @@ -533,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; @@ -587,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) { @@ -600,8 +641,12 @@ static int flatten_response_body(modsec_rec *msr) { retval = hash_response_body_links(msr); if(retval > 0) { retval = inject_hashed_response_body(msr, retval); - if (msr->txcfg->debuglog_level >= 4) { - msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); + if(retval < 0){ + msr_log(msr, 1, "inject_hashed_response_body: Unable to inject hash into response body. Returning response without changes." ); + }else{ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Hash completed in %" APR_TIME_T_FMT " usec.", (apr_time_now() - time1)); + } } } @@ -616,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'; } @@ -974,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 0960dc8e63..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); @@ -339,6 +370,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { if (em == NULL) return NULL; +#ifndef LOG_NO_FILENAME if (em->file != NULL) { s_file = apr_psprintf(mp, "[file \"%s\"] ", log_escape(mp, (char *)em->file)); @@ -349,6 +381,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { s_line = apr_psprintf(mp, "[line %d] ", em->line); if (s_line == NULL) return NULL; } +#endif s_level = apr_psprintf(mp, "[level %d] ", em->level); if (s_level == NULL) return NULL; diff --git a/apache2/libinjection/libinjection.h b/apache2/libinjection/libinjection.h index 11b14ac5f3..6b40b1df6a 100644 --- a/apache2/libinjection/libinjection.h +++ b/apache2/libinjection/libinjection.h @@ -1,5 +1,5 @@ /** - * Copyright 2012, 2013 Nick Galbreath + * Copyright 2012-2016 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -7,8 +7,8 @@ * */ -#ifndef _LIBINJECTION_H -#define _LIBINJECTION_H +#ifndef LIBINJECTION_H +#define LIBINJECTION_H #ifdef __cplusplus # define LIBINJECTION_BEGIN_DECLS extern "C" { @@ -49,9 +49,9 @@ const char* libinjection_version(void); */ int libinjection_sqli(const char* s, size_t slen, char fingerprint[]); -/** ALPHA version of xss detector. +/** ALPHA version of xss detector. * - * NOT DONE. + * NOT DONE. * * \param[in] s input string, may contain nulls, does not need to be null-terminated * \param[in] slen input string length @@ -62,4 +62,4 @@ int libinjection_xss(const char* s, size_t slen); LIBINJECTION_END_DECLS -#endif /* _LIBINJECTION_H */ +#endif /* LIBINJECTION_H */ diff --git a/apache2/libinjection/libinjection_html5.c b/apache2/libinjection/libinjection_html5.c index 38ef9f0f64..a380ca0ad6 100644 --- a/apache2/libinjection/libinjection_html5.c +++ b/apache2/libinjection/libinjection_html5.c @@ -71,20 +71,20 @@ void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_ switch (flags) { case DATA_STATE: - hs->state = h5_state_data; - break; + hs->state = h5_state_data; + break; case VALUE_NO_QUOTE: - hs->state = h5_state_before_attribute_name; - break; + hs->state = h5_state_before_attribute_name; + break; case VALUE_SINGLE_QUOTE: - hs->state = h5_state_attribute_value_single_quote; - break; + hs->state = h5_state_attribute_value_single_quote; + break; case VALUE_DOUBLE_QUOTE: - hs->state = h5_state_attribute_value_double_quote; - break; + hs->state = h5_state_attribute_value_double_quote; + break; case VALUE_BACK_QUOTE: - hs->state = h5_state_attribute_value_back_quote; - break; + hs->state = h5_state_attribute_value_back_quote; + break; } } @@ -100,10 +100,18 @@ int libinjection_h5_next(h5_state_t* hs) /** * Everything below here is private * -*/ + */ + static int h5_is_white(char ch) { + /* + * \t = horizontal tab = 0x09 + * \n = newline = 0x0A + * \v = vertical tab = 0x0B + * \f = form feed = 0x0C + * \r = cr = 0x0D + */ return strchr(" \t\n\v\f\r", ch) != NULL; } @@ -112,19 +120,19 @@ static int h5_skip_white(h5_state_t* hs) char ch; while (hs->pos < hs->len) { ch = hs->s[hs->pos]; - switch (ch) { - case 0x00: /* IE only */ - case 0x20: - case 0x09: - case 0x0A: - case 0x0B: /* IE only */ - case 0x0C: + switch (ch) { + case 0x00: /* IE only */ + case 0x20: + case 0x09: + case 0x0A: + case 0x0B: /* IE only */ + case 0x0C: case 0x0D: /* IE only */ hs->pos += 1; - break; - default: + break; + default: return ch; - } + } } return CHAR_EOF; } @@ -172,6 +180,9 @@ static int h5_state_tag_open(h5_state_t* hs) char ch; TRACE(); + if (hs->pos >= hs->len) { + return 0; + } ch = hs->s[hs->pos]; if (ch == CHAR_BANG) { hs->pos += 1; @@ -259,12 +270,12 @@ static int h5_state_tag_name(h5_state_t* hs) pos = hs->pos; while (pos < hs->len) { ch = hs->s[pos]; - if (ch == 0) { - /* special non-standard case */ - /* allow nulls in tag name */ - /* some old browsers apparently allow and ignore them */ - pos += 1; - } else if (h5_is_white(ch)) { + if (ch == 0) { + /* special non-standard case */ + /* allow nulls in tag name */ + /* some old browsers apparently allow and ignore them */ + pos += 1; + } else if (h5_is_white(ch)) { hs->token_start = hs->s + hs->pos; hs->token_len = pos - hs->pos; hs->token_type = TAG_NAME_OPEN; @@ -332,7 +343,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs) default: { return h5_state_attribute_name(hs); } - } + } } static int h5_state_attribute_name(h5_state_t* hs) @@ -450,12 +461,12 @@ static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar) TRACE(); /* skip initial quote in normal case. - * dont do this is pos == 0 since it means we have started + * don't do this "if (pos == 0)" since it means we have started * in a non-data state. given an input of '>pos > 0) { - hs->pos += 1; + hs->pos += 1; } @@ -705,10 +716,13 @@ static int h5_state_comment(h5_state_t* hs) char ch; const char* idx; size_t pos; + size_t offset; + const char* end = hs->s + hs->len; TRACE(); pos = hs->pos; while (1) { + idx = (const char*) memchr(hs->s + pos, CHAR_DASH, hs->len - pos); /* did not find anything or has less than 3 chars left */ @@ -719,21 +733,62 @@ static int h5_state_comment(h5_state_t* hs) hs->token_type = TAG_COMMENT; return 1; } - ch = *(idx + 1); + offset = 1; + + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + ch = *(idx + offset); if (ch != CHAR_DASH && ch != CHAR_BANG) { pos = (size_t)(idx - hs->s) + 1; continue; } - ch = *(idx + 2); + + /* need to test */ +#if 0 + /* skip all nulls */ + while (idx + offset < end && *(idx + offset) == 0) { + offset += 1; + } + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } +#endif + + offset += 1; + if (idx + offset == end) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_COMMENT; + return 1; + } + + + ch = *(idx + offset); if (ch != CHAR_GT) { pos = (size_t)(idx - hs->s) + 1; continue; } + offset += 1; /* ends in --> or -!> */ hs->token_start = hs->s + hs->pos; hs->token_len = (size_t)(idx - hs->s) - hs->pos; - hs->pos = (size_t)(idx - hs->s) + 3; + hs->pos = (size_t)(idx + offset - hs->s); hs->state = h5_state_data; hs->token_type = TAG_COMMENT; return 1; diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c index 0b67c5cc49..cecbbea3fb 100644 --- a/apache2/libinjection/libinjection_sqli.c +++ b/apache2/libinjection/libinjection_sqli.c @@ -1,5 +1,5 @@ /** - * Copyright 2012,2013 Nick Galbreath + * Copyright 2012,2016 Nick Galbreath * nickg@client9.com * BSD License -- see COPYING.txt for details * @@ -18,7 +18,7 @@ #include "libinjection_sqli.h" #include "libinjection_sqli_data.h" -#define LIBINJECTION_VERSION "3.9.1" +#define LIBINJECTION_VERSION "3.9.2" #define LIBINJECTION_SQLI_TOKEN_SIZE sizeof(((stoken_t*)(0))->val) #define LIBINJECTION_SQLI_MAX_TOKENS 5 @@ -112,15 +112,11 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1) } while (cur < last) { - if (cur[0] == c0) { - if (cur[1] == c1) { - return cur; - } else { - cur += 2; /* (c0 == c1) ? 1 : 2; */ - } - } else { - cur += 1; + /* safe since cur < len - 1 always */ + if (cur[0] == c0 && cur[1] == c1) { + return cur; } + cur += 1; } return NULL; @@ -191,11 +187,11 @@ static int char_is_white(char ch) { /* ' ' space is 0x32 '\t 0x09 \011 horizontal tab '\n' 0x0a \012 new line - '\v' 0x0b \013 verical tab + '\v' 0x0b \013 vertical tab '\f' 0x0c \014 new page '\r' 0x0d \015 carriage return 0x00 \000 null (oracle) - 0xa0 \240 is latin1 + 0xa0 \240 is Latin-1 */ return strchr(" \t\n\v\f\r\240\000", ch) != NULL; } @@ -294,7 +290,7 @@ static void st_clear(stoken_t * st) static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len, const char value) { - /* done to elimiate unused warning */ + /* done to eliminate unused warning */ (void)len; st->type = (char) stype; st->pos = pos; @@ -402,7 +398,7 @@ static size_t parse_eol_comment(struct libinjection_sqli_state * sf) } } -/** In Ansi mode, hash is an operator +/** In ANSI mode, hash is an operator * In MYSQL mode, it's a EOL comment like '--' */ static size_t parse_hash(struct libinjection_sqli_state * sf) @@ -842,7 +838,7 @@ static size_t parse_bstring(struct libinjection_sqli_state *sf) /* * hex literal string - * re: [XX]'[0123456789abcdefABCDEF]*' + * re: [xX]'[0123456789abcdefABCDEF]*' * mysql has requirement of having EVEN number of chars, * but pgsql does not */ @@ -1072,7 +1068,7 @@ static size_t parse_money(struct libinjection_sqli_state *sf) /* we have $foobar$ ... find it again */ strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); - if (strend == NULL) { + if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { /* fell off edge */ st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); sf->current->str_open = '$'; @@ -1104,7 +1100,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) const char *cs = sf->s; const size_t slen = sf->slen; size_t pos = sf->pos; - int have_dot = 0; int have_e = 0; int have_exp = 0; @@ -1136,7 +1131,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } if (pos < slen && cs[pos] == '.') { - have_dot = 1; pos += 1; while (pos < slen && ISDIGIT(cs[pos])) { pos += 1; @@ -1185,7 +1179,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf) } } - if (have_dot == 1 && have_e == 1 && have_exp == 0) { + if (have_e == 1 && have_exp == 0) { /* very special form of * "1234.e" * "10.10E" @@ -1242,29 +1236,13 @@ int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) const unsigned char ch = (unsigned char) (s[*pos]); /* - * if not ascii, then continue... - * actually probably need to just assuming - * it's a string + * look up the parser, and call it + * + * Porting Note: this is mapping of char to function + * charparsers[ch]() */ - if (ch > 127) { + fnptr = char_parse_map[ch]; - /* 160 or 0xA0 or octal 240 is "latin1 non-breaking space" - * but is treated as a space in mysql. - */ - if (ch == 160) { - fnptr = parse_white; - } else { - fnptr = parse_word; - } - } else { - /* - * look up the parser, and call it - * - * Porting Note: this is mapping of char to function - * charparsers[ch]() - */ - fnptr = char_parse_map[ch]; - } *pos = (*fnptr) (sf); /* @@ -1349,16 +1327,22 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, a->type == TYPE_UNION || a->type == TYPE_FUNCTION || a->type == TYPE_EXPRESSION || + a->type == TYPE_TSQL || a->type == TYPE_SQLTYPE)) { - return CHAR_NULL; + return FALSE; } - if (b->type != TYPE_KEYWORD && b->type != TYPE_BAREWORD && - b->type != TYPE_OPERATOR && b->type != TYPE_SQLTYPE && - b->type != TYPE_LOGIC_OPERATOR && - b->type != TYPE_FUNCTION && - b->type != TYPE_UNION && b->type != TYPE_EXPRESSION) { - return CHAR_NULL; + if (! + (b->type == TYPE_KEYWORD || + b->type == TYPE_BAREWORD || + b->type == TYPE_OPERATOR || + b->type == TYPE_UNION || + b->type == TYPE_FUNCTION || + b->type == TYPE_EXPRESSION || + b->type == TYPE_TSQL || + b->type == TYPE_SQLTYPE || + b->type == TYPE_LOGIC_OPERATOR)) { + return FALSE; } sz1 = a->len; @@ -1374,7 +1358,6 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, tmp[sz1] = ' '; memcpy(tmp + sz1 + 1, b->val, sz2); tmp[sz3] = CHAR_NULL; - ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3); if (ch != CHAR_NULL) { @@ -1450,6 +1433,13 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) sf->tokenvec[2].type == TYPE_COMMA && sf->tokenvec[3].type == TYPE_LEFTPARENS && sf->tokenvec[4].type == TYPE_NUMBER + ) || + ( + sf->tokenvec[0].type == TYPE_BAREWORD && + sf->tokenvec[1].type == TYPE_RIGHTPARENS && + sf->tokenvec[2].type == TYPE_OPERATOR && + sf->tokenvec[3].type == TYPE_LEFTPARENS && + sf->tokenvec[4].type == TYPE_BAREWORD ) ) { @@ -1506,16 +1496,6 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; sf->stats_folds += 1; continue; - } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && - sf->tokenvec[left+1].type == TYPE_FUNCTION && - cstrcasecmp("IF", sf->tokenvec[left+1].val, sf->tokenvec[left+1].len) == 0) { - /* IF is normally a function, except in Transact-SQL where it can be used as a - * standalone control flow operator, e.g. ; IF 1=1 ... - * if found after a semicolon, convert from 'f' type to 'T' type - */ - sf->tokenvec[left+1].type = TYPE_TSQL; - left += 2; - continue; /* reparse everything, but we probably can advance left, and pos */ } else if ((sf->tokenvec[left].type == TYPE_OPERATOR || sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR) && (st_is_unary_op(&sf->tokenvec[left+1]) || @@ -1539,9 +1519,22 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) left -= 1; } continue; + } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && + sf->tokenvec[left+1].type == TYPE_FUNCTION && + (sf->tokenvec[left+1].val[0] == 'I' || + sf->tokenvec[left+1].val[0] == 'i' ) && + (sf->tokenvec[left+1].val[1] == 'F' || + sf->tokenvec[left+1].val[1] == 'f' )) { + /* IF is normally a function, except in Transact-SQL where it can be used as a + * standalone control flow operator, e.g. ; IF 1=1 ... + * if found after a semicolon, convert from 'f' type to 'T' type + */ + sf->tokenvec[left+1].type = TYPE_TSQL; + /* left += 2; */ + continue; /* reparse everything, but we probably can advance left, and pos */ } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) && sf->tokenvec[left+1].type == TYPE_LEFTPARENS && ( - /* TSQL functions but common enough to be collumn names */ + /* TSQL functions but common enough to be column names */ cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || @@ -1564,7 +1557,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) /* pos is the same * other conversions need to go here... for instance - * password CAN be a function, coalese CAN be a function + * password CAN be a function, coalesce CAN be a function */ sf->tokenvec[left].type = TYPE_FUNCTION; continue; @@ -1828,7 +1821,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) * 1,-sin(1) --> 1 (1) * Here, just do * 1,-sin(1) --> 1,sin(1) - * just remove unary opartor + * just remove unary operator */ st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); pos -= 1; @@ -1852,9 +1845,21 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf) pos -= 1; left = 0; continue; + } else if ((sf->tokenvec[left].type == TYPE_FUNCTION) && + (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) && + (sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) { + /* + * whats going on here + * Some SQL functions like USER() have 0 args + * if we get User(foo), then User is not a function + * This should be expanded since it eliminated a lot of false + * positives. + */ + if (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) { + sf->tokenvec[left].type = TYPE_BAREWORD; + } } - /* no folding -- assume left-most token is is good, now use the existing 2 tokens -- do not get another @@ -2019,7 +2024,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state) } /* - * return TRUE if sqli, false is benign + * return TRUE if SQLi, false is benign */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) { @@ -2033,10 +2038,10 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { /* - * if ending comment is contains 'sp_password' then it's sqli! + * if ending comment is contains 'sp_password' then it's SQLi! * MS Audit log apparently ignores anything with - * 'sp_password' in it. Unable to find primary refernece to - * this "feature" of SQL Server but seems to be known sqli + * 'sp_password' in it. Unable to find primary reference to + * this "feature" of SQL Server but seems to be known SQLi * technique */ if (my_memmem(sql_state->s, sql_state->slen, @@ -2055,7 +2060,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->fingerprint[1] == TYPE_UNION) { if (sql_state->stats_tokens == 2) { - /* not sure why but 1U comes up in Sqli attack + /* not sure why but 1U comes up in SQLi attack * likely part of parameter splitting/etc. * lots of reasons why "1 union" might be normal * input, so beep only if other SQLi things are present @@ -2080,7 +2085,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) /* * for fingerprint like 'nc', only comments of /x are treated - * as SQL... ending comments of "--" and "#" are not sqli + * as SQL... ending comments of "--" and "#" are not SQLi */ if (sql_state->tokenvec[0].type == TYPE_BAREWORD && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2090,7 +2095,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * if '1c' ends with '/x' then it's sqli + * if '1c' ends with '/x' then it's SQLi */ if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT && @@ -2113,13 +2118,13 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) if (sql_state->tokenvec[0].type == TYPE_NUMBER && sql_state->tokenvec[1].type == TYPE_COMMENT) { if (sql_state->stats_tokens > 2) { - /* we have some folding going on, highly likely sqli */ + /* we have some folding going on, highly likely SQLi */ sql_state->reason = __LINE__; return TRUE; } /* * we check that next character after the number is either whitespace, - * or '/' or a '-' ==> sqli. + * or '/' or a '-' ==> SQLi. */ ch = sql_state->s[sql_state->tokenvec[0].len]; if ( ch <= 32 ) { @@ -2141,7 +2146,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * detect obvious sqli scans.. many people put '--' in plain text + * detect obvious SQLi scans.. many people put '--' in plain text * so only detect if input ends with '--', e.g. 1-- but not 1-- foo */ if ((sql_state->tokenvec[1].len > 2) @@ -2177,7 +2182,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) } /* - * not sqli + * not SQLi */ sql_state->reason = __LINE__; return FALSE; @@ -2186,8 +2191,8 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) streq(sql_state->fingerprint, "1&1") || streq(sql_state->fingerprint, "1&v") || streq(sql_state->fingerprint, "1&s")) { - /* 'sexy and 17' not sqli - * 'sexy and 17<18' sqli + /* 'sexy and 17' not SQLi + * 'sexy and 17<18' SQLi */ if (sql_state->stats_tokens == 3) { sql_state->reason = __LINE__; @@ -2243,7 +2248,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) size_t slen = sql_state->slen; /* - * no input? not sqli + * no input? not SQLi */ if (slen == 0) { return FALSE; diff --git a/apache2/libinjection/libinjection_sqli.h b/apache2/libinjection/libinjection_sqli.h index 4f16db8dbf..b9746555a7 100644 --- a/apache2/libinjection/libinjection_sqli.h +++ b/apache2/libinjection/libinjection_sqli.h @@ -1,14 +1,14 @@ /** - * Copyright 2012, 2013 Nick Galbreath + * Copyright 2012-2016 Nick Galbreath * nickg@client9.com - * BSD License -- see COPYING.txt for details + * BSD License -- see `COPYING.txt` for details * * https://libinjection.client9.com/ * */ -#ifndef _LIBINJECTION_SQLI_H -#define _LIBINJECTION_SQLI_H +#ifndef LIBINJECTION_SQLI_H +#define LIBINJECTION_SQLI_H #ifdef __cplusplus extern "C" { @@ -40,10 +40,6 @@ struct libinjection_sqli_token { #ifdef SWIG %immutable; #endif - char type; - char str_open; - char str_close; - /* * position and length of token * in original string @@ -53,17 +49,20 @@ struct libinjection_sqli_token { /* count: * in type 'v', used for number of opening '@' - * but maybe unsed in other contexts + * but maybe used in other contexts */ int count; + char type; + char str_open; + char str_close; char val[32]; }; typedef struct libinjection_sqli_token stoken_t; /** - * Pointer to function, takes cstr input, + * Pointer to function, takes c-string input, * returns '\0' for no match, else a char */ struct libinjection_sqli_state; @@ -97,7 +96,7 @@ struct libinjection_sqli_state { int flags; /* - * pos is index in string we are at when tokenizing + * pos is the index in the string during tokenization */ size_t pos; @@ -118,7 +117,7 @@ struct libinjection_sqli_state { /* * fingerprint pattern c-string * +1 for ending null - * Mimimum of 8 bytes to add gcc's -fstack-protector to work + * Minimum of 8 bytes to add gcc's -fstack-protector to work */ char fingerprint[8]; @@ -156,7 +155,7 @@ struct libinjection_sqli_state { */ int stats_comment_c; - /* '#' operators or mysql EOL comments found + /* '#' operators or MySQL EOL comments found * */ int stats_comment_hash; @@ -208,8 +207,8 @@ void libinjection_sqli_init(struct libinjection_sqli_state* sql_state, */ int libinjection_is_sqli(struct libinjection_sqli_state* sql_state); -/* FOR H@CKERS ONLY - * +/* FOR HACKERS ONLY + * provides deep hooks into the decision making process */ void libinjection_sqli_callback(struct libinjection_sqli_state* sql_state, ptr_lookup_fn fn, @@ -269,7 +268,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sql_state); * two functions. With this, you over-ride one part or the other. * * return libinjection_sqli_blacklist(sql_state) && - * libinject_sqli_not_whitelist(sql_state); + * libinjection_sqli_not_whitelist(sql_state); * * \param sql_state should be filled out after libinjection_sqli_fingerprint is called */ @@ -284,7 +283,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state); /* Given a positive match for a pattern (i.e. pattern is SQLi), this function * does additional analysis to reduce false positives. * - * \return TRUE if sqli, false otherwise + * \return TRUE if SQLi, false otherwise */ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state); @@ -292,4 +291,4 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state); } #endif -#endif /* _LIBINJECTION_SQLI_H */ +#endif /* LIBINJECTION_SQLI_H */ diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h index 8f3a2e0e23..f5e1454143 100644 --- a/apache2/libinjection/libinjection_sqli_data.h +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -1,6 +1,6 @@ -#ifndef _LIBINJECTION_SQLI_DATA_H -#define _LIBINJECTION_SQLI_DATA_H +#ifndef LIBINJECTION_SQLI_DATA_H +#define LIBINJECTION_SQLI_DATA_H #include "libinjection.h" #include "libinjection_sqli.h" @@ -164,6 +164,134 @@ static const pt2Function char_parse_map[] = { &parse_char, /* 125 */ &parse_operator1, /* 126 */ &parse_white, /* 127 */ + &parse_word, /* 128 */ + &parse_word, /* 129 */ + &parse_word, /* 130 */ + &parse_word, /* 131 */ + &parse_word, /* 132 */ + &parse_word, /* 133 */ + &parse_word, /* 134 */ + &parse_word, /* 135 */ + &parse_word, /* 136 */ + &parse_word, /* 137 */ + &parse_word, /* 138 */ + &parse_word, /* 139 */ + &parse_word, /* 140 */ + &parse_word, /* 141 */ + &parse_word, /* 142 */ + &parse_word, /* 143 */ + &parse_word, /* 144 */ + &parse_word, /* 145 */ + &parse_word, /* 146 */ + &parse_word, /* 147 */ + &parse_word, /* 148 */ + &parse_word, /* 149 */ + &parse_word, /* 150 */ + &parse_word, /* 151 */ + &parse_word, /* 152 */ + &parse_word, /* 153 */ + &parse_word, /* 154 */ + &parse_word, /* 155 */ + &parse_word, /* 156 */ + &parse_word, /* 157 */ + &parse_word, /* 158 */ + &parse_word, /* 159 */ + &parse_white, /* 160 */ + &parse_word, /* 161 */ + &parse_word, /* 162 */ + &parse_word, /* 163 */ + &parse_word, /* 164 */ + &parse_word, /* 165 */ + &parse_word, /* 166 */ + &parse_word, /* 167 */ + &parse_word, /* 168 */ + &parse_word, /* 169 */ + &parse_word, /* 170 */ + &parse_word, /* 171 */ + &parse_word, /* 172 */ + &parse_word, /* 173 */ + &parse_word, /* 174 */ + &parse_word, /* 175 */ + &parse_word, /* 176 */ + &parse_word, /* 177 */ + &parse_word, /* 178 */ + &parse_word, /* 179 */ + &parse_word, /* 180 */ + &parse_word, /* 181 */ + &parse_word, /* 182 */ + &parse_word, /* 183 */ + &parse_word, /* 184 */ + &parse_word, /* 185 */ + &parse_word, /* 186 */ + &parse_word, /* 187 */ + &parse_word, /* 188 */ + &parse_word, /* 189 */ + &parse_word, /* 190 */ + &parse_word, /* 191 */ + &parse_word, /* 192 */ + &parse_word, /* 193 */ + &parse_word, /* 194 */ + &parse_word, /* 195 */ + &parse_word, /* 196 */ + &parse_word, /* 197 */ + &parse_word, /* 198 */ + &parse_word, /* 199 */ + &parse_word, /* 200 */ + &parse_word, /* 201 */ + &parse_word, /* 202 */ + &parse_word, /* 203 */ + &parse_word, /* 204 */ + &parse_word, /* 205 */ + &parse_word, /* 206 */ + &parse_word, /* 207 */ + &parse_word, /* 208 */ + &parse_word, /* 209 */ + &parse_word, /* 210 */ + &parse_word, /* 211 */ + &parse_word, /* 212 */ + &parse_word, /* 213 */ + &parse_word, /* 214 */ + &parse_word, /* 215 */ + &parse_word, /* 216 */ + &parse_word, /* 217 */ + &parse_word, /* 218 */ + &parse_word, /* 219 */ + &parse_word, /* 220 */ + &parse_word, /* 221 */ + &parse_word, /* 222 */ + &parse_word, /* 223 */ + &parse_word, /* 224 */ + &parse_word, /* 225 */ + &parse_word, /* 226 */ + &parse_word, /* 227 */ + &parse_word, /* 228 */ + &parse_word, /* 229 */ + &parse_word, /* 230 */ + &parse_word, /* 231 */ + &parse_word, /* 232 */ + &parse_word, /* 233 */ + &parse_word, /* 234 */ + &parse_word, /* 235 */ + &parse_word, /* 236 */ + &parse_word, /* 237 */ + &parse_word, /* 238 */ + &parse_word, /* 239 */ + &parse_word, /* 240 */ + &parse_word, /* 241 */ + &parse_word, /* 242 */ + &parse_word, /* 243 */ + &parse_word, /* 244 */ + &parse_word, /* 245 */ + &parse_word, /* 246 */ + &parse_word, /* 247 */ + &parse_word, /* 248 */ + &parse_word, /* 249 */ + &parse_word, /* 250 */ + &parse_word, /* 251 */ + &parse_word, /* 252 */ + &parse_word, /* 253 */ + &parse_word, /* 254 */ + &parse_word, /* 255 */ }; static const keyword_t sql_keywords[] = { @@ -317,6 +445,8 @@ static const keyword_t sql_keywords[] = { {"0&VUEN", 'F'}, {"0&VUES", 'F'}, {"0&VUEV", 'F'}, + {"0)&(EK", 'F'}, + {"0)&(EN", 'F'}, {"0)UE(1", 'F'}, {"0)UE(F", 'F'}, {"0)UE(N", 'F'}, @@ -395,7 +525,6 @@ static const keyword_t sql_keywords[] = { {"01&1KV", 'F'}, {"01&1O(", 'F'}, {"01&1OF", 'F'}, - {"01&1OO", 'F'}, {"01&1OS", 'F'}, {"01&1OV", 'F'}, {"01&1TN", 'F'}, @@ -458,6 +587,7 @@ static const keyword_t sql_keywords[] = { {"01&K(S", 'F'}, {"01&K(V", 'F'}, {"01&K1O", 'F'}, + {"01&KC", 'F'}, {"01&KF(", 'F'}, {"01&KNK", 'F'}, {"01&KO(", 'F'}, @@ -522,7 +652,6 @@ static const keyword_t sql_keywords[] = { {"01&S1", 'F'}, {"01&S1;", 'F'}, {"01&S1C", 'F'}, - {"01&S1O", 'F'}, {"01&S;", 'F'}, {"01&S;C", 'F'}, {"01&S;E", 'F'}, @@ -547,7 +676,6 @@ static const keyword_t sql_keywords[] = { {"01&SO1", 'F'}, {"01&SOF", 'F'}, {"01&SON", 'F'}, - {"01&SOO", 'F'}, {"01&SOS", 'F'}, {"01&SOV", 'F'}, {"01&STN", 'F'}, @@ -593,7 +721,6 @@ static const keyword_t sql_keywords[] = { {"01&VKV", 'F'}, {"01&VO(", 'F'}, {"01&VOF", 'F'}, - {"01&VOO", 'F'}, {"01&VOS", 'F'}, {"01&VS", 'F'}, {"01&VS;", 'F'}, @@ -730,6 +857,7 @@ static const keyword_t sql_keywords[] = { {"01)ESO", 'F'}, {"01)EVC", 'F'}, {"01)EVO", 'F'}, + {"01)F(F", 'F'}, {"01)K(1", 'F'}, {"01)K(F", 'F'}, {"01)K(N", 'F'}, @@ -751,6 +879,7 @@ static const keyword_t sql_keywords[] = { {"01)KN&", 'F'}, {"01)KN;", 'F'}, {"01)KNB", 'F'}, + {"01)KNC", 'F'}, {"01)KNE", 'F'}, {"01)KNK", 'F'}, {"01)KNU", 'F'}, @@ -877,11 +1006,13 @@ static const keyword_t sql_keywords[] = { {"01;EVT", 'F'}, {"01;N:T", 'F'}, {"01;T(1", 'F'}, + {"01;T(C", 'F'}, {"01;T(E", 'F'}, {"01;T(F", 'F'}, {"01;T(N", 'F'}, {"01;T(S", 'F'}, {"01;T(V", 'F'}, + {"01;T1(", 'F'}, {"01;T1,", 'F'}, {"01;T1;", 'F'}, {"01;T1C", 'F'}, @@ -913,6 +1044,7 @@ static const keyword_t sql_keywords[] = { {"01;TNT", 'F'}, {"01;TNV", 'F'}, {"01;TO(", 'F'}, + {"01;TS(", 'F'}, {"01;TS,", 'F'}, {"01;TS;", 'F'}, {"01;TSC", 'F'}, @@ -920,12 +1052,8 @@ static const keyword_t sql_keywords[] = { {"01;TSK", 'F'}, {"01;TSO", 'F'}, {"01;TST", 'F'}, - {"01;TT(", 'F'}, - {"01;TT1", 'F'}, - {"01;TTF", 'F'}, {"01;TTN", 'F'}, - {"01;TTS", 'F'}, - {"01;TTV", 'F'}, + {"01;TV(", 'F'}, {"01;TV,", 'F'}, {"01;TV;", 'F'}, {"01;TVC", 'F'}, @@ -967,7 +1095,6 @@ static const keyword_t sql_keywords[] = { {"01B(1)", 'F'}, {"01B(1O", 'F'}, {"01B(F(", 'F'}, - {"01B(N)", 'F'}, {"01B(NO", 'F'}, {"01B(S)", 'F'}, {"01B(SO", 'F'}, @@ -1116,11 +1243,18 @@ static const keyword_t sql_keywords[] = { {"01E(SO", 'F'}, {"01E(V)", 'F'}, {"01E(VO", 'F'}, + {"01E1;T", 'F'}, {"01E1C", 'F'}, {"01E1O(", 'F'}, {"01E1OF", 'F'}, {"01E1OS", 'F'}, {"01E1OV", 'F'}, + {"01E1T(", 'F'}, + {"01E1T1", 'F'}, + {"01E1TF", 'F'}, + {"01E1TN", 'F'}, + {"01E1TS", 'F'}, + {"01E1TV", 'F'}, {"01E1UE", 'F'}, {"01EF()", 'F'}, {"01EF(1", 'F'}, @@ -1134,35 +1268,50 @@ static const keyword_t sql_keywords[] = { {"01EK(N", 'F'}, {"01EK(S", 'F'}, {"01EK(V", 'F'}, + {"01EK1;", 'F'}, {"01EK1C", 'F'}, {"01EK1O", 'F'}, + {"01EK1T", 'F'}, {"01EK1U", 'F'}, {"01EKF(", 'F'}, + {"01EKN;", 'F'}, {"01EKNC", 'F'}, {"01EKNE", 'F'}, + {"01EKNT", 'F'}, {"01EKNU", 'F'}, {"01EKOK", 'F'}, + {"01EKS;", 'F'}, {"01EKSC", 'F'}, {"01EKSO", 'F'}, + {"01EKST", 'F'}, {"01EKSU", 'F'}, {"01EKU(", 'F'}, {"01EKU1", 'F'}, {"01EKUE", 'F'}, {"01EKUF", 'F'}, - {"01EKUN", 'F'}, {"01EKUS", 'F'}, {"01EKUV", 'F'}, + {"01EKV;", 'F'}, {"01EKVC", 'F'}, {"01EKVO", 'F'}, + {"01EKVT", 'F'}, {"01EKVU", 'F'}, + {"01EN;T", 'F'}, {"01ENC", 'F'}, {"01ENEN", 'F'}, {"01ENO(", 'F'}, {"01ENOF", 'F'}, {"01ENOS", 'F'}, {"01ENOV", 'F'}, + {"01ENT(", 'F'}, + {"01ENT1", 'F'}, + {"01ENTF", 'F'}, + {"01ENTN", 'F'}, + {"01ENTS", 'F'}, + {"01ENTV", 'F'}, {"01ENUE", 'F'}, {"01EOKN", 'F'}, + {"01ES;T", 'F'}, {"01ESC", 'F'}, {"01ESO(", 'F'}, {"01ESO1", 'F'}, @@ -1170,6 +1319,12 @@ static const keyword_t sql_keywords[] = { {"01ESON", 'F'}, {"01ESOS", 'F'}, {"01ESOV", 'F'}, + {"01EST(", 'F'}, + {"01EST1", 'F'}, + {"01ESTF", 'F'}, + {"01ESTN", 'F'}, + {"01ESTS", 'F'}, + {"01ESTV", 'F'}, {"01ESUE", 'F'}, {"01EU(1", 'F'}, {"01EU(F", 'F'}, @@ -1182,19 +1337,23 @@ static const keyword_t sql_keywords[] = { {"01EUEF", 'F'}, {"01EUEK", 'F'}, {"01EUF(", 'F'}, - {"01EUN,", 'F'}, - {"01EUNC", 'F'}, - {"01EUNO", 'F'}, {"01EUS,", 'F'}, {"01EUSC", 'F'}, {"01EUSO", 'F'}, {"01EUV,", 'F'}, {"01EUVC", 'F'}, {"01EUVO", 'F'}, + {"01EV;T", 'F'}, {"01EVC", 'F'}, {"01EVO(", 'F'}, {"01EVOF", 'F'}, {"01EVOS", 'F'}, + {"01EVT(", 'F'}, + {"01EVT1", 'F'}, + {"01EVTF", 'F'}, + {"01EVTN", 'F'}, + {"01EVTS", 'F'}, + {"01EVTV", 'F'}, {"01EVUE", 'F'}, {"01F()1", 'F'}, {"01F()F", 'F'}, @@ -1251,6 +1410,8 @@ static const keyword_t sql_keywords[] = { {"01K)EN", 'F'}, {"01K)ES", 'F'}, {"01K)EV", 'F'}, + {"01K)F(", 'F'}, + {"01K)O(", 'F'}, {"01K)OF", 'F'}, {"01K)UE", 'F'}, {"01K1", 'F'}, @@ -1387,7 +1548,6 @@ static const keyword_t sql_keywords[] = { {"01KVU(", 'F'}, {"01KVUE", 'F'}, {"01N&F(", 'F'}, - {"01N(1)", 'F'}, {"01N(1O", 'F'}, {"01N(F(", 'F'}, {"01N(S)", 'F'}, @@ -1410,12 +1570,6 @@ static const keyword_t sql_keywords[] = { {"01NESO", 'F'}, {"01NEVC", 'F'}, {"01NEVO", 'F'}, - {"01NF()", 'F'}, - {"01NF(1", 'F'}, - {"01NF(F", 'F'}, - {"01NF(N", 'F'}, - {"01NF(S", 'F'}, - {"01NF(V", 'F'}, {"01NU(E", 'F'}, {"01NUE", 'F'}, {"01NUE(", 'F'}, @@ -1437,6 +1591,7 @@ static const keyword_t sql_keywords[] = { {"01O(EF", 'F'}, {"01O(EK", 'F'}, {"01O(EN", 'F'}, + {"01O(EO", 'F'}, {"01O(ES", 'F'}, {"01O(EV", 'F'}, {"01O(F(", 'F'}, @@ -1502,6 +1657,7 @@ static const keyword_t sql_keywords[] = { {"01OS)B", 'F'}, {"01OS)C", 'F'}, {"01OS)E", 'F'}, + {"01OS)F", 'F'}, {"01OS)K", 'F'}, {"01OS)O", 'F'}, {"01OS)U", 'F'}, @@ -1550,6 +1706,14 @@ static const keyword_t sql_keywords[] = { {"01OSKS", 'F'}, {"01OSKU", 'F'}, {"01OSKV", 'F'}, + {"01OST(", 'F'}, + {"01OST1", 'F'}, + {"01OSTE", 'F'}, + {"01OSTF", 'F'}, + {"01OSTN", 'F'}, + {"01OSTS", 'F'}, + {"01OSTT", 'F'}, + {"01OSTV", 'F'}, {"01OSU", 'F'}, {"01OSU(", 'F'}, {"01OSU1", 'F'}, @@ -1558,7 +1722,6 @@ static const keyword_t sql_keywords[] = { {"01OSUE", 'F'}, {"01OSUF", 'F'}, {"01OSUK", 'F'}, - {"01OSUN", 'F'}, {"01OSUO", 'F'}, {"01OSUS", 'F'}, {"01OSUT", 'F'}, @@ -1589,6 +1752,7 @@ static const keyword_t sql_keywords[] = { {"01OV)B", 'F'}, {"01OV)C", 'F'}, {"01OV)E", 'F'}, + {"01OV)F", 'F'}, {"01OV)K", 'F'}, {"01OV)O", 'F'}, {"01OV)U", 'F'}, @@ -1642,6 +1806,14 @@ static const keyword_t sql_keywords[] = { {"01OVSO", 'F'}, {"01OVSU", 'F'}, {"01OVSV", 'F'}, + {"01OVT(", 'F'}, + {"01OVT1", 'F'}, + {"01OVTE", 'F'}, + {"01OVTF", 'F'}, + {"01OVTN", 'F'}, + {"01OVTS", 'F'}, + {"01OVTT", 'F'}, + {"01OVTV", 'F'}, {"01OVU", 'F'}, {"01OVU(", 'F'}, {"01OVU1", 'F'}, @@ -1650,7 +1822,6 @@ static const keyword_t sql_keywords[] = { {"01OVUE", 'F'}, {"01OVUF", 'F'}, {"01OVUK", 'F'}, - {"01OVUN", 'F'}, {"01OVUO", 'F'}, {"01OVUS", 'F'}, {"01OVUT", 'F'}, @@ -1672,6 +1843,96 @@ static const keyword_t sql_keywords[] = { {"01SVO(", 'F'}, {"01SVOF", 'F'}, {"01SVOS", 'F'}, + {"01T(1)", 'F'}, + {"01T(1O", 'F'}, + {"01T(F(", 'F'}, + {"01T(N)", 'F'}, + {"01T(NO", 'F'}, + {"01T(S)", 'F'}, + {"01T(SO", 'F'}, + {"01T(V)", 'F'}, + {"01T(VO", 'F'}, + {"01T1(F", 'F'}, + {"01T1O(", 'F'}, + {"01T1OF", 'F'}, + {"01T1OS", 'F'}, + {"01T1OV", 'F'}, + {"01TE(1", 'F'}, + {"01TE(F", 'F'}, + {"01TE(N", 'F'}, + {"01TE(S", 'F'}, + {"01TE(V", 'F'}, + {"01TE1N", 'F'}, + {"01TE1O", 'F'}, + {"01TEF(", 'F'}, + {"01TEK(", 'F'}, + {"01TEK1", 'F'}, + {"01TEKF", 'F'}, + {"01TEKN", 'F'}, + {"01TEKS", 'F'}, + {"01TEKV", 'F'}, + {"01TENN", 'F'}, + {"01TENO", 'F'}, + {"01TESN", 'F'}, + {"01TESO", 'F'}, + {"01TEVN", 'F'}, + {"01TEVO", 'F'}, + {"01TF()", 'F'}, + {"01TF(1", 'F'}, + {"01TF(F", 'F'}, + {"01TF(N", 'F'}, + {"01TF(S", 'F'}, + {"01TF(V", 'F'}, + {"01TN(1", 'F'}, + {"01TN(F", 'F'}, + {"01TN(S", 'F'}, + {"01TN(V", 'F'}, + {"01TN1C", 'F'}, + {"01TN1O", 'F'}, + {"01TN;E", 'F'}, + {"01TN;N", 'F'}, + {"01TN;T", 'F'}, + {"01TNE(", 'F'}, + {"01TNE1", 'F'}, + {"01TNEF", 'F'}, + {"01TNEN", 'F'}, + {"01TNES", 'F'}, + {"01TNEV", 'F'}, + {"01TNF(", 'F'}, + {"01TNKN", 'F'}, + {"01TNN:", 'F'}, + {"01TNNC", 'F'}, + {"01TNNO", 'F'}, + {"01TNO(", 'F'}, + {"01TNOF", 'F'}, + {"01TNOS", 'F'}, + {"01TNOV", 'F'}, + {"01TNSC", 'F'}, + {"01TNSO", 'F'}, + {"01TNT(", 'F'}, + {"01TNT1", 'F'}, + {"01TNTF", 'F'}, + {"01TNTN", 'F'}, + {"01TNTS", 'F'}, + {"01TNTV", 'F'}, + {"01TNVC", 'F'}, + {"01TNVO", 'F'}, + {"01TS(F", 'F'}, + {"01TSO(", 'F'}, + {"01TSO1", 'F'}, + {"01TSOF", 'F'}, + {"01TSON", 'F'}, + {"01TSOS", 'F'}, + {"01TSOV", 'F'}, + {"01TTNE", 'F'}, + {"01TTNK", 'F'}, + {"01TTNN", 'F'}, + {"01TTNT", 'F'}, + {"01TV(1", 'F'}, + {"01TV(F", 'F'}, + {"01TVO(", 'F'}, + {"01TVOF", 'F'}, + {"01TVOS", 'F'}, {"01U", 'F'}, {"01U(1)", 'F'}, {"01U(1O", 'F'}, @@ -1757,7 +2018,6 @@ static const keyword_t sql_keywords[] = { {"01UENU", 'F'}, {"01UEOK", 'F'}, {"01UEON", 'F'}, - {"01UEOO", 'F'}, {"01UES", 'F'}, {"01UES&", 'F'}, {"01UES(", 'F'}, @@ -1793,30 +2053,6 @@ static const keyword_t sql_keywords[] = { {"01UF(S", 'F'}, {"01UF(V", 'F'}, {"01UK(E", 'F'}, - {"01UN(1", 'F'}, - {"01UN(F", 'F'}, - {"01UN(S", 'F'}, - {"01UN(V", 'F'}, - {"01UN,(", 'F'}, - {"01UN,F", 'F'}, - {"01UN1(", 'F'}, - {"01UN1,", 'F'}, - {"01UN1O", 'F'}, - {"01UNC", 'F'}, - {"01UNE(", 'F'}, - {"01UNE1", 'F'}, - {"01UNEF", 'F'}, - {"01UNEN", 'F'}, - {"01UNES", 'F'}, - {"01UNEV", 'F'}, - {"01UNF(", 'F'}, - {"01UNO(", 'F'}, - {"01UNOF", 'F'}, - {"01UNOS", 'F'}, - {"01UNOV", 'F'}, - {"01UNS(", 'F'}, - {"01UNS,", 'F'}, - {"01UNSO", 'F'}, {"01UO(E", 'F'}, {"01UON(", 'F'}, {"01UON1", 'F'}, @@ -1834,7 +2070,9 @@ static const keyword_t sql_keywords[] = { {"01UTN(", 'F'}, {"01UTN1", 'F'}, {"01UTNF", 'F'}, + {"01UTNN", 'F'}, {"01UTNS", 'F'}, + {"01UTNV", 'F'}, {"01UV,(", 'F'}, {"01UV,F", 'F'}, {"01UVC", 'F'}, @@ -1872,6 +2110,8 @@ static const keyword_t sql_keywords[] = { {"01VUE;", 'F'}, {"01VUEC", 'F'}, {"01VUEK", 'F'}, + {"0;T(EF", 'F'}, + {"0;T(EK", 'F'}, {"0;TKNC", 'F'}, {"0E(1&(", 'F'}, {"0E(1&1", 'F'}, @@ -1986,7 +2226,6 @@ static const keyword_t sql_keywords[] = { {"0E(S)V", 'F'}, {"0E(S,F", 'F'}, {"0E(S1)", 'F'}, - {"0E(S1O", 'F'}, {"0E(SF(", 'F'}, {"0E(SO(", 'F'}, {"0E(SO1", 'F'}, @@ -2270,7 +2509,6 @@ static const keyword_t sql_keywords[] = { {"0EK1N)", 'F'}, {"0EK1N;", 'F'}, {"0EK1NC", 'F'}, - {"0EK1NF", 'F'}, {"0EK1NK", 'F'}, {"0EK1O(", 'F'}, {"0EK1OF", 'F'}, @@ -2321,7 +2559,6 @@ static const keyword_t sql_keywords[] = { {"0EKN1", 'F'}, {"0EKN1;", 'F'}, {"0EKN1C", 'F'}, - {"0EKN1F", 'F'}, {"0EKN1K", 'F'}, {"0EKN1O", 'F'}, {"0EKN;(", 'F'}, @@ -2367,7 +2604,6 @@ static const keyword_t sql_keywords[] = { {"0EKS1C", 'F'}, {"0EKS1F", 'F'}, {"0EKS1K", 'F'}, - {"0EKS1O", 'F'}, {"0EKS;(", 'F'}, {"0EKSB(", 'F'}, {"0EKSB1", 'F'}, @@ -2486,7 +2722,6 @@ static const keyword_t sql_keywords[] = { {"0EN,F(", 'F'}, {"0EN1;", 'F'}, {"0EN1;C", 'F'}, - {"0EN1C", 'F'}, {"0EN1O(", 'F'}, {"0EN1OF", 'F'}, {"0EN1OS", 'F'}, @@ -2620,10 +2855,6 @@ static const keyword_t sql_keywords[] = { {"0ES1;", 'F'}, {"0ES1;C", 'F'}, {"0ES1C", 'F'}, - {"0ES1O(", 'F'}, - {"0ES1OF", 'F'}, - {"0ES1OS", 'F'}, - {"0ES1OV", 'F'}, {"0ES;(E", 'F'}, {"0ESB(1", 'F'}, {"0ESB(F", 'F'}, @@ -2942,6 +3173,14 @@ static const keyword_t sql_keywords[] = { {"0F()SO", 'F'}, {"0F()SU", 'F'}, {"0F()SV", 'F'}, + {"0F()T(", 'F'}, + {"0F()T1", 'F'}, + {"0F()TE", 'F'}, + {"0F()TF", 'F'}, + {"0F()TN", 'F'}, + {"0F()TS", 'F'}, + {"0F()TT", 'F'}, + {"0F()TV", 'F'}, {"0F()U", 'F'}, {"0F()U(", 'F'}, {"0F()U1", 'F'}, @@ -2950,7 +3189,6 @@ static const keyword_t sql_keywords[] = { {"0F()UE", 'F'}, {"0F()UF", 'F'}, {"0F()UK", 'F'}, - {"0F()UN", 'F'}, {"0F()UO", 'F'}, {"0F()US", 'F'}, {"0F()UT", 'F'}, @@ -2980,6 +3218,7 @@ static const keyword_t sql_keywords[] = { {"0F(1)N", 'F'}, {"0F(1)O", 'F'}, {"0F(1)S", 'F'}, + {"0F(1)T", 'F'}, {"0F(1)U", 'F'}, {"0F(1)V", 'F'}, {"0F(1,(", 'F'}, @@ -3003,12 +3242,14 @@ static const keyword_t sql_keywords[] = { {"0F(EK1", 'F'}, {"0F(EKF", 'F'}, {"0F(EKN", 'F'}, + {"0F(EKO", 'F'}, {"0F(EKS", 'F'}, {"0F(EKV", 'F'}, {"0F(EN&", 'F'}, {"0F(EN)", 'F'}, {"0F(ENK", 'F'}, {"0F(ENO", 'F'}, + {"0F(EOK", 'F'}, {"0F(ES&", 'F'}, {"0F(ES)", 'F'}, {"0F(ESK", 'F'}, @@ -3047,6 +3288,7 @@ static const keyword_t sql_keywords[] = { {"0F(N)N", 'F'}, {"0F(N)O", 'F'}, {"0F(N)S", 'F'}, + {"0F(N)T", 'F'}, {"0F(N)U", 'F'}, {"0F(N)V", 'F'}, {"0F(N,(", 'F'}, @@ -3075,6 +3317,7 @@ static const keyword_t sql_keywords[] = { {"0F(S)N", 'F'}, {"0F(S)O", 'F'}, {"0F(S)S", 'F'}, + {"0F(S)T", 'F'}, {"0F(S)U", 'F'}, {"0F(S)V", 'F'}, {"0F(S,(", 'F'}, @@ -3107,6 +3350,7 @@ static const keyword_t sql_keywords[] = { {"0F(V)N", 'F'}, {"0F(V)O", 'F'}, {"0F(V)S", 'F'}, + {"0F(V)T", 'F'}, {"0F(V)U", 'F'}, {"0F(V)V", 'F'}, {"0F(V,(", 'F'}, @@ -3395,7 +3639,6 @@ static const keyword_t sql_keywords[] = { {"0N&1KV", 'F'}, {"0N&1O(", 'F'}, {"0N&1OF", 'F'}, - {"0N&1OO", 'F'}, {"0N&1OS", 'F'}, {"0N&1OV", 'F'}, {"0N&1TN", 'F'}, @@ -3455,6 +3698,7 @@ static const keyword_t sql_keywords[] = { {"0N&K(S", 'F'}, {"0N&K(V", 'F'}, {"0N&K1O", 'F'}, + {"0N&KC", 'F'}, {"0N&KF(", 'F'}, {"0N&KNK", 'F'}, {"0N&KO(", 'F'}, @@ -3481,7 +3725,6 @@ static const keyword_t sql_keywords[] = { {"0N&NB(", 'F'}, {"0N&NB1", 'F'}, {"0N&NBF", 'F'}, - {"0N&NBN", 'F'}, {"0N&NBS", 'F'}, {"0N&NBV", 'F'}, {"0N&NF(", 'F'}, @@ -3512,7 +3755,6 @@ static const keyword_t sql_keywords[] = { {"0N&S1", 'F'}, {"0N&S1;", 'F'}, {"0N&S1C", 'F'}, - {"0N&S1O", 'F'}, {"0N&S;", 'F'}, {"0N&S;C", 'F'}, {"0N&S;E", 'F'}, @@ -3537,7 +3779,6 @@ static const keyword_t sql_keywords[] = { {"0N&SO1", 'F'}, {"0N&SOF", 'F'}, {"0N&SON", 'F'}, - {"0N&SOO", 'F'}, {"0N&SOS", 'F'}, {"0N&SOV", 'F'}, {"0N&STN", 'F'}, @@ -3583,7 +3824,6 @@ static const keyword_t sql_keywords[] = { {"0N&VKV", 'F'}, {"0N&VO(", 'F'}, {"0N&VOF", 'F'}, - {"0N&VOO", 'F'}, {"0N&VOS", 'F'}, {"0N&VS", 'F'}, {"0N&VS;", 'F'}, @@ -3595,48 +3835,6 @@ static const keyword_t sql_keywords[] = { {"0N&VU;", 'F'}, {"0N&VUC", 'F'}, {"0N&VUE", 'F'}, - {"0N(1)F", 'F'}, - {"0N(1)O", 'F'}, - {"0N(1)U", 'F'}, - {"0N(1)V", 'F'}, - {"0N(1O(", 'F'}, - {"0N(1OF", 'F'}, - {"0N(1OS", 'F'}, - {"0N(1OV", 'F'}, - {"0N(EF(", 'F'}, - {"0N(EKF", 'F'}, - {"0N(EKN", 'F'}, - {"0N(ENK", 'F'}, - {"0N(F()", 'F'}, - {"0N(F(1", 'F'}, - {"0N(F(F", 'F'}, - {"0N(F(N", 'F'}, - {"0N(F(S", 'F'}, - {"0N(F(V", 'F'}, - {"0N(S)1", 'F'}, - {"0N(S)F", 'F'}, - {"0N(S)N", 'F'}, - {"0N(S)O", 'F'}, - {"0N(S)S", 'F'}, - {"0N(S)U", 'F'}, - {"0N(S)V", 'F'}, - {"0N(SO(", 'F'}, - {"0N(SO1", 'F'}, - {"0N(SOF", 'F'}, - {"0N(SON", 'F'}, - {"0N(SOS", 'F'}, - {"0N(SOV", 'F'}, - {"0N(U(E", 'F'}, - {"0N(V)1", 'F'}, - {"0N(V)F", 'F'}, - {"0N(V)N", 'F'}, - {"0N(V)O", 'F'}, - {"0N(V)S", 'F'}, - {"0N(V)U", 'F'}, - {"0N(V)V", 'F'}, - {"0N(VO(", 'F'}, - {"0N(VOF", 'F'}, - {"0N(VOS", 'F'}, {"0N)&(1", 'F'}, {"0N)&(E", 'F'}, {"0N)&(F", 'F'}, @@ -3756,6 +3954,7 @@ static const keyword_t sql_keywords[] = { {"0N)ESO", 'F'}, {"0N)EVC", 'F'}, {"0N)EVO", 'F'}, + {"0N)F(F", 'F'}, {"0N)K(1", 'F'}, {"0N)K(F", 'F'}, {"0N)K(N", 'F'}, @@ -3777,6 +3976,7 @@ static const keyword_t sql_keywords[] = { {"0N)KN&", 'F'}, {"0N)KN;", 'F'}, {"0N)KNB", 'F'}, + {"0N)KNC", 'F'}, {"0N)KNE", 'F'}, {"0N)KNK", 'F'}, {"0N)KNU", 'F'}, @@ -3807,7 +4007,6 @@ static const keyword_t sql_keywords[] = { {"0N)O1K", 'F'}, {"0N)O1U", 'F'}, {"0N)OF(", 'F'}, - {"0N)ON", 'F'}, {"0N)ON&", 'F'}, {"0N)ON)", 'F'}, {"0N)ON;", 'F'}, @@ -3861,12 +4060,6 @@ static const keyword_t sql_keywords[] = { {"0N,F(N", 'F'}, {"0N,F(S", 'F'}, {"0N,F(V", 'F'}, - {"0N1F()", 'F'}, - {"0N1F(1", 'F'}, - {"0N1F(F", 'F'}, - {"0N1F(N", 'F'}, - {"0N1F(S", 'F'}, - {"0N1F(V", 'F'}, {"0N1O(1", 'F'}, {"0N1O(F", 'F'}, {"0N1O(N", 'F'}, @@ -3937,11 +4130,13 @@ static const keyword_t sql_keywords[] = { {"0N;EVT", 'F'}, {"0N;N:T", 'F'}, {"0N;T(1", 'F'}, + {"0N;T(C", 'F'}, {"0N;T(E", 'F'}, {"0N;T(F", 'F'}, {"0N;T(N", 'F'}, {"0N;T(S", 'F'}, {"0N;T(V", 'F'}, + {"0N;T1(", 'F'}, {"0N;T1,", 'F'}, {"0N;T1;", 'F'}, {"0N;T1C", 'F'}, @@ -3956,7 +4151,6 @@ static const keyword_t sql_keywords[] = { {"0N;TK1", 'F'}, {"0N;TKF", 'F'}, {"0N;TKK", 'F'}, - {"0N;TKN", 'F'}, {"0N;TKO", 'F'}, {"0N;TKS", 'F'}, {"0N;TKV", 'F'}, @@ -3974,6 +4168,7 @@ static const keyword_t sql_keywords[] = { {"0N;TNT", 'F'}, {"0N;TNV", 'F'}, {"0N;TO(", 'F'}, + {"0N;TS(", 'F'}, {"0N;TS,", 'F'}, {"0N;TS;", 'F'}, {"0N;TSC", 'F'}, @@ -3981,12 +4176,8 @@ static const keyword_t sql_keywords[] = { {"0N;TSK", 'F'}, {"0N;TSO", 'F'}, {"0N;TST", 'F'}, - {"0N;TT(", 'F'}, - {"0N;TT1", 'F'}, - {"0N;TTF", 'F'}, {"0N;TTN", 'F'}, - {"0N;TTS", 'F'}, - {"0N;TTV", 'F'}, + {"0N;TV(", 'F'}, {"0N;TV,", 'F'}, {"0N;TV;", 'F'}, {"0N;TVC", 'F'}, @@ -4025,13 +4216,16 @@ static const keyword_t sql_keywords[] = { {"0NAVOF", 'F'}, {"0NAVOS", 'F'}, {"0NAVUE", 'F'}, + {"0NB(1&", 'F'}, {"0NB(1)", 'F'}, {"0NB(1O", 'F'}, {"0NB(F(", 'F'}, - {"0NB(N)", 'F'}, + {"0NB(N&", 'F'}, {"0NB(NO", 'F'}, + {"0NB(S&", 'F'}, {"0NB(S)", 'F'}, {"0NB(SO", 'F'}, + {"0NB(V&", 'F'}, {"0NB(V)", 'F'}, {"0NB(VO", 'F'}, {"0NB1", 'F'}, @@ -4176,11 +4370,18 @@ static const keyword_t sql_keywords[] = { {"0NE(SO", 'F'}, {"0NE(V)", 'F'}, {"0NE(VO", 'F'}, + {"0NE1;T", 'F'}, {"0NE1C", 'F'}, {"0NE1O(", 'F'}, {"0NE1OF", 'F'}, {"0NE1OS", 'F'}, {"0NE1OV", 'F'}, + {"0NE1T(", 'F'}, + {"0NE1T1", 'F'}, + {"0NE1TF", 'F'}, + {"0NE1TN", 'F'}, + {"0NE1TS", 'F'}, + {"0NE1TV", 'F'}, {"0NE1UE", 'F'}, {"0NEF()", 'F'}, {"0NEF(1", 'F'}, @@ -4188,13 +4389,20 @@ static const keyword_t sql_keywords[] = { {"0NEF(N", 'F'}, {"0NEF(S", 'F'}, {"0NEF(V", 'F'}, - {"0NENC", 'F'}, + {"0NEN;T", 'F'}, {"0NENO(", 'F'}, {"0NENOF", 'F'}, {"0NENOS", 'F'}, {"0NENOV", 'F'}, + {"0NENT(", 'F'}, + {"0NENT1", 'F'}, + {"0NENTF", 'F'}, + {"0NENTN", 'F'}, + {"0NENTS", 'F'}, + {"0NENTV", 'F'}, {"0NENUE", 'F'}, {"0NEOKN", 'F'}, + {"0NES;T", 'F'}, {"0NESC", 'F'}, {"0NESO(", 'F'}, {"0NESO1", 'F'}, @@ -4202,6 +4410,12 @@ static const keyword_t sql_keywords[] = { {"0NESON", 'F'}, {"0NESOS", 'F'}, {"0NESOV", 'F'}, + {"0NEST(", 'F'}, + {"0NEST1", 'F'}, + {"0NESTF", 'F'}, + {"0NESTN", 'F'}, + {"0NESTS", 'F'}, + {"0NESTV", 'F'}, {"0NESUE", 'F'}, {"0NEU(1", 'F'}, {"0NEU(F", 'F'}, @@ -4214,19 +4428,23 @@ static const keyword_t sql_keywords[] = { {"0NEUEF", 'F'}, {"0NEUEK", 'F'}, {"0NEUF(", 'F'}, - {"0NEUN,", 'F'}, - {"0NEUNC", 'F'}, - {"0NEUNO", 'F'}, {"0NEUS,", 'F'}, {"0NEUSC", 'F'}, {"0NEUSO", 'F'}, {"0NEUV,", 'F'}, {"0NEUVC", 'F'}, {"0NEUVO", 'F'}, + {"0NEV;T", 'F'}, {"0NEVC", 'F'}, {"0NEVO(", 'F'}, {"0NEVOF", 'F'}, {"0NEVOS", 'F'}, + {"0NEVT(", 'F'}, + {"0NEVT1", 'F'}, + {"0NEVTF", 'F'}, + {"0NEVTN", 'F'}, + {"0NEVTS", 'F'}, + {"0NEVTV", 'F'}, {"0NEVUE", 'F'}, {"0NF()1", 'F'}, {"0NF()F", 'F'}, @@ -4237,7 +4455,6 @@ static const keyword_t sql_keywords[] = { {"0NF()U", 'F'}, {"0NF()V", 'F'}, {"0NF(1)", 'F'}, - {"0NF(1N", 'F'}, {"0NF(1O", 'F'}, {"0NF(E(", 'F'}, {"0NF(E1", 'F'}, @@ -4247,7 +4464,6 @@ static const keyword_t sql_keywords[] = { {"0NF(ES", 'F'}, {"0NF(EV", 'F'}, {"0NF(F(", 'F'}, - {"0NF(N)", 'F'}, {"0NF(N,", 'F'}, {"0NF(NO", 'F'}, {"0NF(S)", 'F'}, @@ -4257,7 +4473,6 @@ static const keyword_t sql_keywords[] = { {"0NK(1)", 'F'}, {"0NK(1O", 'F'}, {"0NK(F(", 'F'}, - {"0NK(N)", 'F'}, {"0NK(NO", 'F'}, {"0NK(S)", 'F'}, {"0NK(SO", 'F'}, @@ -4284,6 +4499,8 @@ static const keyword_t sql_keywords[] = { {"0NK)EN", 'F'}, {"0NK)ES", 'F'}, {"0NK)EV", 'F'}, + {"0NK)F(", 'F'}, + {"0NK)O(", 'F'}, {"0NK)OF", 'F'}, {"0NK)UE", 'F'}, {"0NK1", 'F'}, @@ -4337,7 +4554,6 @@ static const keyword_t sql_keywords[] = { {"0NKNBN", 'F'}, {"0NKNBS", 'F'}, {"0NKNBV", 'F'}, - {"0NKNC", 'F'}, {"0NKNE(", 'F'}, {"0NKNE1", 'F'}, {"0NKNEF", 'F'}, @@ -4425,6 +4641,7 @@ static const keyword_t sql_keywords[] = { {"0NO(EF", 'F'}, {"0NO(EK", 'F'}, {"0NO(EN", 'F'}, + {"0NO(EO", 'F'}, {"0NO(ES", 'F'}, {"0NO(EV", 'F'}, {"0NO(F(", 'F'}, @@ -4448,11 +4665,6 @@ static const keyword_t sql_keywords[] = { {"0NOF(S", 'F'}, {"0NOF(V", 'F'}, {"0NOK&(", 'F'}, - {"0NOK&1", 'F'}, - {"0NOK&F", 'F'}, - {"0NOK&N", 'F'}, - {"0NOK&S", 'F'}, - {"0NOK&V", 'F'}, {"0NOK(1", 'F'}, {"0NOK(F", 'F'}, {"0NOK(N", 'F'}, @@ -4490,6 +4702,7 @@ static const keyword_t sql_keywords[] = { {"0NOS)B", 'F'}, {"0NOS)C", 'F'}, {"0NOS)E", 'F'}, + {"0NOS)F", 'F'}, {"0NOS)K", 'F'}, {"0NOS)O", 'F'}, {"0NOS)U", 'F'}, @@ -4498,7 +4711,6 @@ static const keyword_t sql_keywords[] = { {"0NOS1(", 'F'}, {"0NOS1F", 'F'}, {"0NOS1N", 'F'}, - {"0NOS1O", 'F'}, {"0NOS1S", 'F'}, {"0NOS1U", 'F'}, {"0NOS1V", 'F'}, @@ -4538,6 +4750,14 @@ static const keyword_t sql_keywords[] = { {"0NOSKS", 'F'}, {"0NOSKU", 'F'}, {"0NOSKV", 'F'}, + {"0NOST(", 'F'}, + {"0NOST1", 'F'}, + {"0NOSTE", 'F'}, + {"0NOSTF", 'F'}, + {"0NOSTN", 'F'}, + {"0NOSTS", 'F'}, + {"0NOSTT", 'F'}, + {"0NOSTV", 'F'}, {"0NOSU", 'F'}, {"0NOSU(", 'F'}, {"0NOSU1", 'F'}, @@ -4546,7 +4766,6 @@ static const keyword_t sql_keywords[] = { {"0NOSUE", 'F'}, {"0NOSUF", 'F'}, {"0NOSUK", 'F'}, - {"0NOSUN", 'F'}, {"0NOSUO", 'F'}, {"0NOSUS", 'F'}, {"0NOSUT", 'F'}, @@ -4576,6 +4795,7 @@ static const keyword_t sql_keywords[] = { {"0NOV)B", 'F'}, {"0NOV)C", 'F'}, {"0NOV)E", 'F'}, + {"0NOV)F", 'F'}, {"0NOV)K", 'F'}, {"0NOV)O", 'F'}, {"0NOV)U", 'F'}, @@ -4629,6 +4849,14 @@ static const keyword_t sql_keywords[] = { {"0NOVSO", 'F'}, {"0NOVSU", 'F'}, {"0NOVSV", 'F'}, + {"0NOVT(", 'F'}, + {"0NOVT1", 'F'}, + {"0NOVTE", 'F'}, + {"0NOVTF", 'F'}, + {"0NOVTN", 'F'}, + {"0NOVTS", 'F'}, + {"0NOVTT", 'F'}, + {"0NOVTV", 'F'}, {"0NOVU", 'F'}, {"0NOVU(", 'F'}, {"0NOVU1", 'F'}, @@ -4637,7 +4865,6 @@ static const keyword_t sql_keywords[] = { {"0NOVUE", 'F'}, {"0NOVUF", 'F'}, {"0NOVUK", 'F'}, - {"0NOVUN", 'F'}, {"0NOVUO", 'F'}, {"0NOVUS", 'F'}, {"0NOVUT", 'F'}, @@ -4650,6 +4877,96 @@ static const keyword_t sql_keywords[] = { {"0NSUE;", 'F'}, {"0NSUEC", 'F'}, {"0NSUEK", 'F'}, + {"0NT(1)", 'F'}, + {"0NT(1O", 'F'}, + {"0NT(F(", 'F'}, + {"0NT(N)", 'F'}, + {"0NT(NO", 'F'}, + {"0NT(S)", 'F'}, + {"0NT(SO", 'F'}, + {"0NT(V)", 'F'}, + {"0NT(VO", 'F'}, + {"0NT1(F", 'F'}, + {"0NT1O(", 'F'}, + {"0NT1OF", 'F'}, + {"0NT1OS", 'F'}, + {"0NT1OV", 'F'}, + {"0NTE(1", 'F'}, + {"0NTE(F", 'F'}, + {"0NTE(N", 'F'}, + {"0NTE(S", 'F'}, + {"0NTE(V", 'F'}, + {"0NTE1N", 'F'}, + {"0NTE1O", 'F'}, + {"0NTEF(", 'F'}, + {"0NTEK(", 'F'}, + {"0NTEK1", 'F'}, + {"0NTEKF", 'F'}, + {"0NTEKN", 'F'}, + {"0NTEKS", 'F'}, + {"0NTEKV", 'F'}, + {"0NTENN", 'F'}, + {"0NTENO", 'F'}, + {"0NTESN", 'F'}, + {"0NTESO", 'F'}, + {"0NTEVN", 'F'}, + {"0NTEVO", 'F'}, + {"0NTF()", 'F'}, + {"0NTF(1", 'F'}, + {"0NTF(F", 'F'}, + {"0NTF(N", 'F'}, + {"0NTF(S", 'F'}, + {"0NTF(V", 'F'}, + {"0NTN(1", 'F'}, + {"0NTN(F", 'F'}, + {"0NTN(S", 'F'}, + {"0NTN(V", 'F'}, + {"0NTN1C", 'F'}, + {"0NTN1O", 'F'}, + {"0NTN;E", 'F'}, + {"0NTN;N", 'F'}, + {"0NTN;T", 'F'}, + {"0NTNE(", 'F'}, + {"0NTNE1", 'F'}, + {"0NTNEF", 'F'}, + {"0NTNEN", 'F'}, + {"0NTNES", 'F'}, + {"0NTNEV", 'F'}, + {"0NTNF(", 'F'}, + {"0NTNKN", 'F'}, + {"0NTNN:", 'F'}, + {"0NTNNC", 'F'}, + {"0NTNNO", 'F'}, + {"0NTNO(", 'F'}, + {"0NTNOF", 'F'}, + {"0NTNOS", 'F'}, + {"0NTNOV", 'F'}, + {"0NTNSC", 'F'}, + {"0NTNSO", 'F'}, + {"0NTNT(", 'F'}, + {"0NTNT1", 'F'}, + {"0NTNTF", 'F'}, + {"0NTNTN", 'F'}, + {"0NTNTS", 'F'}, + {"0NTNTV", 'F'}, + {"0NTNVC", 'F'}, + {"0NTNVO", 'F'}, + {"0NTS(F", 'F'}, + {"0NTSO(", 'F'}, + {"0NTSO1", 'F'}, + {"0NTSOF", 'F'}, + {"0NTSON", 'F'}, + {"0NTSOS", 'F'}, + {"0NTSOV", 'F'}, + {"0NTTNE", 'F'}, + {"0NTTNK", 'F'}, + {"0NTTNN", 'F'}, + {"0NTTNT", 'F'}, + {"0NTV(1", 'F'}, + {"0NTV(F", 'F'}, + {"0NTVO(", 'F'}, + {"0NTVOF", 'F'}, + {"0NTVOS", 'F'}, {"0NU(1)", 'F'}, {"0NU(1O", 'F'}, {"0NU(E(", 'F'}, @@ -4733,7 +5050,6 @@ static const keyword_t sql_keywords[] = { {"0NUENU", 'F'}, {"0NUEOK", 'F'}, {"0NUEON", 'F'}, - {"0NUEOO", 'F'}, {"0NUES", 'F'}, {"0NUES&", 'F'}, {"0NUES(", 'F'}, @@ -4769,30 +5085,6 @@ static const keyword_t sql_keywords[] = { {"0NUF(S", 'F'}, {"0NUF(V", 'F'}, {"0NUK(E", 'F'}, - {"0NUN(1", 'F'}, - {"0NUN(F", 'F'}, - {"0NUN(S", 'F'}, - {"0NUN(V", 'F'}, - {"0NUN,(", 'F'}, - {"0NUN,F", 'F'}, - {"0NUN1(", 'F'}, - {"0NUN1,", 'F'}, - {"0NUN1O", 'F'}, - {"0NUNC", 'F'}, - {"0NUNE(", 'F'}, - {"0NUNE1", 'F'}, - {"0NUNEF", 'F'}, - {"0NUNEN", 'F'}, - {"0NUNES", 'F'}, - {"0NUNEV", 'F'}, - {"0NUNF(", 'F'}, - {"0NUNO(", 'F'}, - {"0NUNOF", 'F'}, - {"0NUNOS", 'F'}, - {"0NUNOV", 'F'}, - {"0NUNS(", 'F'}, - {"0NUNS,", 'F'}, - {"0NUNSO", 'F'}, {"0NUO(E", 'F'}, {"0NUON(", 'F'}, {"0NUON1", 'F'}, @@ -4810,110 +5102,15 @@ static const keyword_t sql_keywords[] = { {"0NUTN(", 'F'}, {"0NUTN1", 'F'}, {"0NUTNF", 'F'}, + {"0NUTNN", 'F'}, {"0NUTNS", 'F'}, + {"0NUTNV", 'F'}, {"0NUV,(", 'F'}, {"0NUV,F", 'F'}, {"0NUVC", 'F'}, {"0NUVO(", 'F'}, {"0NUVOF", 'F'}, {"0NUVOS", 'F'}, - {"0O(1)O", 'F'}, - {"0O(1)U", 'F'}, - {"0O(1O(", 'F'}, - {"0O(1OF", 'F'}, - {"0O(1OS", 'F'}, - {"0O(1OV", 'F'}, - {"0O(F()", 'F'}, - {"0O(F(1", 'F'}, - {"0O(F(F", 'F'}, - {"0O(F(N", 'F'}, - {"0O(F(S", 'F'}, - {"0O(F(V", 'F'}, - {"0O(N)O", 'F'}, - {"0O(N)U", 'F'}, - {"0O(NO(", 'F'}, - {"0O(NOF", 'F'}, - {"0O(NOS", 'F'}, - {"0O(NOV", 'F'}, - {"0O(S)O", 'F'}, - {"0O(S)U", 'F'}, - {"0O(SO(", 'F'}, - {"0O(SO1", 'F'}, - {"0O(SOF", 'F'}, - {"0O(SON", 'F'}, - {"0O(SOS", 'F'}, - {"0O(SOV", 'F'}, - {"0O(V)O", 'F'}, - {"0O(V)U", 'F'}, - {"0O(VO(", 'F'}, - {"0O(VOF", 'F'}, - {"0O(VOS", 'F'}, - {"0O1UE(", 'F'}, - {"0O1UE1", 'F'}, - {"0O1UEF", 'F'}, - {"0O1UEK", 'F'}, - {"0O1UEN", 'F'}, - {"0O1UES", 'F'}, - {"0O1UEV", 'F'}, - {"0OF()O", 'F'}, - {"0OF()U", 'F'}, - {"0OF(1)", 'F'}, - {"0OF(1O", 'F'}, - {"0OF(F(", 'F'}, - {"0OF(N)", 'F'}, - {"0OF(NO", 'F'}, - {"0OF(S)", 'F'}, - {"0OF(SO", 'F'}, - {"0OF(V)", 'F'}, - {"0OF(VO", 'F'}, - {"0ONUE(", 'F'}, - {"0ONUE1", 'F'}, - {"0ONUEF", 'F'}, - {"0ONUEK", 'F'}, - {"0ONUEN", 'F'}, - {"0ONUES", 'F'}, - {"0ONUEV", 'F'}, - {"0OSUE(", 'F'}, - {"0OSUE1", 'F'}, - {"0OSUEF", 'F'}, - {"0OSUEK", 'F'}, - {"0OSUEN", 'F'}, - {"0OSUES", 'F'}, - {"0OSUEV", 'F'}, - {"0OUE(1", 'F'}, - {"0OUE(F", 'F'}, - {"0OUE(N", 'F'}, - {"0OUE(S", 'F'}, - {"0OUE(V", 'F'}, - {"0OUE1,", 'F'}, - {"0OUE1O", 'F'}, - {"0OUEF(", 'F'}, - {"0OUEK(", 'F'}, - {"0OUEK1", 'F'}, - {"0OUEKF", 'F'}, - {"0OUEKN", 'F'}, - {"0OUEKS", 'F'}, - {"0OUEKV", 'F'}, - {"0OUEN,", 'F'}, - {"0OUENO", 'F'}, - {"0OUES,", 'F'}, - {"0OUESO", 'F'}, - {"0OUEV,", 'F'}, - {"0OUEVO", 'F'}, - {"0OVO(1", 'F'}, - {"0OVO(F", 'F'}, - {"0OVO(N", 'F'}, - {"0OVO(S", 'F'}, - {"0OVO(V", 'F'}, - {"0OVOF(", 'F'}, - {"0OVOSU", 'F'}, - {"0OVUE(", 'F'}, - {"0OVUE1", 'F'}, - {"0OVUEF", 'F'}, - {"0OVUEK", 'F'}, - {"0OVUEN", 'F'}, - {"0OVUES", 'F'}, - {"0OVUEV", 'F'}, {"0S&(1&", 'F'}, {"0S&(1)", 'F'}, {"0S&(1,", 'F'}, @@ -4972,7 +5169,6 @@ static const keyword_t sql_keywords[] = { {"0S&1KV", 'F'}, {"0S&1O(", 'F'}, {"0S&1OF", 'F'}, - {"0S&1OO", 'F'}, {"0S&1OS", 'F'}, {"0S&1OV", 'F'}, {"0S&1TN", 'F'}, @@ -5033,6 +5229,7 @@ static const keyword_t sql_keywords[] = { {"0S&K(S", 'F'}, {"0S&K(V", 'F'}, {"0S&K1O", 'F'}, + {"0S&KC", 'F'}, {"0S&KF(", 'F'}, {"0S&KNK", 'F'}, {"0S&KO(", 'F'}, @@ -5098,7 +5295,6 @@ static const keyword_t sql_keywords[] = { {"0S&S1", 'F'}, {"0S&S1;", 'F'}, {"0S&S1C", 'F'}, - {"0S&S1O", 'F'}, {"0S&S;", 'F'}, {"0S&S;C", 'F'}, {"0S&S;E", 'F'}, @@ -5123,7 +5319,6 @@ static const keyword_t sql_keywords[] = { {"0S&SO1", 'F'}, {"0S&SOF", 'F'}, {"0S&SON", 'F'}, - {"0S&SOO", 'F'}, {"0S&SOS", 'F'}, {"0S&SOV", 'F'}, {"0S&STN", 'F'}, @@ -5169,7 +5364,6 @@ static const keyword_t sql_keywords[] = { {"0S&VKV", 'F'}, {"0S&VO(", 'F'}, {"0S&VOF", 'F'}, - {"0S&VOO", 'F'}, {"0S&VOS", 'F'}, {"0S&VS", 'F'}, {"0S&VS;", 'F'}, @@ -5306,6 +5500,7 @@ static const keyword_t sql_keywords[] = { {"0S)ESO", 'F'}, {"0S)EVC", 'F'}, {"0S)EVO", 'F'}, + {"0S)F(F", 'F'}, {"0S)K(1", 'F'}, {"0S)K(F", 'F'}, {"0S)K(N", 'F'}, @@ -5327,6 +5522,7 @@ static const keyword_t sql_keywords[] = { {"0S)KN&", 'F'}, {"0S)KN;", 'F'}, {"0S)KNB", 'F'}, + {"0S)KNC", 'F'}, {"0S)KNE", 'F'}, {"0S)KNK", 'F'}, {"0S)KNU", 'F'}, @@ -5419,22 +5615,6 @@ static const keyword_t sql_keywords[] = { {"0S1F(S", 'F'}, {"0S1F(V", 'F'}, {"0S1NC", 'F'}, - {"0S1O(1", 'F'}, - {"0S1O(F", 'F'}, - {"0S1O(N", 'F'}, - {"0S1O(S", 'F'}, - {"0S1O(V", 'F'}, - {"0S1OF(", 'F'}, - {"0S1OS(", 'F'}, - {"0S1OS1", 'F'}, - {"0S1OSF", 'F'}, - {"0S1OSU", 'F'}, - {"0S1OSV", 'F'}, - {"0S1OV(", 'F'}, - {"0S1OVF", 'F'}, - {"0S1OVO", 'F'}, - {"0S1OVS", 'F'}, - {"0S1OVU", 'F'}, {"0S1S;", 'F'}, {"0S1S;C", 'F'}, {"0S1SC", 'F'}, @@ -5490,11 +5670,13 @@ static const keyword_t sql_keywords[] = { {"0S;EVT", 'F'}, {"0S;N:T", 'F'}, {"0S;T(1", 'F'}, + {"0S;T(C", 'F'}, {"0S;T(E", 'F'}, {"0S;T(F", 'F'}, {"0S;T(N", 'F'}, {"0S;T(S", 'F'}, {"0S;T(V", 'F'}, + {"0S;T1(", 'F'}, {"0S;T1,", 'F'}, {"0S;T1;", 'F'}, {"0S;T1C", 'F'}, @@ -5527,6 +5709,7 @@ static const keyword_t sql_keywords[] = { {"0S;TNT", 'F'}, {"0S;TNV", 'F'}, {"0S;TO(", 'F'}, + {"0S;TS(", 'F'}, {"0S;TS,", 'F'}, {"0S;TS;", 'F'}, {"0S;TSC", 'F'}, @@ -5534,12 +5717,8 @@ static const keyword_t sql_keywords[] = { {"0S;TSK", 'F'}, {"0S;TSO", 'F'}, {"0S;TST", 'F'}, - {"0S;TT(", 'F'}, - {"0S;TT1", 'F'}, - {"0S;TTF", 'F'}, {"0S;TTN", 'F'}, - {"0S;TTS", 'F'}, - {"0S;TTV", 'F'}, + {"0S;TV(", 'F'}, {"0S;TV,", 'F'}, {"0S;TV;", 'F'}, {"0S;TVC", 'F'}, @@ -5581,7 +5760,6 @@ static const keyword_t sql_keywords[] = { {"0SB(1)", 'F'}, {"0SB(1O", 'F'}, {"0SB(F(", 'F'}, - {"0SB(N)", 'F'}, {"0SB(NO", 'F'}, {"0SB(S)", 'F'}, {"0SB(SO", 'F'}, @@ -5730,11 +5908,18 @@ static const keyword_t sql_keywords[] = { {"0SE(SO", 'F'}, {"0SE(V)", 'F'}, {"0SE(VO", 'F'}, + {"0SE1;T", 'F'}, {"0SE1C", 'F'}, {"0SE1O(", 'F'}, {"0SE1OF", 'F'}, {"0SE1OS", 'F'}, {"0SE1OV", 'F'}, + {"0SE1T(", 'F'}, + {"0SE1T1", 'F'}, + {"0SE1TF", 'F'}, + {"0SE1TN", 'F'}, + {"0SE1TS", 'F'}, + {"0SE1TV", 'F'}, {"0SE1UE", 'F'}, {"0SEF()", 'F'}, {"0SEF(1", 'F'}, @@ -5748,35 +5933,50 @@ static const keyword_t sql_keywords[] = { {"0SEK(N", 'F'}, {"0SEK(S", 'F'}, {"0SEK(V", 'F'}, + {"0SEK1;", 'F'}, {"0SEK1C", 'F'}, {"0SEK1O", 'F'}, + {"0SEK1T", 'F'}, {"0SEK1U", 'F'}, {"0SEKF(", 'F'}, + {"0SEKN;", 'F'}, {"0SEKNC", 'F'}, {"0SEKNE", 'F'}, + {"0SEKNT", 'F'}, {"0SEKNU", 'F'}, {"0SEKOK", 'F'}, + {"0SEKS;", 'F'}, {"0SEKSC", 'F'}, {"0SEKSO", 'F'}, + {"0SEKST", 'F'}, {"0SEKSU", 'F'}, {"0SEKU(", 'F'}, {"0SEKU1", 'F'}, {"0SEKUE", 'F'}, {"0SEKUF", 'F'}, - {"0SEKUN", 'F'}, {"0SEKUS", 'F'}, {"0SEKUV", 'F'}, + {"0SEKV;", 'F'}, {"0SEKVC", 'F'}, {"0SEKVO", 'F'}, + {"0SEKVT", 'F'}, {"0SEKVU", 'F'}, + {"0SEN;T", 'F'}, {"0SENC", 'F'}, {"0SENEN", 'F'}, {"0SENO(", 'F'}, {"0SENOF", 'F'}, {"0SENOS", 'F'}, {"0SENOV", 'F'}, + {"0SENT(", 'F'}, + {"0SENT1", 'F'}, + {"0SENTF", 'F'}, + {"0SENTN", 'F'}, + {"0SENTS", 'F'}, + {"0SENTV", 'F'}, {"0SENUE", 'F'}, {"0SEOKN", 'F'}, + {"0SES;T", 'F'}, {"0SESC", 'F'}, {"0SESO(", 'F'}, {"0SESO1", 'F'}, @@ -5784,6 +5984,12 @@ static const keyword_t sql_keywords[] = { {"0SESON", 'F'}, {"0SESOS", 'F'}, {"0SESOV", 'F'}, + {"0SEST(", 'F'}, + {"0SEST1", 'F'}, + {"0SESTF", 'F'}, + {"0SESTN", 'F'}, + {"0SESTS", 'F'}, + {"0SESTV", 'F'}, {"0SESUE", 'F'}, {"0SEU(1", 'F'}, {"0SEU(F", 'F'}, @@ -5796,19 +6002,23 @@ static const keyword_t sql_keywords[] = { {"0SEUEF", 'F'}, {"0SEUEK", 'F'}, {"0SEUF(", 'F'}, - {"0SEUN,", 'F'}, - {"0SEUNC", 'F'}, - {"0SEUNO", 'F'}, {"0SEUS,", 'F'}, {"0SEUSC", 'F'}, {"0SEUSO", 'F'}, {"0SEUV,", 'F'}, {"0SEUVC", 'F'}, {"0SEUVO", 'F'}, + {"0SEV;T", 'F'}, {"0SEVC", 'F'}, {"0SEVO(", 'F'}, {"0SEVOF", 'F'}, {"0SEVOS", 'F'}, + {"0SEVT(", 'F'}, + {"0SEVT1", 'F'}, + {"0SEVTF", 'F'}, + {"0SEVTN", 'F'}, + {"0SEVTS", 'F'}, + {"0SEVTV", 'F'}, {"0SEVUE", 'F'}, {"0SF()1", 'F'}, {"0SF()F", 'F'}, @@ -5866,6 +6076,8 @@ static const keyword_t sql_keywords[] = { {"0SK)EN", 'F'}, {"0SK)ES", 'F'}, {"0SK)EV", 'F'}, + {"0SK)F(", 'F'}, + {"0SK)O(", 'F'}, {"0SK)OF", 'F'}, {"0SK)UE", 'F'}, {"0SK1", 'F'}, @@ -6011,6 +6223,7 @@ static const keyword_t sql_keywords[] = { {"0SO(EF", 'F'}, {"0SO(EK", 'F'}, {"0SO(EN", 'F'}, + {"0SO(EO", 'F'}, {"0SO(ES", 'F'}, {"0SO(EV", 'F'}, {"0SO(F(", 'F'}, @@ -6043,6 +6256,7 @@ static const keyword_t sql_keywords[] = { {"0SO1)B", 'F'}, {"0SO1)C", 'F'}, {"0SO1)E", 'F'}, + {"0SO1)F", 'F'}, {"0SO1)K", 'F'}, {"0SO1)O", 'F'}, {"0SO1)U", 'F'}, @@ -6089,12 +6303,17 @@ static const keyword_t sql_keywords[] = { {"0SO1N(", 'F'}, {"0SO1N,", 'F'}, {"0SO1NE", 'F'}, - {"0SO1NF", 'F'}, {"0SO1NU", 'F'}, - {"0SO1S(", 'F'}, - {"0SO1SF", 'F'}, {"0SO1SU", 'F'}, {"0SO1SV", 'F'}, + {"0SO1T(", 'F'}, + {"0SO1T1", 'F'}, + {"0SO1TE", 'F'}, + {"0SO1TF", 'F'}, + {"0SO1TN", 'F'}, + {"0SO1TS", 'F'}, + {"0SO1TT", 'F'}, + {"0SO1TV", 'F'}, {"0SO1U", 'F'}, {"0SO1U(", 'F'}, {"0SO1U1", 'F'}, @@ -6103,7 +6322,6 @@ static const keyword_t sql_keywords[] = { {"0SO1UE", 'F'}, {"0SO1UF", 'F'}, {"0SO1UK", 'F'}, - {"0SO1UN", 'F'}, {"0SO1UO", 'F'}, {"0SO1US", 'F'}, {"0SO1UT", 'F'}, @@ -6166,16 +6384,14 @@ static const keyword_t sql_keywords[] = { {"0SON)B", 'F'}, {"0SON)C", 'F'}, {"0SON)E", 'F'}, + {"0SON)F", 'F'}, {"0SON)K", 'F'}, {"0SON)O", 'F'}, {"0SON)U", 'F'}, {"0SON,(", 'F'}, {"0SON,F", 'F'}, {"0SON1(", 'F'}, - {"0SON1F", 'F'}, - {"0SON1N", 'F'}, {"0SON1O", 'F'}, - {"0SON1S", 'F'}, {"0SON1U", 'F'}, {"0SON1V", 'F'}, {"0SON;", 'F'}, @@ -6213,6 +6429,14 @@ static const keyword_t sql_keywords[] = { {"0SONKU", 'F'}, {"0SONKV", 'F'}, {"0SONSU", 'F'}, + {"0SONT(", 'F'}, + {"0SONT1", 'F'}, + {"0SONTE", 'F'}, + {"0SONTF", 'F'}, + {"0SONTN", 'F'}, + {"0SONTS", 'F'}, + {"0SONTT", 'F'}, + {"0SONTV", 'F'}, {"0SONU", 'F'}, {"0SONU(", 'F'}, {"0SONU1", 'F'}, @@ -6221,7 +6445,6 @@ static const keyword_t sql_keywords[] = { {"0SONUE", 'F'}, {"0SONUF", 'F'}, {"0SONUK", 'F'}, - {"0SONUN", 'F'}, {"0SONUO", 'F'}, {"0SONUS", 'F'}, {"0SONUT", 'F'}, @@ -6244,6 +6467,7 @@ static const keyword_t sql_keywords[] = { {"0SOS)B", 'F'}, {"0SOS)C", 'F'}, {"0SOS)E", 'F'}, + {"0SOS)F", 'F'}, {"0SOS)K", 'F'}, {"0SOS)O", 'F'}, {"0SOS)U", 'F'}, @@ -6252,7 +6476,6 @@ static const keyword_t sql_keywords[] = { {"0SOS1(", 'F'}, {"0SOS1F", 'F'}, {"0SOS1N", 'F'}, - {"0SOS1O", 'F'}, {"0SOS1S", 'F'}, {"0SOS1U", 'F'}, {"0SOS1V", 'F'}, @@ -6293,6 +6516,14 @@ static const keyword_t sql_keywords[] = { {"0SOSKS", 'F'}, {"0SOSKU", 'F'}, {"0SOSKV", 'F'}, + {"0SOST(", 'F'}, + {"0SOST1", 'F'}, + {"0SOSTE", 'F'}, + {"0SOSTF", 'F'}, + {"0SOSTN", 'F'}, + {"0SOSTS", 'F'}, + {"0SOSTT", 'F'}, + {"0SOSTV", 'F'}, {"0SOSU", 'F'}, {"0SOSU(", 'F'}, {"0SOSU1", 'F'}, @@ -6301,7 +6532,6 @@ static const keyword_t sql_keywords[] = { {"0SOSUE", 'F'}, {"0SOSUF", 'F'}, {"0SOSUK", 'F'}, - {"0SOSUN", 'F'}, {"0SOSUO", 'F'}, {"0SOSUS", 'F'}, {"0SOSUT", 'F'}, @@ -6332,6 +6562,7 @@ static const keyword_t sql_keywords[] = { {"0SOV)B", 'F'}, {"0SOV)C", 'F'}, {"0SOV)E", 'F'}, + {"0SOV)F", 'F'}, {"0SOV)K", 'F'}, {"0SOV)O", 'F'}, {"0SOV)U", 'F'}, @@ -6385,6 +6616,14 @@ static const keyword_t sql_keywords[] = { {"0SOVSO", 'F'}, {"0SOVSU", 'F'}, {"0SOVSV", 'F'}, + {"0SOVT(", 'F'}, + {"0SOVT1", 'F'}, + {"0SOVTE", 'F'}, + {"0SOVTF", 'F'}, + {"0SOVTN", 'F'}, + {"0SOVTS", 'F'}, + {"0SOVTT", 'F'}, + {"0SOVTV", 'F'}, {"0SOVU", 'F'}, {"0SOVU(", 'F'}, {"0SOVU1", 'F'}, @@ -6393,11 +6632,100 @@ static const keyword_t sql_keywords[] = { {"0SOVUE", 'F'}, {"0SOVUF", 'F'}, {"0SOVUK", 'F'}, - {"0SOVUN", 'F'}, {"0SOVUO", 'F'}, {"0SOVUS", 'F'}, {"0SOVUT", 'F'}, {"0SOVUV", 'F'}, + {"0ST(1)", 'F'}, + {"0ST(1O", 'F'}, + {"0ST(F(", 'F'}, + {"0ST(N)", 'F'}, + {"0ST(NO", 'F'}, + {"0ST(S)", 'F'}, + {"0ST(SO", 'F'}, + {"0ST(V)", 'F'}, + {"0ST(VO", 'F'}, + {"0ST1(F", 'F'}, + {"0ST1O(", 'F'}, + {"0ST1OF", 'F'}, + {"0ST1OS", 'F'}, + {"0ST1OV", 'F'}, + {"0STE(1", 'F'}, + {"0STE(F", 'F'}, + {"0STE(N", 'F'}, + {"0STE(S", 'F'}, + {"0STE(V", 'F'}, + {"0STE1N", 'F'}, + {"0STE1O", 'F'}, + {"0STEF(", 'F'}, + {"0STEK(", 'F'}, + {"0STEK1", 'F'}, + {"0STEKF", 'F'}, + {"0STEKN", 'F'}, + {"0STEKS", 'F'}, + {"0STEKV", 'F'}, + {"0STENN", 'F'}, + {"0STENO", 'F'}, + {"0STESN", 'F'}, + {"0STESO", 'F'}, + {"0STEVN", 'F'}, + {"0STEVO", 'F'}, + {"0STF()", 'F'}, + {"0STF(1", 'F'}, + {"0STF(F", 'F'}, + {"0STF(N", 'F'}, + {"0STF(S", 'F'}, + {"0STF(V", 'F'}, + {"0STN(1", 'F'}, + {"0STN(F", 'F'}, + {"0STN(S", 'F'}, + {"0STN(V", 'F'}, + {"0STN1C", 'F'}, + {"0STN1O", 'F'}, + {"0STN;E", 'F'}, + {"0STN;N", 'F'}, + {"0STN;T", 'F'}, + {"0STNE(", 'F'}, + {"0STNE1", 'F'}, + {"0STNEF", 'F'}, + {"0STNEN", 'F'}, + {"0STNES", 'F'}, + {"0STNEV", 'F'}, + {"0STNF(", 'F'}, + {"0STNKN", 'F'}, + {"0STNN:", 'F'}, + {"0STNNC", 'F'}, + {"0STNNO", 'F'}, + {"0STNO(", 'F'}, + {"0STNOF", 'F'}, + {"0STNOS", 'F'}, + {"0STNOV", 'F'}, + {"0STNSC", 'F'}, + {"0STNSO", 'F'}, + {"0STNT(", 'F'}, + {"0STNT1", 'F'}, + {"0STNTF", 'F'}, + {"0STNTN", 'F'}, + {"0STNTS", 'F'}, + {"0STNTV", 'F'}, + {"0STNVC", 'F'}, + {"0STNVO", 'F'}, + {"0STS(F", 'F'}, + {"0STSO(", 'F'}, + {"0STSO1", 'F'}, + {"0STSOF", 'F'}, + {"0STSON", 'F'}, + {"0STSOS", 'F'}, + {"0STSOV", 'F'}, + {"0STTNE", 'F'}, + {"0STTNK", 'F'}, + {"0STTNN", 'F'}, + {"0STTNT", 'F'}, + {"0STV(1", 'F'}, + {"0STV(F", 'F'}, + {"0STVO(", 'F'}, + {"0STVOF", 'F'}, + {"0STVOS", 'F'}, {"0SU(1)", 'F'}, {"0SU(1O", 'F'}, {"0SU(E(", 'F'}, @@ -6481,7 +6809,6 @@ static const keyword_t sql_keywords[] = { {"0SUENU", 'F'}, {"0SUEOK", 'F'}, {"0SUEON", 'F'}, - {"0SUEOO", 'F'}, {"0SUES", 'F'}, {"0SUES&", 'F'}, {"0SUES(", 'F'}, @@ -6517,30 +6844,6 @@ static const keyword_t sql_keywords[] = { {"0SUF(S", 'F'}, {"0SUF(V", 'F'}, {"0SUK(E", 'F'}, - {"0SUN(1", 'F'}, - {"0SUN(F", 'F'}, - {"0SUN(S", 'F'}, - {"0SUN(V", 'F'}, - {"0SUN,(", 'F'}, - {"0SUN,F", 'F'}, - {"0SUN1(", 'F'}, - {"0SUN1,", 'F'}, - {"0SUN1O", 'F'}, - {"0SUNC", 'F'}, - {"0SUNE(", 'F'}, - {"0SUNE1", 'F'}, - {"0SUNEF", 'F'}, - {"0SUNEN", 'F'}, - {"0SUNES", 'F'}, - {"0SUNEV", 'F'}, - {"0SUNF(", 'F'}, - {"0SUNO(", 'F'}, - {"0SUNOF", 'F'}, - {"0SUNOS", 'F'}, - {"0SUNOV", 'F'}, - {"0SUNS(", 'F'}, - {"0SUNS,", 'F'}, - {"0SUNSO", 'F'}, {"0SUO(E", 'F'}, {"0SUON(", 'F'}, {"0SUON1", 'F'}, @@ -6558,7 +6861,9 @@ static const keyword_t sql_keywords[] = { {"0SUTN(", 'F'}, {"0SUTN1", 'F'}, {"0SUTNF", 'F'}, + {"0SUTNN", 'F'}, {"0SUTNS", 'F'}, + {"0SUTNV", 'F'}, {"0SUV,(", 'F'}, {"0SUV,F", 'F'}, {"0SUVC", 'F'}, @@ -6582,7 +6887,6 @@ static const keyword_t sql_keywords[] = { {"0SVOSF", 'F'}, {"0SVOSU", 'F'}, {"0SVOSV", 'F'}, - {"0SVS", 'F'}, {"0SVS;", 'F'}, {"0SVS;C", 'F'}, {"0SVSC", 'F'}, @@ -6622,16 +6926,19 @@ static const keyword_t sql_keywords[] = { {"0T(N1)", 'F'}, {"0T(N1O", 'F'}, {"0T(NF(", 'F'}, + {"0T(NN)", 'F'}, + {"0T(NNO", 'F'}, {"0T(NO(", 'F'}, {"0T(NOF", 'F'}, {"0T(NOS", 'F'}, {"0T(NOV", 'F'}, {"0T(NS)", 'F'}, {"0T(NSO", 'F'}, + {"0T(NV)", 'F'}, + {"0T(NVO", 'F'}, {"0T(S)F", 'F'}, {"0T(S)O", 'F'}, {"0T(S1)", 'F'}, - {"0T(S1O", 'F'}, {"0T(SF(", 'F'}, {"0T(SN)", 'F'}, {"0T(SNO", 'F'}, @@ -6696,6 +7003,12 @@ static const keyword_t sql_keywords[] = { {"0TNF(N", 'F'}, {"0TNF(S", 'F'}, {"0TNF(V", 'F'}, + {"0TNN;", 'F'}, + {"0TNN;C", 'F'}, + {"0TNNO(", 'F'}, + {"0TNNOF", 'F'}, + {"0TNNOS", 'F'}, + {"0TNNOV", 'F'}, {"0TNO(1", 'F'}, {"0TNO(F", 'F'}, {"0TNO(N", 'F'}, @@ -6714,6 +7027,9 @@ static const keyword_t sql_keywords[] = { {"0TNSOS", 'F'}, {"0TNSOV", 'F'}, {"0TNV;", 'F'}, + {"0TNV;C", 'F'}, + {"0TNVO(", 'F'}, + {"0TNVOF", 'F'}, {"0TNVOS", 'F'}, {"0TSF(1", 'F'}, {"0TSF(F", 'F'}, @@ -6944,7 +7260,6 @@ static const keyword_t sql_keywords[] = { {"0V&1KV", 'F'}, {"0V&1O(", 'F'}, {"0V&1OF", 'F'}, - {"0V&1OO", 'F'}, {"0V&1OS", 'F'}, {"0V&1OV", 'F'}, {"0V&1TN", 'F'}, @@ -7005,6 +7320,7 @@ static const keyword_t sql_keywords[] = { {"0V&K(S", 'F'}, {"0V&K(V", 'F'}, {"0V&K1O", 'F'}, + {"0V&KC", 'F'}, {"0V&KF(", 'F'}, {"0V&KNK", 'F'}, {"0V&KO(", 'F'}, @@ -7070,7 +7386,6 @@ static const keyword_t sql_keywords[] = { {"0V&S1", 'F'}, {"0V&S1;", 'F'}, {"0V&S1C", 'F'}, - {"0V&S1O", 'F'}, {"0V&S;", 'F'}, {"0V&S;C", 'F'}, {"0V&S;E", 'F'}, @@ -7095,7 +7410,6 @@ static const keyword_t sql_keywords[] = { {"0V&SO1", 'F'}, {"0V&SOF", 'F'}, {"0V&SON", 'F'}, - {"0V&SOO", 'F'}, {"0V&SOS", 'F'}, {"0V&SOV", 'F'}, {"0V&STN", 'F'}, @@ -7141,7 +7455,6 @@ static const keyword_t sql_keywords[] = { {"0V&VKV", 'F'}, {"0V&VO(", 'F'}, {"0V&VOF", 'F'}, - {"0V&VOO", 'F'}, {"0V&VOS", 'F'}, {"0V&VS", 'F'}, {"0V&VS;", 'F'}, @@ -7278,6 +7591,7 @@ static const keyword_t sql_keywords[] = { {"0V)ESO", 'F'}, {"0V)EVC", 'F'}, {"0V)EVO", 'F'}, + {"0V)F(F", 'F'}, {"0V)K(1", 'F'}, {"0V)K(F", 'F'}, {"0V)K(N", 'F'}, @@ -7299,6 +7613,7 @@ static const keyword_t sql_keywords[] = { {"0V)KN&", 'F'}, {"0V)KN;", 'F'}, {"0V)KNB", 'F'}, + {"0V)KNC", 'F'}, {"0V)KNE", 'F'}, {"0V)KNK", 'F'}, {"0V)KNU", 'F'}, @@ -7426,11 +7741,13 @@ static const keyword_t sql_keywords[] = { {"0V;EVT", 'F'}, {"0V;N:T", 'F'}, {"0V;T(1", 'F'}, + {"0V;T(C", 'F'}, {"0V;T(E", 'F'}, {"0V;T(F", 'F'}, {"0V;T(N", 'F'}, {"0V;T(S", 'F'}, {"0V;T(V", 'F'}, + {"0V;T1(", 'F'}, {"0V;T1,", 'F'}, {"0V;T1;", 'F'}, {"0V;T1C", 'F'}, @@ -7463,6 +7780,7 @@ static const keyword_t sql_keywords[] = { {"0V;TNT", 'F'}, {"0V;TNV", 'F'}, {"0V;TO(", 'F'}, + {"0V;TS(", 'F'}, {"0V;TS,", 'F'}, {"0V;TS;", 'F'}, {"0V;TSC", 'F'}, @@ -7470,12 +7788,8 @@ static const keyword_t sql_keywords[] = { {"0V;TSK", 'F'}, {"0V;TSO", 'F'}, {"0V;TST", 'F'}, - {"0V;TT(", 'F'}, - {"0V;TT1", 'F'}, - {"0V;TTF", 'F'}, {"0V;TTN", 'F'}, - {"0V;TTS", 'F'}, - {"0V;TTV", 'F'}, + {"0V;TV(", 'F'}, {"0V;TV,", 'F'}, {"0V;TV;", 'F'}, {"0V;TVC", 'F'}, @@ -7517,7 +7831,6 @@ static const keyword_t sql_keywords[] = { {"0VB(1)", 'F'}, {"0VB(1O", 'F'}, {"0VB(F(", 'F'}, - {"0VB(N)", 'F'}, {"0VB(NO", 'F'}, {"0VB(S)", 'F'}, {"0VB(SO", 'F'}, @@ -7666,11 +7979,18 @@ static const keyword_t sql_keywords[] = { {"0VE(SO", 'F'}, {"0VE(V)", 'F'}, {"0VE(VO", 'F'}, + {"0VE1;T", 'F'}, {"0VE1C", 'F'}, {"0VE1O(", 'F'}, {"0VE1OF", 'F'}, {"0VE1OS", 'F'}, {"0VE1OV", 'F'}, + {"0VE1T(", 'F'}, + {"0VE1T1", 'F'}, + {"0VE1TF", 'F'}, + {"0VE1TN", 'F'}, + {"0VE1TS", 'F'}, + {"0VE1TV", 'F'}, {"0VE1UE", 'F'}, {"0VEF()", 'F'}, {"0VEF(1", 'F'}, @@ -7684,35 +8004,50 @@ static const keyword_t sql_keywords[] = { {"0VEK(N", 'F'}, {"0VEK(S", 'F'}, {"0VEK(V", 'F'}, + {"0VEK1;", 'F'}, {"0VEK1C", 'F'}, {"0VEK1O", 'F'}, + {"0VEK1T", 'F'}, {"0VEK1U", 'F'}, {"0VEKF(", 'F'}, + {"0VEKN;", 'F'}, {"0VEKNC", 'F'}, {"0VEKNE", 'F'}, + {"0VEKNT", 'F'}, {"0VEKNU", 'F'}, {"0VEKOK", 'F'}, + {"0VEKS;", 'F'}, {"0VEKSC", 'F'}, {"0VEKSO", 'F'}, + {"0VEKST", 'F'}, {"0VEKSU", 'F'}, {"0VEKU(", 'F'}, {"0VEKU1", 'F'}, {"0VEKUE", 'F'}, {"0VEKUF", 'F'}, - {"0VEKUN", 'F'}, {"0VEKUS", 'F'}, {"0VEKUV", 'F'}, + {"0VEKV;", 'F'}, {"0VEKVC", 'F'}, {"0VEKVO", 'F'}, + {"0VEKVT", 'F'}, {"0VEKVU", 'F'}, + {"0VEN;T", 'F'}, {"0VENC", 'F'}, {"0VENEN", 'F'}, {"0VENO(", 'F'}, {"0VENOF", 'F'}, {"0VENOS", 'F'}, {"0VENOV", 'F'}, + {"0VENT(", 'F'}, + {"0VENT1", 'F'}, + {"0VENTF", 'F'}, + {"0VENTN", 'F'}, + {"0VENTS", 'F'}, + {"0VENTV", 'F'}, {"0VENUE", 'F'}, {"0VEOKN", 'F'}, + {"0VES;T", 'F'}, {"0VESC", 'F'}, {"0VESO(", 'F'}, {"0VESO1", 'F'}, @@ -7720,6 +8055,12 @@ static const keyword_t sql_keywords[] = { {"0VESON", 'F'}, {"0VESOS", 'F'}, {"0VESOV", 'F'}, + {"0VEST(", 'F'}, + {"0VEST1", 'F'}, + {"0VESTF", 'F'}, + {"0VESTN", 'F'}, + {"0VESTS", 'F'}, + {"0VESTV", 'F'}, {"0VESUE", 'F'}, {"0VEU(1", 'F'}, {"0VEU(F", 'F'}, @@ -7732,19 +8073,23 @@ static const keyword_t sql_keywords[] = { {"0VEUEF", 'F'}, {"0VEUEK", 'F'}, {"0VEUF(", 'F'}, - {"0VEUN,", 'F'}, - {"0VEUNC", 'F'}, - {"0VEUNO", 'F'}, {"0VEUS,", 'F'}, {"0VEUSC", 'F'}, {"0VEUSO", 'F'}, {"0VEUV,", 'F'}, {"0VEUVC", 'F'}, {"0VEUVO", 'F'}, + {"0VEV;T", 'F'}, {"0VEVC", 'F'}, {"0VEVO(", 'F'}, {"0VEVOF", 'F'}, {"0VEVOS", 'F'}, + {"0VEVT(", 'F'}, + {"0VEVT1", 'F'}, + {"0VEVTF", 'F'}, + {"0VEVTN", 'F'}, + {"0VEVTS", 'F'}, + {"0VEVTV", 'F'}, {"0VEVUE", 'F'}, {"0VF()1", 'F'}, {"0VF()F", 'F'}, @@ -7802,6 +8147,8 @@ static const keyword_t sql_keywords[] = { {"0VK)EN", 'F'}, {"0VK)ES", 'F'}, {"0VK)EV", 'F'}, + {"0VK)F(", 'F'}, + {"0VK)O(", 'F'}, {"0VK)OF", 'F'}, {"0VK)UE", 'F'}, {"0VK1", 'F'}, @@ -7947,6 +8294,7 @@ static const keyword_t sql_keywords[] = { {"0VO(EF", 'F'}, {"0VO(EK", 'F'}, {"0VO(EN", 'F'}, + {"0VO(EO", 'F'}, {"0VO(ES", 'F'}, {"0VO(EV", 'F'}, {"0VO(F(", 'F'}, @@ -8012,6 +8360,7 @@ static const keyword_t sql_keywords[] = { {"0VOS)B", 'F'}, {"0VOS)C", 'F'}, {"0VOS)E", 'F'}, + {"0VOS)F", 'F'}, {"0VOS)K", 'F'}, {"0VOS)O", 'F'}, {"0VOS)U", 'F'}, @@ -8020,7 +8369,6 @@ static const keyword_t sql_keywords[] = { {"0VOS1(", 'F'}, {"0VOS1F", 'F'}, {"0VOS1N", 'F'}, - {"0VOS1O", 'F'}, {"0VOS1S", 'F'}, {"0VOS1U", 'F'}, {"0VOS1V", 'F'}, @@ -8061,6 +8409,14 @@ static const keyword_t sql_keywords[] = { {"0VOSKS", 'F'}, {"0VOSKU", 'F'}, {"0VOSKV", 'F'}, + {"0VOST(", 'F'}, + {"0VOST1", 'F'}, + {"0VOSTE", 'F'}, + {"0VOSTF", 'F'}, + {"0VOSTN", 'F'}, + {"0VOSTS", 'F'}, + {"0VOSTT", 'F'}, + {"0VOSTV", 'F'}, {"0VOSU", 'F'}, {"0VOSU(", 'F'}, {"0VOSU1", 'F'}, @@ -8069,7 +8425,6 @@ static const keyword_t sql_keywords[] = { {"0VOSUE", 'F'}, {"0VOSUF", 'F'}, {"0VOSUK", 'F'}, - {"0VOSUN", 'F'}, {"0VOSUO", 'F'}, {"0VOSUS", 'F'}, {"0VOSUT", 'F'}, @@ -8082,6 +8437,96 @@ static const keyword_t sql_keywords[] = { {"0VOU(E", 'F'}, {"0VOUEK", 'F'}, {"0VOUEN", 'F'}, + {"0VT(1)", 'F'}, + {"0VT(1O", 'F'}, + {"0VT(F(", 'F'}, + {"0VT(N)", 'F'}, + {"0VT(NO", 'F'}, + {"0VT(S)", 'F'}, + {"0VT(SO", 'F'}, + {"0VT(V)", 'F'}, + {"0VT(VO", 'F'}, + {"0VT1(F", 'F'}, + {"0VT1O(", 'F'}, + {"0VT1OF", 'F'}, + {"0VT1OS", 'F'}, + {"0VT1OV", 'F'}, + {"0VTE(1", 'F'}, + {"0VTE(F", 'F'}, + {"0VTE(N", 'F'}, + {"0VTE(S", 'F'}, + {"0VTE(V", 'F'}, + {"0VTE1N", 'F'}, + {"0VTE1O", 'F'}, + {"0VTEF(", 'F'}, + {"0VTEK(", 'F'}, + {"0VTEK1", 'F'}, + {"0VTEKF", 'F'}, + {"0VTEKN", 'F'}, + {"0VTEKS", 'F'}, + {"0VTEKV", 'F'}, + {"0VTENN", 'F'}, + {"0VTENO", 'F'}, + {"0VTESN", 'F'}, + {"0VTESO", 'F'}, + {"0VTEVN", 'F'}, + {"0VTEVO", 'F'}, + {"0VTF()", 'F'}, + {"0VTF(1", 'F'}, + {"0VTF(F", 'F'}, + {"0VTF(N", 'F'}, + {"0VTF(S", 'F'}, + {"0VTF(V", 'F'}, + {"0VTN(1", 'F'}, + {"0VTN(F", 'F'}, + {"0VTN(S", 'F'}, + {"0VTN(V", 'F'}, + {"0VTN1C", 'F'}, + {"0VTN1O", 'F'}, + {"0VTN;E", 'F'}, + {"0VTN;N", 'F'}, + {"0VTN;T", 'F'}, + {"0VTNE(", 'F'}, + {"0VTNE1", 'F'}, + {"0VTNEF", 'F'}, + {"0VTNEN", 'F'}, + {"0VTNES", 'F'}, + {"0VTNEV", 'F'}, + {"0VTNF(", 'F'}, + {"0VTNKN", 'F'}, + {"0VTNN:", 'F'}, + {"0VTNNC", 'F'}, + {"0VTNNO", 'F'}, + {"0VTNO(", 'F'}, + {"0VTNOF", 'F'}, + {"0VTNOS", 'F'}, + {"0VTNOV", 'F'}, + {"0VTNSC", 'F'}, + {"0VTNSO", 'F'}, + {"0VTNT(", 'F'}, + {"0VTNT1", 'F'}, + {"0VTNTF", 'F'}, + {"0VTNTN", 'F'}, + {"0VTNTS", 'F'}, + {"0VTNTV", 'F'}, + {"0VTNVC", 'F'}, + {"0VTNVO", 'F'}, + {"0VTS(F", 'F'}, + {"0VTSO(", 'F'}, + {"0VTSO1", 'F'}, + {"0VTSOF", 'F'}, + {"0VTSON", 'F'}, + {"0VTSOS", 'F'}, + {"0VTSOV", 'F'}, + {"0VTTNE", 'F'}, + {"0VTTNK", 'F'}, + {"0VTTNN", 'F'}, + {"0VTTNT", 'F'}, + {"0VTV(1", 'F'}, + {"0VTV(F", 'F'}, + {"0VTVO(", 'F'}, + {"0VTVOF", 'F'}, + {"0VTVOS", 'F'}, {"0VU", 'F'}, {"0VU(1)", 'F'}, {"0VU(1O", 'F'}, @@ -8166,7 +8611,6 @@ static const keyword_t sql_keywords[] = { {"0VUENU", 'F'}, {"0VUEOK", 'F'}, {"0VUEON", 'F'}, - {"0VUEOO", 'F'}, {"0VUES", 'F'}, {"0VUES&", 'F'}, {"0VUES(", 'F'}, @@ -8202,30 +8646,6 @@ static const keyword_t sql_keywords[] = { {"0VUF(S", 'F'}, {"0VUF(V", 'F'}, {"0VUK(E", 'F'}, - {"0VUN(1", 'F'}, - {"0VUN(F", 'F'}, - {"0VUN(S", 'F'}, - {"0VUN(V", 'F'}, - {"0VUN,(", 'F'}, - {"0VUN,F", 'F'}, - {"0VUN1(", 'F'}, - {"0VUN1,", 'F'}, - {"0VUN1O", 'F'}, - {"0VUNC", 'F'}, - {"0VUNE(", 'F'}, - {"0VUNE1", 'F'}, - {"0VUNEF", 'F'}, - {"0VUNEN", 'F'}, - {"0VUNES", 'F'}, - {"0VUNEV", 'F'}, - {"0VUNF(", 'F'}, - {"0VUNO(", 'F'}, - {"0VUNOF", 'F'}, - {"0VUNOS", 'F'}, - {"0VUNOV", 'F'}, - {"0VUNS(", 'F'}, - {"0VUNS,", 'F'}, - {"0VUNSO", 'F'}, {"0VUO(E", 'F'}, {"0VUON(", 'F'}, {"0VUON1", 'F'}, @@ -8243,7 +8663,9 @@ static const keyword_t sql_keywords[] = { {"0VUTN(", 'F'}, {"0VUTN1", 'F'}, {"0VUTNF", 'F'}, + {"0VUTNN", 'F'}, {"0VUTNS", 'F'}, + {"0VUTNV", 'F'}, {"0VUV,(", 'F'}, {"0VUV,F", 'F'}, {"0VUVC", 'F'}, @@ -8264,7 +8686,6 @@ static const keyword_t sql_keywords[] = { {"ABS", 'f'}, {"ACCESSIBLE", 'k'}, {"ACOS", 'f'}, - {"ADD", 'k'}, {"ADDDATE", 'f'}, {"ADDTIME", 'f'}, {"AES_DECRYPT", 'f'}, @@ -8310,6 +8731,10 @@ static const keyword_t sql_keywords[] = { {"AVG", 'f'}, {"BEFORE", 'k'}, {"BEGIN", 'T'}, + {"BEGIN DECLARE", 'T'}, + {"BEGIN GOTO", 'T'}, + {"BEGIN TRY", 'T'}, + {"BEGIN TRY DECLARE", 'T'}, {"BENCHMARK", 'f'}, {"BETWEEN", 'o'}, {"BIGINT", 't'}, @@ -8361,7 +8786,7 @@ static const keyword_t sql_keywords[] = { {"CHAR_LENGTH", 'f'}, {"CHDIR", 'f'}, {"CHDRIVE", 'f'}, - {"CHECK", 'k'}, + {"CHECK", 'n'}, {"CHECKSUM_AGG", 'f'}, {"CHOOSE", 'f'}, {"CHR", 'f'}, @@ -8466,6 +8891,7 @@ static const keyword_t sql_keywords[] = { {"DAY_SECOND", 'k'}, {"DBMS_LOCK.SLEEP", 'f'}, {"DBMS_PIPE.RECEIVE_MESSAGE", 'f'}, + {"DBMS_UTILITY.SQLID_TO_SQLHASH", 'f'}, {"DB_ID", 'f'}, {"DB_NAME", 'f'}, {"DCOUNT", 'f'}, @@ -8544,6 +8970,8 @@ static const keyword_t sql_keywords[] = { {"FILEGROUP_NAME", 'f'}, {"FILELEN", 'f'}, {"FILEPROPERTY", 'f'}, + {"FILETOBLOB", 'f'}, + {"FILETOCLOB", 'f'}, {"FILE_ID", 'f'}, {"FILE_IDEX", 'f'}, {"FILE_NAME", 'f'}, @@ -8611,7 +9039,7 @@ static const keyword_t sql_keywords[] = { {"IDENT_SEED", 'f'}, {"IF", 'f'}, {"IF EXISTS", 'f'}, - {"IF NOT", 'n'}, + {"IF NOT", 'f'}, {"IF NOT EXISTS", 'f'}, {"IFF", 'f'}, {"IFNULL", 'f'}, @@ -8676,6 +9104,7 @@ static const keyword_t sql_keywords[] = { {"IS_USED_LOCK", 'f'}, {"ITERATE", 'k'}, {"JOIN", 'k'}, + {"JSON_KEYS", 'f'}, {"JULIANDAY", 'f'}, {"JUSTIFY_DAYS", 'f'}, {"JUSTIFY_HOURS", 'f'}, @@ -8694,7 +9123,7 @@ static const keyword_t sql_keywords[] = { {"LEADING", 'k'}, {"LEAST", 'f'}, {"LEAVE", 'k'}, - {"LEFT", 'n'}, + {"LEFT", 'f'}, {"LEFT JOIN", 'k'}, {"LEFT OUTER", 'k'}, {"LEFT OUTER JOIN", 'k'}, @@ -8818,7 +9247,7 @@ static const keyword_t sql_keywords[] = { {"ORDER BY", 'B'}, {"ORIGINAL_DB_NAME", 'f'}, {"ORIGINAL_LOGIN", 'f'}, - {"OUT", 'k'}, + {"OUT", 'n'}, {"OUTER", 'n'}, {"OUTFILE", 'k'}, {"OVERLAPS", 'f'}, @@ -8987,6 +9416,7 @@ static const keyword_t sql_keywords[] = { {"SPLIT_PART", 'f'}, {"SQL", 'k'}, {"SQLEXCEPTION", 'k'}, + {"SQLITE_VERSION", 'f'}, {"SQLSTATE", 'k'}, {"SQLWARNING", 'k'}, {"SQL_BIG_RESULT", 'k'}, @@ -9037,7 +9467,7 @@ static const keyword_t sql_keywords[] = { {"SYSTEM_USER", 'f'}, {"SYSUSERS", 'k'}, {"SYSUTCDATETME", 'f'}, - {"TABLE", 'k'}, + {"TABLE", 'n'}, {"TAN", 'f'}, {"TERMINATED", 'k'}, {"TERTIARY_WEIGHTS", 'f'}, @@ -9081,6 +9511,7 @@ static const keyword_t sql_keywords[] = { {"TRUE", '1'}, {"TRUNC", 'f'}, {"TRUNCATE", 'f'}, + {"TRY", 'T'}, {"TRY_CAST", 'f'}, {"TRY_CONVERT", 'f'}, {"TRY_PARSE", 'f'}, @@ -9217,5 +9648,5 @@ static const keyword_t sql_keywords[] = { {"||", '&'}, {"~*", 'o'}, }; -static const size_t sql_keywords_sz = 9049; +static const size_t sql_keywords_sz = 9352; #endif diff --git a/apache2/libinjection/libinjection_xss.c b/apache2/libinjection/libinjection_xss.c index 2807c22f08..f0df4d84ac 100644 --- a/apache2/libinjection/libinjection_xss.c +++ b/apache2/libinjection/libinjection_xss.c @@ -6,13 +6,6 @@ #include #include -#ifndef DEBUG -#include -#define TRACE() printf("%s:%d\n", __FUNCTION__, __LINE__) -#else -#define TRACE() -#endif - typedef enum attribute { TYPE_NONE , TYPE_BLACK /* ban always */ @@ -37,109 +30,109 @@ typedef struct stringtype { static const int gsHexDecodeMap[256] = { - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, - 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256 + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, + 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256 }; static int html_decode_char_at(const char* src, size_t len, size_t* consumed) { - int val = 0; - size_t i; - int ch; - - if (len == 0 || src == NULL) { - *consumed = 0; - return -1; - } - - *consumed = 1; - if (*src != '&' || len < 2) { - return (unsigned char)(*src); - } - - - if (*(src+1) != '#') { - /* normally this would be for named entities - * but for this case we don't actually care - */ - return '&'; - } - - if (*(src+2) == 'x' || *(src+2) == 'X') { - ch = (unsigned char) (*(src+3)); - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - /* degenerate case '&#[?]' */ - return '&'; + int val = 0; + size_t i; + int ch; + + if (len == 0 || src == NULL) { + *consumed = 0; + return -1; } - val = ch; - i = 4; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - ch = gsHexDecodeMap[ch]; - if (ch == 256) { - *consumed = i; - return val; - } - val = (val * 16) + ch; - if (val > 0x1000FF) { - return '&'; - } - ++i; + + *consumed = 1; + if (*src != '&' || len < 2) { + return (unsigned char)(*src); } - *consumed = i; - return val; - } else { - i = 2; - ch = (unsigned char) src[i]; - if (ch < '0' || ch > '9') { - return '&'; + + + if (*(src+1) != '#') { + /* normally this would be for named entities + * but for this case we don't actually care + */ + return '&'; } - val = ch - '0'; - i += 1; - while (i < len) { - ch = (unsigned char) src[i]; - if (ch == ';') { - *consumed = i + 1; - return val; - } - if (ch < '0' || ch > '9') { - *consumed = i; - return val; - } - val = (val * 10) + (ch - '0'); - if (val > 0x1000FF) { - return '&'; - } - ++i; + + if (*(src+2) == 'x' || *(src+2) == 'X') { + ch = (unsigned char) (*(src+3)); + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + /* degenerate case '&#[?]' */ + return '&'; + } + val = ch; + i = 4; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + *consumed = i; + return val; + } + val = (val * 16) + ch; + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } else { + i = 2; + ch = (unsigned char) src[i]; + if (ch < '0' || ch > '9') { + return '&'; + } + val = ch - '0'; + i += 1; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + if (ch < '0' || ch > '9') { + *consumed = i; + return val; + } + val = (val * 10) + (ch - '0'); + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; } - *consumed = i; - return val; - } } @@ -157,7 +150,7 @@ static stringtype_t BLACKATTR[] = { , { "DATASRC", TYPE_BLACK } /* IE */ , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */ - , { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */ + , { "FORMACTION", TYPE_ATTR_URL } /* HTML 5 */ , { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */ , { "FROM", TYPE_ATTR_URL } /* SVG */ , { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */ @@ -173,20 +166,20 @@ static stringtype_t BLACKATTR[] = { }; /* xmlns */ -/* xml-stylesheet > , */ +/* `xml-stylesheet` > , */ /* -static const char* BLACKATTR[] = { - "ATTRIBUTENAME", - "BACKGROUND", - "DATAFORMATAS", - "HREF", - "SCROLL", - "SRC", - "STYLE", - "SRCDOC", - NULL -}; + static const char* BLACKATTR[] = { + "ATTRIBUTENAME", + "BACKGROUND", + "DATAFORMATAS", + "HREF", + "SCROLL", + "SRC", + "STYLE", + "SRCDOC", + NULL + }; */ static const char* BLACKTAG[] = { @@ -220,36 +213,36 @@ static const char* BLACKTAG[] = { static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) { - char ca; - char cb; - /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ - while (n-- > 0) { - cb = *b++; - if (cb == '\0') continue; + char ca; + char cb; + /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ + while (n-- > 0) { + cb = *b++; + if (cb == '\0') continue; - ca = *a++; + ca = *a++; - if (cb >= 'a' && cb <= 'z') { - cb -= 0x20; - } - /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ - if (ca != cb) { - return 1; + if (cb >= 'a' && cb <= 'z') { + cb -= 0x20; + } + /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ + if (ca != cb) { + return 1; + } } - } - if (*a == 0) { - /* printf(" MATCH \n"); */ - return 0; - } else { - return 1; - } + if (*a == 0) { + /* printf(" MATCH \n"); */ + return 0; + } else { + return 1; + } } /* - * Does an HTML encoded binary string (const char*, lenght) start with - * a all uppercase c-string (null terminated), case insenstive! - * + * Does an HTML encoded binary string (const char*, length) start with + * a all uppercase c-string (null terminated), case insensitive! + * * also ignore any embedded nulls in the HTML string! * * return 1 if match / starts with @@ -257,47 +250,47 @@ static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) */ static int htmlencode_startswith(const char *a, const char *b, size_t n) { - size_t consumed; - int cb; - int first = 1; - /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ + size_t consumed; + int cb; + int first = 1; + /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ while (n > 0) { - if (*a == 0) { - /* printf("Match EOL!\n"); */ - return 1; - } - cb = html_decode_char_at(b, n, &consumed); - b += consumed; - n -= consumed; - - if (first && cb <= 32) { - /* ignore all leading whitespace and control characters */ - continue; - } - first = 0; + if (*a == 0) { + /* printf("Match EOL!\n"); */ + return 1; + } + cb = html_decode_char_at(b, n, &consumed); + b += consumed; + n -= consumed; + + if (first && cb <= 32) { + /* ignore all leading whitespace and control characters */ + continue; + } + first = 0; if (cb == 0) { - /* always ignore null characters in user input */ - continue; - } + /* always ignore null characters in user input */ + continue; + } if (cb == 10) { - /* always ignore vtab characters in user input */ - /* who allows this?? */ - continue; - } + /* always ignore vertical tab characters in user input */ + /* who allows this?? */ + continue; + } if (cb >= 'a' && cb <= 'z') { - /* upcase */ + /* upcase */ cb -= 0x20; } if (*a != (char) cb) { - /* printf(" %c != %c\n", *a, cb); */ - /* mismatch */ - return 0; + /* printf(" %c != %c\n", *a, cb); */ + /* mismatch */ + return 0; } - a++; + a++; } return (*a == 0) ? 1 : 0; @@ -313,8 +306,8 @@ static int is_black_tag(const char* s, size_t len) black = BLACKTAG; while (*black != NULL) { - if (cstrcasecmp_with_null(*black, s, len) == 0) { - /* printf("Got black tag %s\n", *black); */ + if (cstrcasecmp_with_null(*black, s, len) == 0) { + /* printf("Got black tag %s\n", *black); */ return 1; } black += 1; @@ -324,7 +317,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 's' || s[0] == 'S') && (s[1] == 'v' || s[1] == 'V') && (s[2] == 'g' || s[2] == 'G')) { - /* printf("Got SVG tag \n"); */ + /* printf("Got SVG tag \n"); */ return 1; } @@ -332,7 +325,7 @@ static int is_black_tag(const char* s, size_t len) if ((s[0] == 'x' || s[0] == 'X') && (s[1] == 's' || s[1] == 'S') && (s[2] == 'l' || s[2] == 'L')) { - /* printf("Got XSL tag\n"); */ + /* printf("Got XSL tag\n"); */ return 1; } @@ -347,17 +340,18 @@ static attribute_t is_black_attr(const char* s, size_t len) return TYPE_NONE; } - /* javascript on.* */ - if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { - /* printf("Got javascript on- attribute name\n"); */ - return TYPE_BLACK; - } + if (len >= 5) { + /* JavaScript on.* */ + if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) { + /* printf("Got JavaScript on- attribute name\n"); */ + return TYPE_BLACK; + } + - if (len >= 5) { /* XMLNS can be used to create arbitrary tags */ if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) { - /* printf("Got XMLNS and XLINK tags\n"); */ + /* printf("Got XMLNS and XLINK tags\n"); */ return TYPE_BLACK; } } @@ -365,7 +359,7 @@ static attribute_t is_black_attr(const char* s, size_t len) black = BLACKATTR; while (black->name != NULL) { if (cstrcasecmp_with_null(black->name, s, len) == 0) { - /* printf("Got banned attribute name %s\n", black->name); */ + /* printf("Got banned attribute name %s\n", black->name); */ return black->atype; } black += 1; @@ -387,20 +381,18 @@ static int is_black_url(const char* s, size_t len) static const char* javascript_url = "JAVA"; /* skip whitespace */ - while (len > 0) { + while (len > 0 && (*s <= 32 || *s >= 127)) { /* * HEY: this is a signed character. * We are intentionally skipping high-bit characters too - * since they are not ascii, and Opera sometimes uses UTF8 whitespace + * since they are not ASCII, and Opera sometimes uses UTF-8 whitespace. + * + * Also in EUC-JP some of the high bytes are just ignored. */ - if (*s <= 32) { - ++s; - --len; - } - break; + ++s; + --len; } - if (htmlencode_startswith(data_url, s, len)) { return 1; } @@ -442,16 +434,16 @@ int libinjection_is_xss(const char* s, size_t len, int flags) /* * IE6,7,8 parsing works a bit differently so * a whole