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/CHANGES b/CHANGES index 031648e4d5..bd03641530 100644 --- a/CHANGES +++ b/CHANGES @@ -1,9 +1,260 @@ -DD mmm YYYY - X.Y.Z (To be released) ------------------------------------- +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..00c8cd3145 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +ModSecurity for Apache 2.x +====== + +http://www.modsecurity.org/ + +Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) + +You may not use this file except in compliance with the License. You may obtain a copy of the License at: https://www.apache.org/licenses/LICENSE-2.0 + +If any of the files related to licensing are missing or if you have any other questions related to licensing please contact Trustwave Holdings, Inc. directly using the email address: security@modsecurity.org. + + +## Documentation + +Please refer to: [the documentation folder](https://github.com/SpiderLabs/ModSecurity/tree/v2/master/doc) for the reference manual. + +## Sponsor Note + +ModSecurity is sponsored by Trustwave. Trustwave offers a range of commercial services related to ModSecurity, including a set of Rules, consultancy and customization of ModSecurity. Contact the Trustwave sales department for more information - sales@trustwave.com 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/apache2_config.c b/apache2/apache2_config.c index bfbcb83468..80f8f2b507 100644 --- a/apache2/apache2_config.c +++ b/apache2/apache2_config.c @@ -73,6 +73,9 @@ void *create_directory_config(apr_pool_t *mp, char *path) /* audit log variables */ dcfg->auditlog_flag = NOT_SET; dcfg->auditlog_type = NOT_SET; + #ifdef WITH_YAJL + dcfg->auditlog_format = NOT_SET; + #endif dcfg->max_rule_time = NOT_SET; dcfg->auditlog_dirperms = NOT_SET; dcfg->auditlog_fileperms = NOT_SET; @@ -236,9 +239,9 @@ static void copy_rules_phase(apr_pool_t *mp, /* Copy the rule. */ *(msre_rule **)apr_array_push(child_phase_arr) = rule; - if (rule->actionset->is_chained) mode = 2; + if (rule->actionset && rule->actionset->is_chained) mode = 2; } else { - if (rule->actionset->is_chained) mode = 1; + if (rule->actionset && rule->actionset->is_chained) mode = 1; } } else { if (mode == 2) { @@ -503,6 +506,10 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) merged->auditlog2_fd = parent->auditlog2_fd; merged->auditlog2_name = parent->auditlog2_name; } + #ifdef WITH_YAJL + merged->auditlog_format = (child->auditlog_format == NOT_SET + ? parent->auditlog_format : child->auditlog_format); + #endif merged->auditlog_storage_dir = (child->auditlog_storage_dir == NOT_SET_P ? parent->auditlog_storage_dir : child->auditlog_storage_dir); merged->auditlog_parts = (child->auditlog_parts == NOT_SET_P @@ -667,6 +674,9 @@ void init_directory_config(directory_config *dcfg) /* audit log variables */ if (dcfg->auditlog_flag == NOT_SET) dcfg->auditlog_flag = 0; if (dcfg->auditlog_type == NOT_SET) dcfg->auditlog_type = AUDITLOG_SERIAL; + #ifdef WITH_YAJL + if (dcfg->auditlog_format == NOT_SET) dcfg->auditlog_format = AUDITLOGFORMAT_NATIVE; + #endif if (dcfg->max_rule_time == NOT_SET) dcfg->max_rule_time = 0; if (dcfg->auditlog_dirperms == NOT_SET) dcfg->auditlog_dirperms = CREATEMODE_DIR; if (dcfg->auditlog_fileperms == NOT_SET) dcfg->auditlog_fileperms = CREATEMODE; @@ -722,8 +732,13 @@ void init_directory_config(directory_config *dcfg) if (dcfg->col_timeout == NOT_SET) dcfg->col_timeout = 3600; /* Hash */ - if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp); - if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key); + if (dcfg->hash_is_enabled == HASH_ENABLED) { + if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = getkey(dcfg->mp); + if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = strlen(dcfg->crypto_key); + } else { + if (dcfg->crypto_key == NOT_SET_P) dcfg->crypto_key = ""; + if (dcfg->crypto_key_len == NOT_SET) dcfg->crypto_key_len = 0; + } if (dcfg->crypto_key_add == NOT_SET) dcfg->crypto_key_add = HASH_KEYONLY; if (dcfg->crypto_param_name == NOT_SET_P) dcfg->crypto_param_name = "crypt"; if (dcfg->hash_is_enabled == NOT_SET) dcfg->hash_is_enabled = HASH_DISABLED; @@ -755,6 +770,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, char *rid = NULL; msre_rule *rule = NULL; extern msc_engine *modsecurity; + int type_with_lua = 1; + int type_rule; + int rule_actionset; int offset = 0; #ifdef DEBUG_CONF @@ -786,26 +804,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 +837,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) { @@ -877,8 +897,10 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, rule->actionset, 1); /* Keep track of the parent action for "block" */ - rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; - rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; + if (rule->actionset) { + rule->actionset->parent_intercept_action_rec = dcfg->tmp_default_actionset->intercept_action_rec; + rule->actionset->parent_intercept_action = dcfg->tmp_default_actionset->intercept_action; + } /* Must NOT specify a disruptive action in logging phase. */ if ((rule->actionset != NULL) @@ -893,7 +915,9 @@ static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, if (dcfg->tmp_chain_starter != NULL) { rule->chain_starter = dcfg->tmp_chain_starter; - rule->actionset->phase = rule->chain_starter->actionset->phase; + if (rule->actionset) { + rule->actionset->phase = rule->chain_starter->actionset->phase; + } } if (rule->actionset->is_chained != 1) { @@ -1189,10 +1213,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", @@ -1228,9 +1255,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", @@ -1282,6 +1312,23 @@ 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) +{ + 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) { @@ -1666,7 +1713,7 @@ static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, } char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, - TreeRoot **whitelist, TreeRoot **suspicious_list, + TreeRoot **whitelist, TreeRoot **suspicious_list, const char *filename) { int res = 0; @@ -1753,7 +1800,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; @@ -3223,6 +3270,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, diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c index 88f1903183..f6c785e8d2 100644 --- a/apache2/apache2_io.c +++ b/apache2/apache2_io.c @@ -36,6 +36,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, msc_data_chunk *chunk = NULL; apr_bucket *bucket; apr_status_t rc; + int no_data = 1; char *my_error_msg = NULL; if (msr == NULL) { @@ -85,10 +86,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 +109,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 +162,10 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Input forwarding complete."); } + + if (no_data) { + return ap_get_brigade(f->next, bb_out, mode, block, nbytes); + } } return APR_SUCCESS; @@ -164,7 +176,7 @@ apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, */ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { request_rec *r = msr->r; - unsigned int seen_eos; + unsigned int finished_reading; apr_bucket_brigade *bb_in; apr_bucket *bucket; @@ -188,12 +200,12 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Input filter: Reading request body."); } - if (modsecurity_request_body_start(msr, error_msg) < 0) { return -1; } - seen_eos = 0; + finished_reading = 0; + msr->if_seen_eos = 0; bb_in = apr_brigade_create(msr->mp, r->connection->bucket_alloc); if (bb_in == NULL) return -1; do { @@ -205,6 +217,9 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { * too large and APR_EGENERAL when the client disconnects. */ switch(rc) { + case APR_INCOMPLETE : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -7; case APR_EOF : *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); return -6; @@ -275,14 +290,25 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (msr->txcfg->stream_inbody_inspection == 1) { +#ifndef MSC_LARGE_STREAM_INPUT msr->stream_input_length+=buflen; modsecurity_request_body_to_stream(msr, buf, buflen, error_msg); +#else + if (modsecurity_request_body_to_stream(msr, buf, buflen, error_msg) < 0) { + return -1; + } +#endif } msr->reqbody_length += buflen; if (buflen != 0) { int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg); + + if (msr->reqbody_length > (apr_size_t)msr->txcfg->reqbody_limit && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) { + finished_reading = 1; + } + if (rcbs < 0) { if (rcbs == -5) { if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { @@ -309,15 +335,15 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { } if (APR_BUCKET_IS_EOS(bucket)) { - seen_eos = 1; + finished_reading = 1; + msr->if_seen_eos = 1; } } apr_brigade_cleanup(bb_in); - } while(!seen_eos); + } while(!finished_reading); - // TODO: Why ignore the return code here? - modsecurity_request_body_end(msr, error_msg); + 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 +352,7 @@ apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { msr->if_status = IF_STATUS_WANTS_TO_RUN; - return 1; + return rcbe; } @@ -600,8 +626,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)); + } } } diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c index 0960dc8e63..24bba0cee9 100644 --- a/apache2/apache2_util.c +++ b/apache2/apache2_util.c @@ -268,7 +268,7 @@ static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec * else hostname = ""; #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 - ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, + ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1, hostname, log_escape(msr->mp, r->uri), unique_id); #else @@ -339,6 +339,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { if (em == NULL) return NULL; +#ifndef LOG_NO_FILENAME if (em->file != NULL) { s_file = apr_psprintf(mp, "[file \"%s\"] ", log_escape(mp, (char *)em->file)); @@ -349,6 +350,7 @@ char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { s_line = apr_psprintf(mp, "[line %d] ", em->line); if (s_line == NULL) return NULL; } +#endif s_level = apr_psprintf(mp, "[level %d] ", em->level); if (s_level == NULL) return NULL; diff --git a/apache2/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