From 384592efa1429cbfb4d7f37e97830055f99c6751 Mon Sep 17 00:00:00 2001 From: Packit Service Date: Dec 09 2020 22:57:06 +0000 Subject: mod_security-2.9.2 base --- diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..715dc1a --- /dev/null +++ b/CHANGES @@ -0,0 +1,1891 @@ +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. + [Issue #872 - Kurt Newman] + * Fix invalid storage reference by apr_psprintf at msc_crypt.c + [Issue #609 - Jeff Trawick] + +12 Feb 2015 - 2.9.0 +------------------- + + * Fix apr_crypto.h include, now checking if apr_crypto.h is available by + checking the definition WITH_APU_CRYPTO. + [martinjina and ModSecurity team] + +15 Dez 2014 - 2.9.0-RC2 +----------------------- + + * OpenSSL dependency was removed on MS Windows builds. ModSecurity is now using + the Windows certificate storage. + [Gregg Smith, Steffen and ModSecurity team] + * Informs about external resources loaded/failed while reloading Apache. + [ModSecurity team] + * Adds missing 'ModSecurity:' prefix in some warnings messages. + [Walter Hop and ModSecurity team] + * Refactoring external resources download warn messages. Holding the message + to be displayed when Apache is ready to write on the error_log. + [ModSecurity team] + * Remote resources loading process is now failing in case of HTTP error. + [Walter Hop and ModSecurity team] + * Fixed start up crash on Apache with mod_ssl configured. Crash was happening + during the download of remote resources. + [Christian Folini, Walter Hop and ModSecurity team] + * Curl is not a mandatory dependency to ModSecurity core anymore. + [Rainer Jung and ModSecurity team] + +18 Nov 2014 - 2.9.0-RC1 +----------------------- + + * `pmFromFile' and `ipMatchFromFile' operators are now accepting HTTPS served + files as parameter. + * `SecRemoteRules' directive - allows you to specify a HTTPS served file that + may contain rules in the SecRule format to be loaded into your ModSecurity + instance. + * `SecRemoteRulesFailAction' directive - allows you to control whenever the + user wants to Abort or just Warn when there is a problem while downloading + rules specified with the directive: `SecRemoteRules'. + * `fuzzyHash' operator - allows to match contents using fuzzy hashes. + * `FILES_TMP_CONTENT' collection - make available the content of uploaded + files. + * InsecureNoCheckCert - option to validate or not a chain of SSL certificates + on mlogc connections. + * ModSecurityIIS: ModSecurity event ID was changed from 0 to 0x1. + [Issue #676 - Kris Kater and ModSecurity team] + * Fixed signature on "status call": ModSecurity is now using the original + server signature. + [Issues #702 - Linas and ModSecurity team] + * YAJL version is printed while ModSecurity initialization. + [Issue #703 - Steffen (Apache Lounge) and Mauro Faccenda] + * Fixed subnet representation using slash notation on the @ipMatch operator. + [Issue #706 - Walter Hop and ModSecurity team] + * Limited the length of a status call. + [Issue #714 - 'cpanelkurt' and ModSecurity team] + * Added the missing -P option to nginx regression tests. + [Issue #720 - Paul Yang] + * Fixed automake scripts to do not use features which will be deprecated in + the upcoming releases of automake. + [Issue #760 - ModSecurity team] + * apr-utils's LDFALGS is now considered while building ModSecurity. + [Issue #782 - Daniel J. Luke] + * IIS installer is not considering IIS 6 as compatible anymore. + [Issue #790 - ModSecurity team] + * Fixed yajl build script: now looking for the correct header file. + [Issue #804 - 'rpfilomeno' and ModSecurity team] + * mlgoc is now forced to use TLS 1.x. + [Issue #806 - Josh Amishav-Zlatin and ModSecurity team] + + +14 Apr 2014 - 2.8.0 +------------------- + +Bug fix + * Build issue: Now using autotools to idenfiy if sys/utsname.h is present. + * Change configure.ac version to 2.8 + +31 Mar 2014 - 2.8.0-RC1 +----------------------- + +New features + * JSON Parser is no longer under tests. Now it is part of our mainline; + * Connection limits (SecConnReadStateLimit/SecConnWriteStateLimit) now support white and suspicious list; + * New variables: FULL_REQUEST and FULL_REQUEST_LENGTH were added, allowing the rules to access the full content of a request; + * ModSecurity status is now part of our mainline; + * New operator: @detectXSS was added. It makes usage of the newest libinjection XSS detection functionality; + * Append and prepend are now supported on nginx (Ref: #635); + * SecServerSignature is now available on nginx (Ref: #637). + +Improvements  + * Regression tests are not able to expect different values according to the platform; + * Visual C++ 12/10 runtime dependencies are now part of the IIS installer, no need to have it installed prior ModSecurity installation (Ref: #627); + * New script was added to the IIS versions to identify whenever there is a missing dependency (available through the Application Menu); + * Memory usage improvement: using correct memory pools according to the context (Ref: #618, #620, #619); + * Independent API call to free the connection allocations, independently from the request objects, improvements on Nginx performance, vide issue for more information (Ref: #620, #648); + * IIS installer is now using the correct 32/64bits folders to install; + * IIS Installer 32bits now refuses to install on 64bits environments; + * IIS: Using new WiX options to build the package in the correct architecture; + * While installing IIS version the installer will remove old ModSecurityIIS configuration or files before proceed with the installation, avoiding further errors; + * CRS from IIS version was upgraded to 2.2.9; + * IIS installer does not support repair anymore, in fact it was not working already and it is now disabled; + * ModSecurity now warns the user who tries to use "proxy" in IIS or Nginx. Proxy is Apache only; + * Remove warnings from the build process (Ref: #617); + * Apache configuration in regression tests was changed making it more platform independent; + * Reduced the amount of warnings during the compilation (Ref: #385a2828e87897bd611bd2a519727ef88dc6d632, #1e63e49db4a592d28e08a33fc60750c37a3886fe); + * Regression tests were refactored to be more Nginx friendly; + * Fixed some regression tests that were not being flexible to handle multiple platforms: (Ref #636) +        - Fixed config/00-load-modsec.t test case. Now it expects for Nginx loaded message as it does for Apache. (Ref: #643); +        - Fixed mixed/10-misc-directives.t. Now it does not expect for SecServerSignature on the logs, just in the headers as the Nginx does in silence. +        - Fixed tnf/10-tfn-cache.t, action/10-logging.t, config/10-misc-directives.t, config/10-request-directives.t, misc/00-multipart-parser.t , misc/10-tfn-cache.t, rule/20-exceptions.t, rule/00-basics.t, rule/10-xml.t; +        - Increased the timeout while reading the auditlog; +        - SecAuditLogType Concurrent was removed from the regression test case, not compatible with all ports yet; +        - Regression tests were speeded up, as the number of tests are growing it is impossible to have it slow; +        - Fixed regression tests scripts paths, to make it MacOS friendly; +        - Avoiding dead locks on Nginx regression tests by enforcing a timeout whenever a request appears to fail;  + * Updates to fix errors found by Parfait static code analysis (Ref: #612); + * Cleaning up on the repository, by removing unused files; + * IIS installer now supports to perform the installation without register the DLL on the system. It means that the user can download our MSI installer as it was a tarball archive (Ref #629, #624); + * IIS now support 32bits and 64bits pools, both are registered on IIS (Ref #628). + +Bug fix + * Correctly handling inet_pton in IIS version; + * Nginx was missing a terminator while the charset string was mounted (Ref: #148); + * Added mod_extract_forwarded.c to run before mod_security2.c (Ref: #594); + * Added missing environment variables to regression tests; + * Build system is now more flexible by looking at liblua at: /usr/local/lib; + * Fixed typo in README file. + * Removed the non standard compliant HTTP response status code 44 from modsecurity recommended file (Ref: #665); + * Fixed segmentation fault if it fails to write on the audit log (Ref: #668); + * Not rejecting a larger request with ProcessPartial. Regression tests were also added (Ref: #597); + * Fixed UF8 to unicode conversion. Regression tests were also added(Ref: #672); + * Avoiding segmentation fault by checking if a structure is null before access its members; + * Removed double charset-header that used happen due a hardcoded charset in Nginx implementation (Ref: #650); + * Now alerting the users that there is no memory to proceed loading the configuration instead of just die; + * If SecRuleEngine is set to Off and SecRequestBodyAccess On Nginx returns error 500. Standalone is now capable to identify whenever ModSecurity is enabled or disabled, independently of ModSecurity core (Ref: #645);  + * Fixed missing headers on Nginx whenever SecResponseBodyAccess was set to On and happens to be a filter on phase equals or over 3. (Ref #634); + * IIS is now picking the correct version of AppCmd while uninstalling or installing ModSecurityISS. (Ref #632). + + + +17 Dec 2013 - 2.7.7 +------------------- +Fixes: + +- Changed release version to 2.7.7 +- Got the configure scripts inside the release tarball + + +16 Dec 2013 - 2.7.6 +------------------- +Improvements: + +- Organizes all Makefile.am - 1cde4d2dd9d96747536c1c25d06ba0677069477f + Now using one file per line (sorted). This is the better way to handle it, since it reduces the possibility of merge conflicts. + +- nginx: generates config file using configure input. - 351b9cc357d439e30ebd61d89a9e38ecf55c6827 + The nginx config file was looking for depedencies by its own, by doing that it was ignoring the options that were passed to configure script. This commit deletes this config file and adds a meta-config which is populated by configure whenever the standalone-module is enabled. + +- nginx: adds lua support - da16d9e5d51d4ef8734687514a4e1368e7fb4284 + +- iis: Cosmetics fixies on sqli. - 5046c8327ea21c69b4c0d0c0057c692b05b09fef + This is needed to get it compiled with VS2011 on Windows8 + +- Regression tests: makes configuration compatible with 2.2 and 2.4 (try 2) - ae252ee8767069363906e5a611dff487b799b839 + +- nginx: Trying apxs and apxs2 while compiling nginx module - 65d9272fdc353e1263567b60604542d377d19672 + +- nginx: Trying apxs and apxs2 while compiling nginx module - 35fd75d859e4a8873b8843da1db13e04a1b08140 + +- macos: Using glibtoolize instead of libtoolize - 751a9f4e45213cd69f00c62c71edc9d7ad99b82d + +- regression-tests: makes configuration compatible with 2.2 and 2.4 - 6fc4cac37ab1be8d1232140042b58fe4bd93ee17 + +- Regression test: get it working with apache 2.4 - e9813cd0d9bfc5b0c9aa5832634ec1b39b805108 + Changes in httpd.conf.in to get it working with apache 2.4 + +- Code cosmetics. - 7366f35c1d80772d739b35da8faa972f92a72b97 + Changed to reduce the number of possible fails during Build Bot compilation. + +- iis: Waiting for 5 seconds before move curl directory - 9bf2959c919587ebc63f5a1b8c0785da8927bff5 + Testing buildbot. + +- Redefines unixd_set_global_mutex_perms on tests - f70f6f4281b806627e0cf0dbb9c84ae5864bdb16 + Avoding conflicts with the standalone implementation + +- Adds verbose quality check - 388943440cc9b8c6fdea09f5e365a2e5a3e792e2 + Vera++ and ccpcheck are not outputing to the stderr instead stdout allowing the buildbot to extract some numbers about it. + +- Adds support for coding style and quality check - b77e90152d119609ac78a7028383c3b79898b2cf + Initial effort to get the code on shape. This will be executed by the buildbots as soon as they get ready for it. + +- iis: New improvements on the Wix installer - 2ea5a74a7bfb00f21312e51e48aa6dac03d84600 + * Now the installation is divided in modules: ModSecurity and CRS. + * Added default configuration + * Configuration was moved to "Program Files" folder + * Build_msi script now using candle available in %PATH% + +- iis: Removes the installer helper dependency - 1a12648c9f6028f251af0f03c889397c7954b74c + Now using appcmd directly with WiX instead of calling the installer helper. + +- iis: Remove readme.html - 550d5aae21cba696cac1ce75ab8113e5255d5a59 + This HTML is about "Creating a Native Module for IIS7" not straight related to ModSecurity itself. + +- iis: Adds batch script to compile Wix - a2c5fc831baf0b324ebb66b0f878dacf1ec2f808 + This batch script can be used to generate our msi installer. + +- iis: Adds Wix installer resources - 3604763e15a665eb7a6ecae1f7e7c65cebbb1d17 + This is all about cosmetic changes. + +- iss: Removes Post-Build event. - 28bbde1bb218b004654cb865fc8563d69b848dc2 + There was a copy on Post-Build event using a hard coded path. This patch removes this Post-Build event. + +- iis: Relative paths on the VS project file - 368617ddb2443f9b6036f80a648d467d07c9a054 + There are a ModSecurityIIS solution and project files, those were using hard coded paths to meet the dependencies. As consequence of the last update in our build scripts, now we are able to built the dependencies and load it to our Visual Studio project using relative paths. + +- iis: Adds release script - 9477118903861ce80c4c27cb581bf3462315e98e + +- iis: fixies the Installer.cpp coding style - 79875b1af8e8571098345b91557bab9c06eb7c88 + +- iis: Removes AppWizard remade file - 91738f93bcc82b6ab756c550a66b6cf6af2fa9f8 + Apparently the AppWizard was used to generate part of this Installer, the ReadMe.txt created by the AppWizard was removed by this commit + +- iss: Removes pre-compiled headers - adfbeb85dcfa9466b72eebb8d1bd8eb7728bab79 + No need to use the pre-compiled headers in InstallerHelper, removing it, in order to keep the project lean. + +- iis: Moves installer to InstallerHelper - 6adf25667dd4bfa33010bd6d8ae3d35046a69967 + To organize the folder the Installer application was renamed to installer helper. It is not the real installer, it is just an helper which is executed during the installation phase. + +- iss: Removes fart dependencies - 8c3b8d81b613aaa38f28472af1eb26c90c7fc9da + This commit removes the dependency of the fart.exe utility. The utility was responsible to rename contents inside some dependencies build files. Those modifications are not longer needed. + +- iss: Better err handling in build scripts. - 192599bf63b6ae5aa08e4536a90d5d0a17f969f7 + Now checking for errors in every step of the build phase + +- iis: Moves build_module.bat to build_modsecurity.bat - e25c6b2e85ced7beba4d41867dbdf30e9c1286d3 + The build_modsecurity.bat is now on the iis sub-directory, not in the dependencies anymore. Its content was also changed fixing all the paths. + + +- iis: Identifies arch before unzip apache - cf5de78dfb9fffd21edf17af9e1db8f2fd83c804 + Currently we need the Apache binary which could be used in 32 or 64 bits. This patch makes usage of 'cl' to identify which architecture is set. + +- iis: Renamves winbuild to dependencies - 1447766e816a896e88c9c8f053fcc3f62797bac1 + Since the directory becomes all about dependencies there is no need to call it winbuild anymore. + +- iis: Removes unnecessary files from winbuild dir - 9f8cbf6ed8034ba42aa4967699308df09864fd18 + Those .mak files seems to be part of an old build system. Since the script are now working fine, this commit removes all those .mac files and also a CMakeList.txt and the Makefile.win. + +- iis: Improves the iis build system - b277e538f28c87c81c1b50925dd8b82996b88294 + Now checking for common errors while building. Refactoring on the build scripts, now there is this build_dependencies.bat script on the iis sub-folder. By calling this script all the dependencies should be build under the winbuild/. This commit also removes build scripts that were not needed anymore. + +- iis: Fixes the vcxproj file - a946a163f0ad822c760af80ca32dda61f0e6b2a9 + Versions of the dependencies were changed, as long as the version of the Visual Studio, now 12. + +- iis: Removes unecessary files from the build system - 26738d2e34bcc7620047bd23180e0e26a64c71ee + The following files were removed: + * VCVarsQueryRegistry.bat + * vcvars64.bat + * vsvars32.bat +The visual studio files can be called direcltly, not necessary to distribute those files, at least in VS12. + +- iss: Changes httpd version 2.4.6 - 0a772cb0748aa51a01800e0473309b9de792b456 + Apache version was changed to 2.4.6 to sync with the current apache lounge version. + +- iis: Changes the version of the dependencies - 3e6fb41d36b7a5e98a55d8f52b88b29d1bd50b64 + * pcre from 8.30 to 8.33 + * zlib from 1.2.7 to 1.2.8 + * libxml2 from 2.7.7 to 2.9.1 + * curl from 7.24 to 7.33.0 + +- Removes standalone/Makefile.in - e3c19d53d23c48fea337aae76a87b2a85c36a1f1 + Makefile.in is recommended to be in the repository whenever it is edit manually, in our case the automatically generated Makefile.in is ok. + + +Bug Fixes: + +- test: Avoids conflict of fuctions definition - cef72855e4106ce29e1d39103ebf9eb9ab28f17e + +- test: Makes the unit tests to work again - cc982ae42ec86c79a67be1a01c6ee35fb06c272c + The unit tests was not working due to lack update. This patch adds the necessary stuff to have it work again. + +- iis: Avoids directory link while building - ad330a44bfa39430cf6340cb52971568cccdf1d6 + Build scripts was creating links allowing the project to be loaded into Visual Studio without care about the dependencies versions. Sometimes windows refuse to delete those links leading the script to fail. This patch moves the sources directories instead of create links to it. + +- QA: Avoids the utilization of 3rd filedescriptor - 69c5ccac662f4e11a6eefd54a3e912583c067b9d + No need to use a 3rd description on the quality check scripts. Stderr is now redirected to stdout and filtered as needed. + +- Supports WarningCountingShellCommand in cppcheck and vera - baaf502363e68c3240b60adb7f7c91f5b4f0ba03 + WarningCountingShellCommand allow us to have some measurements on the buildbot waterfall. + +- iis: Using base_rules instead of activated_rules - 7b1537058fa451e0df7098cd907ef19f04102f9d + +- iis: Fix inet_pton build problem - a4202146b8d26b6615bbab986383fe0afae60d77 + There is a function named inet_pton on windows API, with different signature. This patch just override the windows function and point the inet_pton to our implementation. + +- iis: Adds Wix installer xml file.c - b32cb7d9ab397160f0154aa4bd4e9638658b41e6 + This commit adds the Wix template to our git repository. + +- iis: build_modsecurity.bat fixies - 7e03e3f840375ed682c35a5bb67932461cc77013 + This commit enable a cleanup on the mod_security build directory avoiding symbols with different architectures. + +- iis: Fix mlogc build on windows - 9b7663fa79377a0685130a019916d810f31e7478 + The libcurl path was not pointing to the correct directory + +- Fix #154, Uses addn instead of apr_table_setn - 1734221d9d3a78f9aafd68e35717da9ee1a4fe51 + The headers are represented in the format of an apr_table, which is able to handle elements with the same key, however the function apr_table_setn checks if the key exists before add the element, if so it replaces the old value with the new one. This was making our implementation to just keep the last added Cookie. The apr_table_addn function, which is now used, just add a new item without check for olders one. + +- Merge pull request #579 from zimmerle/revert_139 - 61e54f2067ae760808359926ff91d57275df1aac + Revert merge request #139 + +- Revert "Merge pull request #139 from chaizhenhua/remotes/trunk" - 7f7d00fa2c364716691df1b45779304b24a0debb + This reverts commit 10fd40fb0d06f6c577d870b6f15d2f6e2a3a5b1b, reversing changes made to 414033aafa94cd50c9b310afd3f164740caccc94. + +- Merge pull request #578 from client9/remotes/trunk - b0c3977845f60747b15ae10531b7d20355a22627 + libinjection sync to v3.8.0 + +- libinjection sync - a5f175d79fac1e69124da4e1e227b622e7e233d7 + +- Merge pull request #152 from client9/remotes/trunk - 88ebf8a0bdbc4db1be76f3a2e70df77cc52a5925 + Sync to libinjection v3.7.1 + +- libinjection sync - fcb6dc13ed6efb066fb9b70405eecab8b83a2d96 + +- libinjection sync - f52242a013f301ca5c17e59b662124833cb7cc6d + +- Merge pull request #148 from zimmerle/bugfix_charset_missing_string_terminator - b76e26d81ddafc2b99bffad53d1426f8fd33080a + Bugfix: missing string terminator while mounting the charset (nginx) + +- Bugfix: missing string terminator while mounting the charset (nginx) - ff19dcd5c53d4af61d0a9397d4616f47f80ee207 + The charset in headers is mounted using ngx_snprintf which does not place the string terminator. This patch adds the terminator at the end of the string. The size was correctly allocated, just missing the terminator. + +- Merge pull request #141 from client9/remotes/trunk - 9a630eea23a7ead4e77617c86dc937fd7a421a57 + libinjection sync to v3.6.0 + +- libinjection sync - 11217207e8f2e0cf15742273836399866971071a + +- Merge pull request #139 from chaizhenhua/remotes/trunk - 10fd40fb0d06f6c577d870b6f15d2f6e2a3a5b1b + Fixed fd leackage after reload + +- Merge pull request #138 from client9/remotes/trunk - 414033aafa94cd50c9b310afd3f164740caccc94 + libinjection sync + +- Fixed fd leackage after reload - e0993fcd7a166ce9e1a279a47d050af1311d9001 + +- libinjection sync - 2268626c20260e88cab9b7830f8a06101fa7172a + +- Fix logical disjunction and conjunction issues - 7e0a9ecf7d492e85650671a0cfcfd53e5f15df2c + +Security Issues: + +- Fix Chunked string case sensitive issue - CVE-2013-5705 - f8d441cd25172fdfe5b613442fedfc0da3cc333d + (Thanks Martin Holst Swende - @mhswende) + +- Revert "Fix Chuncked string case sensitive issue" - 3901128f17e0763ac1a260106b79859d2aad6d90 + This reverts commit 16a815a3c2735f62238ef99af26090a2b8430d3d. + +- Fix Chuncked string case sensitive issue - 16a815a3c2735f62238ef99af26090a2b8430d3d + + + +23 Jul 2013 - 2.7.5 +------------------- +Improvements: + + * SecUnicodeCodePage is deprecated. SecUnicodeMapFile now accepts the code page as a second parameter. + + * Updated Libinjection to version 3.4.1. Many improvements were made. + + * Severity action now supports strings (emergency, alert, critical, error, warning, notice, info, debug). + +Bug Fixes: + + * Fixed utf8toUnicode tfn null byte conversion. + + * Fixed NGINX crash when issue reload command. + + * Fixed flush output buffer before inject modified hashed response body. + + * Fixed url normalization for Hash Engine. + + * Fixed NGINX ap_unixd_set_global_perms_mutex compilation error with apache 2.4 devel files. + +Security Issues: + +10 May 2013 - 2.7.4 +------------------- +Improvements: + + * Added Libinjection project http://www.client9.com/projects/libinjection/ as a new operator @detectSQLi. (Thanks Nick Galbreath). + + * Added new variable SDBM_DELETE_ERROR that will be set to 1 when sdbm engine fails to delete entries. + + * NGINX is now set to STABLE. Thanks chaizhenhua and all the people in community who help the project testing, sending feedback and patches. + +Bug Fixes: + + * Fixed SecRulePerfTime storing unnecessary rules performance times. + + * Fixed Possible SDBM deadlock condition. + + * Fixed Possible @rsub memory leak. + + * Fixed REMOTE_ADDR content will receive the client ip address when mod_remoteip.c is present. + + * Fixed NGINX Audit engine in Concurrent mode was overwriting existing alert files because a issue with UNIQUE_ID. + + * Fixed CPU 100% issue in NGINX port. This is also related to an memory leak when loading response body. + +Security Issues: + + * Fixed Remote Null Pointer DeReference (CVE-2013-2765). When forceRequestBodyVariable action is triggered and a unknown Content-Type is used, + mod_security will crash trying to manipulate msr->msc_reqbody_chunks->elts however msr->msc_reqbody_chunks is NULL. (Thanks Younes JAAIDI). + +28 Mar 2013 - 2.7.3 +------------------- + + * Fixed IIS version race condition when module is initialized. + + * Fixed IIS version failing config commands in libapr. + + * Nginx version is now RC quality. The rule engine should works for all phases. + We fixed many issues and missing features (for more information please check jira). + Code is running well with latest Nginx 1.2.7 stable. + Thanks chaizhenhua for your help. + + * Added MULTIPART_NAME and MULTIPART_FILENAME. Should be used soon by CRS + and will help prevent attacks using multipart data. + + * Added --enable-htaccess-config configure option. It will allow the follow directives + to be used into .htaccess files when AllowOverride Options is set: + + - SecAction + - SecRule + + - SecRuleRemoveByMsg + - SecRuleRemoveByTag + - SecRuleRemoveById + + - SecRuleUpdateActionById + - SecRuleUpdateTargetById + - SecRuleUpdateTargetByTag + - SecRuleUpdateTargetByMsg + + * Improvements in the ID duplicate code checking. Should be faster now. + + * SECURITY: Added SecXmlExternalEntity (On|Off - default it Off) that will disable + by default the external entity load task executed by LibXml2. This is a security issue + [CVE-2013-1915] reported by Timur Yunusov, Alexey Osipov (Positive Technologies). + +21 Jan 2013 - 2.7.2 +------------------- + + * IIS version is now stable. + + * Fixed IIS version does not pass through POST data to ASP.NET when SecRequestBodyAccess + is set to On (MODSEC-372). + + * Fixed IIS version HTTP Request Smuggling protection does not work (MODSEC-344). + + * Fixed IIS version PHP Injection Attack (958976) protection does not work (MODSEC-346). + + * Fixed IIS version Request limit protections are not working (MODSEC-349). + + * Fixed IIS version Outbound protections are not working (MODSEC-350). + + * Added IIS version better installer. + + * NGINX version removed ModSecurityPassCommand (Thanks chaizhenhua). + + * Fixed NGINX version ngx_http_read_client_request_body returned unexpected buffer type (Thanks chaizhenhua). + + * Fixed NGINX version INCS config directories on fedora (Thanks chaizhenhua). + + * Added NGINX version Added drop action for nginx (Thanks chaizhenhua). + + * Fixed bug in cpf_verify operator (Thanks Hideaki Hayashi). + + * Fixed build modsecurity under Arch Linux. + + * Fixed make test crashing when JIT pcre is enabled. + + * Fixed better cookie separator detection code. + + * Fixed mod_security displaying wrong ip address in error.log using apache 2.4 and mod_remoteip. + + * Fixed mod_security was not compiling when use apr without ipv6 support. + + * Fixed mod_security was not compiling when use lua 5.2. + + * Fixed issue when execute make install under Solaris. + + * Fixed ipmatchf operator was not working as expected. + +01 Nov 2012 - 2.7.1 +------------------- + + * Changed "Encryption" name of directives and options related to hmac feature to "Hash". + + SecEncryptionEngine to SecHashEngine + SecEncryptionKey to SecHashKey + SecEncryptionParam to SecHashParam + SecEncryptionMethodRx to SecHashMethodRx + SecEncryptionMethodPm to SecHashMethodPm + @validateEncryption to @validateHash + ctl:EncryptionEnforcement to ctl:HashEnforcement + ctl:EncryptionEngine to ctl:HashEngine + + * Added a better random bytes generator using apr_generate_random_bytes() to create + the HMAC key. + + * Fixed byte conversion issue during logging under Linux s390x platform. + + * Fixed compilation bug with LibXML2 2.9.0 (Thanks Athmane Madjoudj). + + * Fixed parsing error with modsecurity-recommended.conf and Apache 2.4. + + * Fixed DROP action was disabled for Apache 2 module by mistake. + + * Fixed bug when use ctl:ruleRemoveTargetByTag. + + * Fixed IIS and NGINX modules bugs. + + * Fixed bug when @strmatch patterns use invalid escape sequence (Thanks Hideaki Hayashi). + + * Fixed bugs in @verifySSN (Thanks Hideaki Hayashi). + + * The doc/ directory now contains the instructions to access online documentation. + +15 Oct 2012 - 2.7.0 +------------------- + + * Fixed Pause action should work as a disruptive action (MODSEC-297). + + * Fixed Problem loading mod_env variables in phase 2 (MODSEC-226). + + * Fixed Detect cookie v0 separator and use it for parsing (MODSEC-261). + + * Fixed Variable REMOTE_ADDR with wrong IP address in NGINX version (MODSEC-337). + + * Fixed Errors compiling NGINX version. + + * Added Include directive into standalone module. IIS and NGINX module should + support Include directive like Apache2. + + * Added MULTIPART_INVALID_PART flag. Also used in rule id 200002 for multipart strict + validation. https://www.sec-consult.com/fxdata/seccons/prod/temedia/advisories_txt/20121017-0_mod_security_ruleset_bypass.txt). + + * Updated Reference Manual. + +25 Sep 2012 - 2.6.8 +------------------- + + * Fixed ctl:ruleRemoveTargetByID order issue (MODSEC-333). Thanks to Armadillo Dasypodidae. + + * Fixed variable HIGHEST_SEVERITY incorrectly gets reset in a chain rule (MODSEC-315). Thanks to Valery Reznic. + +10 Sep 2012 - 2.7.0-rc3 +------------------- + + * Fixed requests bigger than SecRequestBodyNoFilesLimit were truncated even engine mode was detection only. + + * Fixed double close() for multipart temporary files (Thanks Seema Deepak). + + * Fixed many small issues reported by Coverity Scanner (Thanks Peter Vrabek). + + * Fixed format string issue in ngnix experimental code. (Thanks Eldar Zaitov). + + * Added ctl:ruleRemoveTargetByTag/Msg and removed ctl:ruleUpdateTargetByTag/Msg. + + * Added IIS and Ngnix platform code. + + * Added new transformation utf8toUnicode. + +23 Jul 2012 - 2.6.7 +------------------- + + * Fixed explicit target replacement using SecUpdateTargetById was broken. + + * The ctl:ruleUpdateTargetById is deprecated and will be removed for future versions since + there is no safe way to use it per-request. + + * Added ctl:ruleRemoveTargetById that can be used to exclude targets to be processed per-request. + +22 Jun 2012 - 2.7.0-rc2 +------------------- + + * Fixed compilation errors and warnings under Windows platform. + + * Fixed SecEncryptionKey was not working as expected. + +08 Jun 2012 - 2.7.0-rc1 +------------------- + + * Added SecEncryptionEngine. Initial crypt engine support, at the momment it will sign some Html + and Response Header options. + + * Added SecEncryptionKey to define the a rand or static key for crypt engine. + + * Added SecEncryptionParam to define the new parameter name. + + * Added SecEncryptionMethodRx used with a regular expression to inspect the html in response + body/header and decide what to protect. + + * Added SecEncryptionMethodPm used with multiple or single strings to inspect the html in response + body/header and decide what to protect. + + * Added ctl encryptionEngine as a per transaction version of SecEncryptionEgine diretive. + + * Added ctl encryptionEnforcement that will allow the engine to sign the data but the enforcement is + disabled. + + * Added validateEncryption operator to enforce the signed elements. + + * Added rsub operator supports the syntax |hex| allowing users to use special chars like \n \r. + + * Added SecRuleUpdateTargetById now supports id range. + + * Added SecRuleUpdateTargetByMsg and its ctl version (Thanks Scott Gifford). + + * Added SecRuleUpdateTargetByTag and its ctl version (Thanks Scott Gifford). + + * Added SecRulePerfTime when greater than zero it will fill rule id's execution time into PERF_RULE + and log id=usec information in the new Perf-rule-info: line in part H. + + * Added PERF_RULES variable that contains rule execution time. + + * Added Engine-mode: section in part H. + + * Added ruleRemoveByMsg ctl version. + + * Added removeCommentsChar and removeComments now can work with style. + + * Added SecArgumentSeparator and SecCookieFormat can be used in different scope locations. + + * Added Rules must have ID action and must be numeric. + + * Added The use of tfns are deprecated in SecDefaultAction. Should be forbid in the future. + + * Added Macro expansion support to the action pause. + + * Added IpmatchFromFile/IpmatchF operator. + + * Added New setrsc action, the RESOURCE collection used SecWebAppId Name Space + + * Added Configure option --enable-cache-lua that allows reuse of Lua VM per transaction. + It will only take any effect when ModSecurity has multiple scripts to run per transaction. + + * Added Configure option --enable-pcre-jit that allows ModSecurity regex engine to use PCRE Jit support. + + * Added Configure option --enable-request-early that allows ModSecurity run phase 1 in post_read_request hook. + + * Added RBL operator now support the httpBl api (http://www.projecthoneypot.org/httpbl_api.php). + + * Added SecHttpBlKey to be used with httpBl api. + + * Added SecSensorId will specify the modsecurity sensor name into audit log part H. + + * Added aliases to phase:2 (phase:request), phase:4 (phase:response) and phase:5 (phase:logging). + + * Added USERAGENT_IP variable. Created when Apache24 is used with mod_remoteip to know the real + client ip address. + + ^ Added new rule metadata actions ver, maturity and accuracy. Also included into RULE collection. + + * Updated Reference manual into doc/ directory. + + * Fixed Variable DURATION contains the elapsed time in microseconds for compatible reasons with apache and + other variables. + + * Fixed Preserve names/identity of the variables going into MATCHED_VARS. + + * Fixed Redirect macro expansion does not work in SecDefaultAction when SecRule uses block action. + + * Fixed rsub operator does not work as expect if regex contains parentheses (Thanks Jerome Freilinger). + + * Current Google Safe Browsing implementation is deprecated. Google changed the API and does not allow + anymore the malware database for download. + +08 Jun 2012 - 2.6.6 +------------------- + + * Added build system support for KfreeBSD and HURD. + + * Fixed a multipart bypass issue related to quote parsing + Credits to Qualys Vulnerability & Malware Research Labs (VMRL). + +20 Mar 2012 - 2.6.5 +------------------- + + * Fixed increased a specific message debug level in SBDM code (MODSEC-293). + + * Cleanup build system. + +09 Mar 2012 - 2.6.4 +------------------- + + * Fixed Mlogc 100% CPU consume (Thanks Klaubert Herr and Ebrahim Khalilzadeh). + + * Fixed ModSecurity cannot load session and user sdbm data. + + * Fixed updateTargetById was creating rule unparsed content making apache memory grow. + + * Code cleanup. + +23 Feb 2012 - 2.6.4-rc1 +------------------- + + * Fixed @rsub adding garbage data into stream variables. + + * Fixed regex for section A into mlogc-batch-load.pl (Thanks Ebrahim Khalilzadeh). + + * Fixed logdata cuts message without closing it with final chars. + + * Added sanitizeMatchedBytes support to verifyCPF, verifyCC and verifySSN. + + +06 Dec 2011 - 2.6.3-rc1 +------------------- + +* Fixed MATCHED_VARS does not correctly handle multiple VARS with the same name. + +* Fixed SDBM garbage collection was not working as expected, increasing the size of files. + +* Fixed wrong timestamp calculation for some time zones in log files. + +* Fixed SecUpdateTargetById failed to load multiple VARS (MODSEC-270). + +* Fixed Reverted hexDecode for hexEncode compatibility reason. + +* Added SecCollectionTimeout to set collection timeout, default is 3600. + +* Added sqlHexDecode transformation to decode sql hex data. Thanks Marc Stern. + +30 Sep 2011 - 2.6.2 +------------------- + + * Fixed hexDecode test during make. + + * Updated the reference manual into doc/ directory. + +5 Sep 2011 - 2.6.2-rc1 +------------------- + + * Added support to macro expansion for rx operator. + + * Added new transformations removeComments and removeCommentsChars + + * Fixed colletion names are not case-sensitive anymore. + + * Fixed compilation errors with apache 2.0. + + * Fixed build system was not using some libraries CFLAGS. + + * Fixed check for valid hex values into hexDecode transformation. + + * Fixed ctl:ruleUpdateTargetById appending multiple targets. + +18 Jun 2011 - 2.6.1 +------------------- + + * Updated the reference manual into doc/ directory. + +11 Jul 2011 - trunk +------------------- + + * Add HttpBl support to rbl operator. + +30 Jun 2011 - 2.6.1-rc1 +------------------- + + * Fixed SecUploadFileMode doesn't work with the new build system. + + * Fixed building with Lua library (Thanks Diego Elio). + + * Fixed some ./configure --enable* features not being enabled in compilation time. + + * Improvements on GSB database add/search operations. + + * Log part K was removed from modsecurity.conf-recommended. + + * Added SecUnicodeMapFile directive. Must be use to load the unicode.mapping file. + + * Added SecUnicodeCodePage directive. Used to define the unicode code page. There are a few already available: + + 1250 (ANSI - Central Europe) + 1251 (ANSI - Cyrillic) + 1252 (ANSI - Latin I) + 1253 (ANSI - Greek) + 1254 (ANSI - Turkish) + 1255 (ANSI - Hebrew) + 1256 (ANSI - Arabic) + 1257 (ANSI - Baltic) + 1258 (ANSI/OEM - Viet Nam) + 20127 (US-ASCII) + 20261 (T.61) + 20866 (Russian - KOI8) + 28591 (ISO 8859-1 Latin I) + 28592 (ISO 8859-2 Central Europe) + 28605 (ISO 8859-15 Latin 9) + 37 (IBM EBCDIC - U.S./Canada) + 437 (OEM - United States) + 500 (IBM EBCDIC - International) + 850 (OEM - Multilingual Latin I) + 860 (OEM - Portuguese) + 861 (OEM - Icelandic) + 863 (OEM - Canadian French) + 865 (OEM - Nordic) + 874 (ANSI/OEM - Thai) + 932 (ANSI/OEM - Japanese Shift-JIS) + 936 (ANSI/OEM - Simplified Chinese GBK) + 949 (ANSI/OEM - Korean) + 950 (ANSI/OEM - Traditional Chinese Big5) + + Also mapping some extra unicode chars defined at http://tools.ietf.org/html/rfc3490#section-3.1 + + * Fixed SecRequestBodyLimit was truncating the real request body. + +18 May 2011 - 2.6.0 +------------------- + + * Added SecWriteStateLimit for Slow Post DoS mitigation. + + * Fix problem when buffering in input filter. + + * Fix memory leak when use MATCHED_VAR_NAMES. + + +2 May 2011 - 2.6.0-rc2 +------------------- + + * Added code optimizations - thanks Diego Elio. + + * Added support to AIX and HPUX in the build system (untested). + + * Renamed decodeBase64Ext to base64DecodeExt. + + * Build system improvements - thanks Diego Elio. + + * Improvements on gsblookup parser. + + * Fixed input filter bug when upload files and SecStreamInBodyInspect is enabled. + + * Logging improvements and bug fix. + + * Remove extra useless files when make clean and maintainer-clean + +18 Apr 2011 - 2.6.0-rc1 +------------------- + + * Replaced previous GPLv2 License to Apachev2. + + * Added Google Safe Browsing lookups operator and directive. It should be + used to extract and lookup urls from http packets. + + * Added Data Modification operator. It must be used with STREAM_* variables + to replace/add/edit any data from http bodies. + + * Added STREAM_OUPUT_BODY and STREAM_INPUT_BODY variables to work with data + modification operators. + + * Added fast ip address operator. It supports partial ip address, cidr for + IPv4 and IPv6. Thanks Tom Donovan. + + * Added new sensitive data tracking verifyCPF and verifySSN. + + * Added MATCHED_VARS and MATCHED_VARS_NAMES. It is similiar to MATCHED_VAR, + but now we should see all matched variables. + + * Added UNIQUE_ID variable. It holds the data created my mod_unique_id. + + * Added new tranformation cmdline. Thanks Marc Stern. + + * Added new exception handling operators and directives. It should help users + reduce FN and FPs. The directives SecRuleUpdateTargetById, SecRuleRemoveByTag + and its ctl actions were included. + + * Added SecStreamOutBodyInspection and SecStreamInBodyInspection to enable STREAM_* + variables. + + * Added SecGsbLookupDB used to load Google Safe Browsing malware databse into + memory. + + * Added the directive SecInterceptOnError to control what to do if a rule returns + values less than zero. + + * Improvements in DetectionOnly engine mode. Also added SecRequestBodyLimitAction + to control what to do if the engine receive a http request over a hard limit. + Note that there is now many combinations with SecRuleEngine and the limit action + directives for response and request data. Please see the reference manual. + + * Improvements under RBL operator. It now will parse return code values for some + RBL lists. + + * Added new Log Part J. It should log some informations about uploaded files. + + * Added new sanitizeMatchedBytes action. It will give more flexibilty for user to sanitize + logged data, also improving peformance when sanitize big amount of data. + + * Improvements on Logging phase. It is possible now see full chains, distinguish between + simple rules, chain starters and chain nodes. + + * Improvements on AutoTools usage. + + * Improvements on pattern matching operators, pmf, pm and strmatch now supports more flexible + input data allowing any kind of special char. + + * Improvements on SecRuleUpdateActionById to update chain nodes. + + * Many bugs were fixed. Please see the ModSecurity Jira for more details + + +19 Mar 2010 - trunk +------------------- + + * Added SecDisableBackendCompression, which disabled backend compression + while keeping the frontend compression enabled (assuming mod_deflate + in installed and configured in the proxy). [Ivan Ristic] + + * Added REQUEST_BODY_LENGTH, which contains the number of request body + bytes read. [Ivan Ristic] + + * Integrate with mod_log_config using the %{VARNAME}M format string. + (MODSEC-108) [Ivan Ristic] + + * Replaced the previous time-measuring mechanism with a new one, which + provides the following information: request time, request duration, + phase duration (for all 5 phases), time spent dealing with persistent + storage, and time spent on audit logging. The new information is now + available in the Stopwatch2 audit log header. The Stopwatch header + remains for backward compatiblity, although it now only includes + the request time and request duration values. Added the following + variables: PERF_COMBINED, PERF_PHASE1, PERF_PHASE2, PERF_PHASE3, + PERF_PHASE4, PERF_PHASE5, PERF_SREAD, PERF_SWRITE, PERF_LOGGING, + PERF_GC. [Ivan Ristic] + + * Added DURATION, which contains the time ellapsed since the beginning + of the current transaction, in milliseconds. [Ivan Ristic] + + * Adjusted phase 5 to execute just prior to mod_log_config. This should + allow phase 5 rules to to implement conditional logging, as well as + pave support for allowing access to all ModSecurity variables from + mog_log_config. [Ivan Ristic] + + * Added the URLENCODED_ERROR flag, which is raised whenever invalid URL + encoding is encountered in the query string or in the request body + (but only if URLENCODED request body processor is used). (MODSEC-111) + [Ivan Ristic] + + * Removed the obsolete PDF UXSS functionality. (MODSEC-96) [Ivan Ristic] + + * Renamed normalisePath to normalizePath and normalisePathWin to + normalizePathWin. Kept the previous names for backward compatibility. + (MODSEC-103) [Ivan Ristic] + + * Moved phase 1 to be run in the same Apache hook as phase 2. This means + that you can now have phase 1 rules in tags and, more + importantly, override server configuration in and others. + (MODSEC-98) [Ivan Ristic] + + * Renamed the sanitise family of actions to sanitize. Kept the old variants + for backward compatibility. (MODSEC-95) [Ivan Ristic] + + * Improve the logging of the ctl action. (MODSEC-99) [Ivan Ristic] + + * Cleanup build files that were from the Apache source. + + +14 Feb 2010 - 2.5.13-dev1 +------------------------- + + * Cleaned up some mlogc code and debugging output. + + * Remove the ability to use a relative path to a piped audit logger + (i.e. mlogc) as Apache does not support it in their piped loggers + and it was breaking Windows and probably other platforms that + use spaces in filesystem paths. Discovered by Tom Donovan. + + * Fix memory leak freeing regex. Discovered by Tom Donovan. + + * Fix some portability issues on Windows. + + +04 Feb 2010 - 2.5.12 +-------------------- + + * Fixed SecUploadFileMode to set the correct mode. + + * Fixed nolog,auditlog/noauditlog/nolog controls for disruptive actions. + + * Added additional file info definitions introduced in APR 0.9.5 so that + build will work with older APRs (IBM HTTP Server v6). + + * Added SecUploadFileLimit to limit the number of uploaded file parts that + will be processed in a multipart POST. The default is 100. + + * Fixed path normalization to better handle backreferences that extend + above root directories. Reported by Sogeti/ESEC R&D. + + * Trim whitespace around phrases used with @pmFromFile and allow + for both LF and CRLF terminated lines. + + * Allow for more robust parsing for multipart header folding. Reported + by Sogeti/ESEC R&D. + + * Fixed failure to match internally set TX variables with regex + (TX:/.../) syntax. + + * Fixed failure to log full internal TX variable names and populate + MATCHED_VAR* vars. + + * Enabled PCRE "studying" by default. This is now a configure-time option. + + * Added PCRE match limits (SecPcreMatchLimit/SecPcreMatchLimitRecursion) to + aide in REDoS type attacks. A rule that goes over the limits will set + TX:MSC_PCRE_LIMITS_EXCEEDED. It is intended that the next major release + of ModSecurity (2.6.x) will move these flags to a dedicated collection. + + * Reduced default PCRE match limits reducing impact of REDoS on poorly + written regex rules. Reported by Sogeti/ESEC R&D. + + * Fixed memory leak in v1 cookie parser. Reported by Sogeti/ESEC R&D. + + * Now support macro expansion in numeric operators (@eq, @ge, @lt, etc.) + + * Update copyright to 2010. + + * Reserved 700,000-799,999 IDs for Ivan Ristic. + + * Fixed SecAction not working when CONNECT request method is used + (MODSEC-110). [Ivan Ristic] + + * Do not escape quotes in macro resolution and only escape NUL in setenv + values. + + +04 Nov 2009 - 2.5.11 +-------------------- + + * Added a new multipart flag, MULTIPART_INVALID_QUOTING, which will be + set true if any invalid quoting is found during multipart parsing. + + * Fixed parsing quoted strings in multipart Content-Disposition headers. + Discovered by Stefan Esser. + + * Cleanup persistence database locking code. + + * Added warning during configure if libcurl is found linked against + gnutls for SSL. The openssl lib is recommended as gnutls has + proven to cause issues with mutexes and may crash. + + * Cleanup some mlogc (over)logging. + + * Do not log output filter errors in the error log. + + * Moved output filter to run before other stock filters (mod_deflate, + mod_cache, mod_expires, mod_filter) to avoid analyzing modified data + in the response. Patch originally submitted by Ivan Ristic. + + +18 Sep 2009 - 2.5.10 +-------------------- + + * Cleanup mlogc so that it builds on Windows. + + * Added more detailed messages to replace "Unknown error" in filters. + + * Added SecAuditLogDirMode and SecAuditLogFileMode to allow fine tuning + auditlog permissions (especially with mpm-itk). + + * Cleanup SecUploadFileMode implementation. + + * Cleanup build scripts. + + * Fixed crash on configuration if SecMarker is used before any rules. + + * Fixed SecRuleUpdateActionById so that it will work on chain starters. + + * Cleanup build system for mlogc. + + * Allow mlogc to periodically flush memory pools. + + * Using nolog,auditlog will now log the "Message:" line to the auditlog, but + nothing to the error log. Prior versions dropped the "Message:" line from + both logs. To do this now, just use "nolog" or "nolog,noauditlog". + + * Forced mlogc to use SSLv3 to avoid some potential auto negotiation + issues with some libcurl versions. + + * Fixed mlogc issue seen on big endian machines where content type + could be listed as zero. + + * Removed extra newline from audit log message line when logging XML errors. + This was causing problems parsing audit logs. + + * Fixed @pm/@pmFromFile case insensitivity. + + * Truncate long parameters in log message for "Match of ... against ... + required" messages. + + * Correctly resolve chained rule actions in logs. + + * Cleanup some code for portability. + + * AIX does not support hidden visibility with xlc compiler. + + * Allow specifying EXTRA_CFLAGS during configure to override gcc specific + values for non-gcc compilers. + + * Populate GEO:COUNTRY_NAME and GEO:COUNTRY_CONTINENT as documented. + + * Handle a newer geo database more gracefully, avoiding a potential crash for + new countries that ModSecurity is not yet aware. + + * Allow checking &GEO "@eq 0" for a failed @geoLookup. + + * Fixed mlogc global mutex locking issue and added more debugging output. + + * Cleaned up build dependencies and configure options. + + +05 Mar 2009 - 2.5.9 +------------------- + + * Fixed parsing multipart content with a missing part header name which + would crash Apache. Discovered by "Internet Security Auditors" + (isecauditors.com). + + * Added ability to specify the config script directly using --with-apr + and --with-apu. + + * Updated copyright year to 2009. + + * Added macro expansion for append/prepend action. + + * Fixed race condition in concurrent updates of persistent counters. Updates + are now atomic. + + * Cleaned up build, adding an option for verbose configure output and making + the mlogc build more portable. + + +21 Nov 2008 - 2.5.8 +------------------- + + * Fixed PDF XSS issue where a non-GET request for a PDF file would crash the + Apache httpd process. Discovered by Steve Grubb at Red Hat. + + * Removed an invalid "Internal error: Issuing "%s" for unspecified error." + message that was logged when denying with nolog/noauditlog set and + causing the request to be audited. + + +24 Sep 2008 - 2.5.7 +------------------- + + * Fixed XML DTD/Schema validation which will now fail after request body + processing errors, even if the XML parser returns a document tree. + + * Added ctl:forceRequestBodyVariable=on|off which, when enabled, will force + the REQUEST_BODY variable to be set when a request body processor is not set. + Previously the REQUEST_BODY target was only populated by the URLENCODED + request body processor. + + * Integrated mlogc source. + + * Fixed logging the hostname in the error_log which was logging the + request hostname instead of the Apache resolved hostname. + + * Allow for disabling request body limit checks in phase:1. + + * Added transformations for processing parity for legacy protocols ported + to HTTP(S): t:parityEven7bit, t:parityOdd7bit, t:parityZero7bit + + * Added t:cssDecode transformation to decode CSS escapes. + + * Now log XML parsing/validation warnings and errors to be in the debug log + at levels 3 and 4, respectivly. + + +31 Jul 2008 - 2.5.6 +------------------- + + * Transformation caching has been deprecated, and is now off by default. We + now advise against using transformation caching in production. + + * Fixed two separate transformation caching issues that could cause incorrect + content inspection in some circumstances. + + * Fixed an issue with the transformation cache using too much RAM, potentially + crashing Apache with a large number of cache entries. Two new configuration + options have been added to allow for a finer control of caching: + + maxitems: Max number of items to cache (default 1024) + incremental: Whether to cache incrementally (default off) + + * Added an experimental regression testing suite. The regression suite may + be executed via "make test-regression", however it is strongly advised + to only be executed on a non-production machine as it will startup the + Apache web server that ModSecurity is compiled against with various + configurations in which it will run tests. + + * Added a licensing exception so that ModSecurity can be used in a derivative + work when that derivative is also under an approved open source license. + + * Updated mlogc to version 1.4.5 which adds a LockFile directive and fixes an + issue in which the configuration file may be deleted. + + +05 Jun 2008 - 2.5.5 +------------------- + + * Fixed an issue where an alert was not logged in the error log + unless "auditlog" was used. + + * Enable the "auditlog" action by default to help prevent a misconfiguration. + The new default is now: "phase:2,log,auditlog,pass" + + * Improve request body processing error messages. + + * Handle lack of a new line after the final boundary in a multipart request. + This fixes the reported WordPress Flash file uploader problem. + + * Fixed issue with multithreaded servers where concurrent XML processing + could crash the web server (at least under Windows). + + * Fixed blocking in phase 3. + + * Force modules "mod_rpaf-2.0.c" and "mod_custom_header.c" to run before + ModSecurity so that the correct IP is used. + + +07 May 2008 - 2.5.4 +------------------- + + * Fixed issue where transformation cache was using the SecDefaultAction + value even when t:none was used within a rule. + + +24 Apr 2008 - 2.5.3 +------------------- + + * Fixed issue where the exec action may not be able to execute shell scripts. + + * Macros are now expanded in expirevar and deprecatevar. + + * Fixed crash if a persistent variable name was more than 126 characters. + + * Updated included Core Ruleset to version 1.6.1 which fixes some + false negative issues in the migration to using some 2.5 features. + + +02 Apr 2008 - 2.5.2 +------------------- + + * Allow HTTP_* targets as an alias for REQUEST_HEADERS:*. + + * Make sure temporary filehandles are closed after a transaction. + + * Make sure the apache include directory is included during build. + + +02 Apr 2008 - 2.1.7 +------------------- + + * Make sure temporary filehandles are closed after a transaction. + + +14 Mar 2008 - 2.5.1 +------------------- + + * Fixed an issue where a match would not occur if transformation caching + was enabled. + + * Using "severity" in a default action is now just a warning. + + * Cleaned up the "make test" target to better locate headers/libraries. + + * Now search /usr/lib64 and /usr/lib32 for lua libs. + + * No longer treat warnings as errors by default (use --enable-strict-compile). + + +19 Feb 2008 - 2.5.0 +------------------- + + * Updated included Core Ruleset to version 1.6.0 which uses 2.5 features. + + * Cleaned up and clarified some documentation. + + * Updated code to be more portable so it builds with MS VC++. + + * Added unit tests for most operators and transformations. + + * Fixed crash on startup when ENV is improperly used without a parameter. + + * Allow macro resolution in setenv action. + + * The default action is now a minimal "phase:2,log,pass" with no default + transformations performed. + + * Implemented SecUploadFileMode to allow setting the mode for uploaded files. + + * Implemented "block" action. + + * Implemented SecRuleUpdateActionById. + + * Fixed removal of phase 5 rules via SecRuleRemoveBy* directives. + + * No longer log the query portion of the URI in the error log as + it may contain sensitive data. + + * Build is now 'configure' based: ./configure && make && make install + + * Added support for Lua scripting in the following ways: SecRuleScript + can be used to specify a script to execute as a rule, the exec + action processes Lua scripts internally, as does the @inspectFile + operator. Refer to the documentation for more details. + + * Changed how allow works. Used on its own it now allows phases 1-4. Used + with parameter "phase" (e.g. SecAction allow:phase) it only affects + the current phase. Used with parameter "request" it allows phases + 1-2. + + * Fixed issue where only the first phase 5 rule would run when the + request was intercepted in an earlier phase. + + * Stricter configuration parsing. Disruptive actions, meta actions and + phases are no longer allowed in a chained rule. Disruptive actions, + are no longer allowed in a logging phase (phase 5) rule, including + inheriting from SecDefaultAction. + + * More efficient collection persistance. + + * Fixed t:escapeSeqDecode to better follow ANSI C escapes. + + * Added t:jsDecode to decode JavScript escape sequences. + + * Added IS_NEW built-in collection variables. + + * New audit log part 'K' logs all matching rules. + + * Implemented SecRequestBodyNoFilesLimit. + + * Enhance handling of the case where we run out of disk space while + writing to audit log entry. + + * Added SecComponentSignature to allow other components the ability + to append to the logged signature. + + * Added skipAfter: action to allow skipping all rules until a rule + with a specified ID is reached. Rule execution then continues after + the specified rule. + + * Added SecMarker directive to allow a fixed target for skipAfter. + + * Added ctl:ruleRemoveById action to allow rule removal on a match. + + * Added a @containsWord operator that will match a given string anywhere in + the target value, but only on word boundaries. + + * Added a MATCHED_VAR_NAME variable to store the last matched variable name + so that it can be more easily used by rules. + + * Added a MATCHED_VAR variable to store the last matched variable value + so that it can be more easily used by rules. + + * Fixed expansion of macros when using relative changes with setvar. In + addition, added support for expanding macros in the variable name. + + * Situations where ModSecurity will intercept, generate an error or log + a level 1-3 message to the debug log are now marked as 'relevant' and may + generate an audit log entry. + + * Fixed deprecatevar:var=N/S action so that it decrements N every S seconds + as documented instead of decrementing by a rate. + + * Enable ModSecurity to look at partial response bodies. In previous + versions, ModSecurity would respond with status code 500 when the + response body was too long. Now, if SecResponseBodyLimitAction is + set to "ProcessPartial", it will process the part of the response + body received up until that point but send the rest without buffering. + + * ModSecurity will now process phases 3 and 4 even when request processing + is interrupted (either by Apache - e.g. by responding with 400, 401 + or 403, or by ModSecurity itself). + + * Fixed the base64decode transformation function to not return extra + characters at the end. + + * Return from the output filter with an error in addition to setting + up the HTTP error status in the output data. + + * Used new Apache API calls to get the server version/banner when available. + + * Added "logdata" meta action to allow logging of raw transaction data. + + * Added TX_SEVERITY that keeps track of the highest severity + for any matched rules so far. + + * Added ARGS_GET, ARGS_POST, ARGS_GET_NAMES, ARGS_POST_NAMES variables to + allow seperation of GET and POST arguments. + + * Added an Apache define (MODSEC_2.5) so that you can conditionally include + directives based on the ModSecurity major/minor versions with IfDefine. + + * Added MODSEC_BUILD variable that contains the numeric build value based + on the ModSecurity version. + + * Enhanced debug logging by displaying more data on rule execution. All + invoked rules are now logged in the debug log at level 5. + + * Stricter validation for @validateUtf8Encoding. + + * No longer process Apache internal subrequests. + + * Fixed warnings on Solaris and/or 64bit builds. + + * Added @within string comparison operator with support for macro expansion. + + * Do not trigger "pause" action for internal requests. + + * Added matching rule filename and line number to audit log. + + * Added new phrase matching operators, @pm and @pmFromFile. These use + an alternate set based matching engine (Aho-Corasick) to perform faster + phrase type matches such as black/white lists, spam keywords, etc. + + * Allow caching transformations per-request/phase so they are not repeated. + + * Added Solaris and Cygwin to the list of platforms not supporting the hidden + visibility attribute. + + * Fixed decoding full-width unicode in t:urlDecodeUni. + + * Add SecGeoLookupDB, @geoLookups and GEO collection to support + geographical lookups by IP/host. + + * Do not try to intercept a request after a failed rule. This fixes the + issue associated with an "Internal Error: Asked to intercept request + but was_intercepted is zero" error message. + + * Removed extraneous exported symbols. + + * Merged the PDF XSS protection functionality into ModSecurity. + + * Exported API for registering custom variables. Example in api directory. + + * Added experimental support for content injection. Directive + SecContentInjection (On|Off) controls whether injection is taking place. + Actions "prepend" and "append" inject content when executed. Do note that + it is your responsibility to make sure the response is of the appropriate + content type (e.g. HTML, plain text, etc). + + * Added string comparison operators with support for macro expansion: + @contains, @streq, @beginsWith and @endsWith. + + * Enhanced debug log output to log macro expansion, quote values and + correctly display values that contained NULs. + + * Removed support for %0 - %9 capture macros as they were incorrectly + expanding url encoded values. Use %{TX.0} - %{TX.9} instead. + + * Added t:length to transform a value to its character length. + + * Added t:trimLeft, t:trimRight, t:trim to remove whitespace + from a value on the left, right or both. + + * Added SecAuditLog2 directive to allow redundent concurrent audit log + index files. This will allow sending audit data to two consoles, etc. + + * Removed CGI style HTTP_* variables in favor of REQUEST_HEADERS:Header-Name. + + * Store filename/line for each rule and display it and the ID (if available) + in the debug log when invoking a rule. Thanks to Christian Bockermann + for the idea. + + * Do not log 'allow' action as intercepted in the debug log. + + * Fixed some collection variable names not printing with the parameter + and/or counting operator in the debug log. + + +19 Feb 2008 - 2.1.6 +------------------- + + * Fixed crash on startup when ENV is improperly used without a parameter. + + * Allow macro resolution in setenv action. + + * Implemented SecUploadFileMode to allow setting the mode for uploaded files. + + * No longer log the query portion of the URI in the error log as + it may contain sensitive data. + + +10 Jan 2008 - 2.1.5 +------------------- + + * Updated included Core Ruleset to version 1.5.1. + + * Phase 5 rules can now be removed via SecRuleRemoveBy* directives. + + * Fixed issue where only the first phase 5 rule would run when the + request was intercepted in an earlier phase. + + * Fixed configuration parsing so that disruptive actions, meta actions + and phases are not allowed in a chained rule (as originally intended). + + * Fixed t:escapeSeqDecode to better follow ANSI C escapes. + + +27 Nov 2007 - 2.1.4 +------------------- + + * Updated included Core Ruleset to version 1.5 and noted in the docs that + XML support is required to use the rules without modification. + + * Fixed an evasion FP, mistaking a multipart non-boundary for a boundary. + + * Fixed multiple warnings on Solaris and/or 64bit builds. + + * Do not process subrequests in phase 2-4, but do hand off the request data. + + * Fixed a blocking FP in the multipart parser, which affected Safari. + + +11 Sep 2007 - 2.1.3 +------------------- + + * Updated multipart parsing code adding variables to allow checking + for various parsing issues (request body abnormalities). + + * Allow mod_rpaf and mod_extract_forwarded2 to work before ModSecurity. + + * Quiet some compiler warnings. + + * Do not block internal ErrorDocument requests after blocking request. + + * Added ability to compile without an external API (use -DNO_MODSEC_API). + + +27 Jul 2007 - 2.1.2 +------------------- + + * Cleaned up and clarified some documentation. + + * Update included core rules to latest version (1.4.3). + + * Enhanced ability to alert/audit failed requests. + + * Do not trigger "pause" action for internal requests. + + * Fixed issue with requests that use internal requests. These had the + potential to be intercepted incorrectly when other Apache httpd modules + that used internal requests were used with mod_security. + + * Added Solaris and Cygwin to the list of platforms not supporting the hidden + visibility attribute. + + * Fixed decoding full-width unicode in t:urlDecodeUni. + + * Lessen some overhead of debugging messages and calculations. + + * Do not try to intercept a request after a failed rule. This fixes the + issue associated with an "Internal Error: Asked to intercept request + but was_intercepted is zero" error message. + + * Added SecAuditLog2 directive to allow redundent concurrent audit log + index files. This will allow sending audit data to two consoles, etc. + + * Small performance improvement in memory management for rule execution. + + +11 Apr 2007 - 2.1.1 +------------------- + + * Add the PCRE_DOLLAR_ENDONLY option when compiling regular expression + for the @rx operator and variables. + + * Really set PCRE_DOTALL option when compiling the regular expression + for the @rx operator as the docs state. + + * Fixed potential memory corruption when expanding macros. + + * Fixed error when a collection was retrieved from storage in the same second + as creation by setting the rate to zero. + + * Fixed ASCIIZ (NUL) parsing for application/x-www-form-urlencoded forms. + + * Fixed the faulty REQUEST_FILENAME variable, which used to change + the internal Apache structures by mistake. + + * Updates to quiet some compiler warnings. + + * Fixed some casting issues for compiling on NetWare (patch from Guenter Knauf). + + +23 Feb 2007 - 2.1.0 +------------------- + + * Removed the "Connection reset by peer" message, which has nothing + to do with us. Actually the message was downgraded from ERROR to + NOTICE so it will still appear in the debug log. + + * Removed the (harmless) message mentioning LAST_UPDATE_TIME missing. + + * It was not possible to remove a rule placed in phase 4 using + SecRuleRemoveById or SecRuleRemoveByMsg. Fixed. + + * Fixed a problem with incorrectly setting requestBodyProcessor using + the ctl action. + + * Bundled Core Rules 2.1-1.3.2b4. + + * Updates to the reference manual. + + * Reversed the return values of @validateDTD and @validateSchema, to + make them consistent with other operators. + + * Added a few helpful debug messages in the XML validation area. + + * Updates to the reference manual. + + * Fixed the validateByteRange operator. + + * Default value for the status action is now 403 (as it was supposed to + be but it was effectively 500). + + * Rule exceptions (removing using an ID range or an regular expression) + is now applied to the current context too. (Previously it only worked + on rules that are inherited from the parent context.) + + * Fix of a bug with expired variables. + + * Fixed regular expression variable selectors for many collections. + + * Performance improvements - up to two times for real-life work loads! + + * Memory consumption improvements (not measured but significant). + + * The allow action did not work in phases 3 and 4. Fixed. + + * Unlocked collections GLOBAL and RESOURCE. + + * Added support for variable expansion in the msg action. + + * New feature: It is now possible to make relative changes to the + audit log parts with the ctl action. For example: "ctl:auditLogParts=+E". + + * New feature: "tag" action. To be used for event categorisation. + + * XML parser was not reporting errors that occured at the end + of XML payload. + + * Files were not extracted from request if SecUploadKeepFiles was + Off. Fixed. + + * Regular expressions that are too long are truncated to 256 + characters before used in error messages. (In order to keep + the error messages in the log at a reasonable size.) + + * Fixed the sha1 transformation function. + + * Fixed the skip action. + + * Fixed REQUEST_PROTOCOL, REMOTE_USER, and AUTH_TYPE. + + * SecRuleEngine did not work in child configuration contexts + (e.g. ). + + * Fixed base64Decode and base64Encode. + + +15 Nov 2006 - 2.0.4 +------------------- + + * Fixed the "deprecatevar" action. + + * Decreasing variable values did not work. + + * Made "nolog" do what it is supposed to do - cause a rule match to + not be logged. Also "nolog" now implies "noauditlog" but it's + possible to follow "nolog" with "auditlog" and have the match + not logged to the error log but logged to the auditlog. (Not + something that strikes me as useful but it's possible.) + + * Relative paths given to SecDataDir will now be treated as relative + to the Apache server root. + + * Added checks to make sure only correct actions are specified in + SecDefaultAction (some actions are required, some don't make any + sense) and in rules that are not chain starters (same). This should + make the unhelpful "Internal Error: Failed to add rule to the ruleset" + message go away. + + * Fixed the problem when "SecRuleInheritance Off" is used in a context + with no rules defined. + + * Fixed a problem of lost input (request body) data on some redirections, + for example when mod_rewrite is used. + + +26 Oct 2006 - 2.0.3 +------------------- + + * Fixed a memory leak (all platforms) and a concurrency control + problem that could cause a crash (multithreaded platforms only). + + * Fixed a SecAuditLogRelevantStatus problem, which would not work + properly unless the regular expression contained a subexpression. + + +19 Oct 2006 - 2.0.2 +------------------- + + * Fixed incorrect permissions on the global mutex, which prevented + the mutex from working properly. + + * Fixed incorrect actionset merging where the status was copied from + the child actionset even though it was not defined. + + * Fixed missing metadata information (in the logs) for warnings. + + +16 Oct 2006 - 2.0.1 +------------------- + + * Rules that used operator negation did not work. Fixed. + + * Fixed bug that prevented invalid regular expressions from being reported. + + +16 Oct 2006 - 2.0.0 +------------------- + + * First stable 2.x release. + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9135230 --- /dev/null +++ b/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + 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. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3a0e59b --- /dev/null +++ b/Makefile.am @@ -0,0 +1,52 @@ +ACLOCAL_AMFLAGS = -I build +SUBDIRS = @TOPLEVEL_SUBDIRS@ tests + +CLEANFILES = +MAINTAINERCLEANFILES = + +CLEANFILES += tests/regression/server_root/conf/*.t_*.conf \ + tests/regression/server_root/logs/*.log + +MAINTAINERCLEANFILES += $(CLEANFILES) \ + aclocal.m4 \ + alp2/Makefile.in \ + apache2/Makefile.in \ + build/config.guess \ + build/config.sub \ + build/depcomp \ + build/libtool.m4 \ + build/ltmain.sh \ + build/lt~obsolete.m4 \ + build/ltoptions.m4 \ + build/ltsugar.m4 \ + build/ltversion.m4 \ + build/missing \ + config.log \ + config.status \ + configure \ + ext/Makefile.in \ + Makefile \ + Makefile.in \ + mlogc/Makefile.in \ + modsecurity_config_auto.h.in~ + +test: check + +test-regression: + (cd tests && $(MAKE) test-regression) + +test-regression-nginx: + (cd tests && $(MAKE) test-regression-nginx) + + +cppcheck: + cppcheck . --enable=all --force 2>&1 | sed 's/^/warning: /g' 1>&2; + +check-coding-style: + for i in `(find . -iname "*.c" ; find . -iname "*.h")`; \ + do echo $$i...; \ + vera++ -rule L004 -param max-line-length=80 $$i 2>&1 | sed 's/^/warning: /g' 1>&2; \ + vera++ -rule L001 $$i 2>&1 | sed 's/^/warning: /g' 1>&2; \ + done; + +.PHONY: test diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..b19f6c8 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,938 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/find_apr.m4 \ + $(top_srcdir)/build/find_apu.m4 \ + $(top_srcdir)/build/find_curl.m4 \ + $(top_srcdir)/build/find_lua.m4 \ + $(top_srcdir)/build/find_pcre.m4 \ + $(top_srcdir)/build/find_ssdeep.m4 \ + $(top_srcdir)/build/find_xml.m4 \ + $(top_srcdir)/build/find_yajl.m4 \ + $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(am__DIST_COMMON) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/apache2/modsecurity_config_auto.h +CONFIG_CLEAN_FILES = nginx/modsecurity/config build/apxs-wrapper \ + tests/regression/misc/40-secRemoteRules.t \ + tests/regression/misc/50-ipmatchfromfile-external.t \ + tests/regression/misc/60-pmfromfile-external.t \ + tests/regression/server_root/conf/httpd.conf +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + cscope distdir dist dist-all distcheck +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +CSCOPE = cscope +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build/apxs-wrapper.in $(top_srcdir)/build/ar-lib \ + $(top_srcdir)/build/compile $(top_srcdir)/build/config.guess \ + $(top_srcdir)/build/config.sub $(top_srcdir)/build/install-sh \ + $(top_srcdir)/build/ltmain.sh $(top_srcdir)/build/missing \ + $(top_srcdir)/nginx/modsecurity/config.in \ + $(top_srcdir)/tests/regression/misc/40-secRemoteRules.t.in \ + $(top_srcdir)/tests/regression/misc/50-ipmatchfromfile-external.t.in \ + $(top_srcdir)/tests/regression/misc/60-pmfromfile-external.t.in \ + $(top_srcdir)/tests/regression/server_root/conf/httpd.conf.in \ + build/ar-lib build/compile build/config.guess build/config.sub \ + build/depcomp build/install-sh build/ltmain.sh build/missing +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__post_remove_distdir = $(am__remove_distdir) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +DIST_TARGETS = dist-gzip +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APR_CFLAGS = @APR_CFLAGS@ +APR_CONFIG = @APR_CONFIG@ +APR_CPPFLAGS = @APR_CPPFLAGS@ +APR_INCLUDEDIR = @APR_INCLUDEDIR@ +APR_LDADD = @APR_LDADD@ +APR_LDFLAGS = @APR_LDFLAGS@ +APR_LINKLD = @APR_LINKLD@ +APR_VERSION = @APR_VERSION@ +APU_CFLAGS = @APU_CFLAGS@ +APU_CONFIG = @APU_CONFIG@ +APU_INCLUDEDIR = @APU_INCLUDEDIR@ +APU_LDADD = @APU_LDADD@ +APU_LDFLAGS = @APU_LDFLAGS@ +APU_LINKLD = @APU_LINKLD@ +APU_VERSION = @APU_VERSION@ +APXS = @APXS@ +APXS_BINDIR = @APXS_BINDIR@ +APXS_CC = @APXS_CC@ +APXS_CFLAGS = @APXS_CFLAGS@ +APXS_EXTRA_CFLAGS = @APXS_EXTRA_CFLAGS@ +APXS_HTTPD = @APXS_HTTPD@ +APXS_INCLUDEDIR = @APXS_INCLUDEDIR@ +APXS_INCLUDES = @APXS_INCLUDES@ +APXS_LDFLAGS = @APXS_LDFLAGS@ +APXS_LIBDIR = @APXS_LIBDIR@ +APXS_LIBEXECDIR = @APXS_LIBEXECDIR@ +APXS_LIBS = @APXS_LIBS@ +APXS_LIBTOOL = @APXS_LIBTOOL@ +APXS_MODULES = @APXS_MODULES@ +APXS_PROGNAME = @APXS_PROGNAME@ +APXS_SBINDIR = @APXS_SBINDIR@ +APXS_WRAPPER = @APXS_WRAPPER@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURL_CFLAGS = @CURL_CFLAGS@ +CURL_CONFIG = @CURL_CONFIG@ +CURL_CPPFLAGS = @CURL_CPPFLAGS@ +CURL_LDADD = @CURL_LDADD@ +CURL_LDFLAGS = @CURL_LDFLAGS@ +CURL_USES_GNUTLS = @CURL_USES_GNUTLS@ +CURL_VERSION = @CURL_VERSION@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENV_CMD = @ENV_CMD@ +EXEEXT = @EXEEXT@ +EXTRA_CFLAGS = @EXTRA_CFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ +LIBXML2_CONFIG = @LIBXML2_CONFIG@ +LIBXML2_CPPFLAGS = @LIBXML2_CPPFLAGS@ +LIBXML2_LDADD = @LIBXML2_LDADD@ +LIBXML2_LDFLAGS = @LIBXML2_LDFLAGS@ +LIBXML2_VERSION = @LIBXML2_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LDADD = @LUA_LDADD@ +LUA_LDFLAGS = @LUA_LDFLAGS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MODSEC_APXS_EXTRA_CFLAGS = @MODSEC_APXS_EXTRA_CFLAGS@ +MODSEC_EXTRA_CFLAGS = @MODSEC_EXTRA_CFLAGS@ +MSC_BASE_DIR = @MSC_BASE_DIR@ +MSC_PKGBASE_DIR = @MSC_PKGBASE_DIR@ +MSC_REGRESSION_CONF_DIR = @MSC_REGRESSION_CONF_DIR@ +MSC_REGRESSION_DIR = @MSC_REGRESSION_DIR@ +MSC_REGRESSION_DOCROOT_DIR = @MSC_REGRESSION_DOCROOT_DIR@ +MSC_REGRESSION_LOGS_DIR = @MSC_REGRESSION_LOGS_DIR@ +MSC_REGRESSION_SERVERROOT_DIR = @MSC_REGRESSION_SERVERROOT_DIR@ +MSC_TEST_DIR = @MSC_TEST_DIR@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_CONFIG = @PCRE_CONFIG@ +PCRE_CPPFLAGS = @PCRE_CPPFLAGS@ +PCRE_LDADD = @PCRE_LDADD@ +PCRE_LDFLAGS = @PCRE_LDFLAGS@ +PCRE_LD_PATH = @PCRE_LD_PATH@ +PCRE_VERSION = @PCRE_VERSION@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSDEEP_CFLAGS = @SSDEEP_CFLAGS@ +SSDEEP_LDADD = @SSDEEP_LDADD@ +SSDEEP_LDFLAGS = @SSDEEP_LDFLAGS@ +STRIP = @STRIP@ +TOPLEVEL_SUBDIRS = @TOPLEVEL_SUBDIRS@ +VERSION = @VERSION@ +YAJL_CFLAGS = @YAJL_CFLAGS@ +YAJL_LDADD = @YAJL_LDADD@ +YAJL_LDFLAGS = @YAJL_LDFLAGS@ +YAJL_LIBS = @YAJL_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +ACLOCAL_AMFLAGS = -I build +SUBDIRS = @TOPLEVEL_SUBDIRS@ tests +CLEANFILES = tests/regression/server_root/conf/*.t_*.conf \ + tests/regression/server_root/logs/*.log +MAINTAINERCLEANFILES = $(CLEANFILES) aclocal.m4 alp2/Makefile.in \ + apache2/Makefile.in build/config.guess build/config.sub \ + build/depcomp build/libtool.m4 build/ltmain.sh \ + build/lt~obsolete.m4 build/ltoptions.m4 build/ltsugar.m4 \ + build/ltversion.m4 build/missing config.log config.status \ + configure ext/Makefile.in Makefile Makefile.in \ + mlogc/Makefile.in modsecurity_config_auto.h.in~ +all: all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): +nginx/modsecurity/config: $(top_builddir)/config.status $(top_srcdir)/nginx/modsecurity/config.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +build/apxs-wrapper: $(top_builddir)/config.status $(top_srcdir)/build/apxs-wrapper.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tests/regression/misc/40-secRemoteRules.t: $(top_builddir)/config.status $(top_srcdir)/tests/regression/misc/40-secRemoteRules.t.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tests/regression/misc/50-ipmatchfromfile-external.t: $(top_builddir)/config.status $(top_srcdir)/tests/regression/misc/50-ipmatchfromfile-external.t.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tests/regression/misc/60-pmfromfile-external.t: $(top_builddir)/config.status $(top_srcdir)/tests/regression/misc/60-pmfromfile-external.t.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +tests/regression/server_root/conf/httpd.conf: $(top_builddir)/config.status $(top_srcdir)/tests/regression/server_root/conf/httpd.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscope: cscope.files + test ! -s cscope.files \ + || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) +clean-cscope: + -rm -f cscope.files +cscope.files: clean-cscope cscopelist +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + -rm -f cscope.out cscope.in.out cscope.po.out cscope.files + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__post_remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__post_remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__post_remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + +dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__post_remove_distdir) + +dist-shar: distdir + @echo WARNING: "Support for shar distribution archives is" \ + "deprecated." >&2 + @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__post_remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__post_remove_distdir) + +dist dist-all: + $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' + $(am__post_remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) + mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build/sub \ + && ../../configure \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + --srcdir=../.. --prefix="$$dc_install_base" \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__post_remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--refresh check check-am clean clean-cscope clean-generic \ + clean-libtool cscope cscopelist-am ctags ctags-am dist \ + dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ + dist-xz dist-zip distcheck distclean distclean-generic \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +test: check + +test-regression: + (cd tests && $(MAKE) test-regression) + +test-regression-nginx: + (cd tests && $(MAKE) test-regression-nginx) + +cppcheck: + cppcheck . --enable=all --force 2>&1 | sed 's/^/warning: /g' 1>&2; + +check-coding-style: + for i in `(find . -iname "*.c" ; find . -iname "*.h")`; \ + do echo $$i...; \ + vera++ -rule L004 -param max-line-length=80 $$i 2>&1 | sed 's/^/warning: /g' 1>&2; \ + vera++ -rule L001 $$i 2>&1 | sed 's/^/warning: /g' 1>&2; \ + done; + +.PHONY: test + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0501be9 --- /dev/null +++ b/NOTICE @@ -0,0 +1,5 @@ + ModSecurity (www.modsecurity.org) +    Copyright [2004-2013] Trustwave Holdings, Inc + +    This product includes software developed at +    Trustwave Holdings, Inc (http://www.trustwave.com/). diff --git a/README.TXT b/README.TXT new file mode 100644 index 0000000..03767e3 --- /dev/null +++ b/README.TXT @@ -0,0 +1,110 @@ +ModSecurity for Apache 2.x, http://www.modsecurity.org/ +Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) + +You may not use this file except in compliance with +the License.  You may obtain a copy of the License at + +    http://www.apache.org/licenses/LICENSE-2.0 + +If any of the files related to licensing are missing or if you have any +other questions related to licensing please contact Trustwave Holdings, Inc. +directly using the email address security@modsecurity.org. + + +DOCUMENTATION + +Please refer to the documentation folder (/doc) for +the reference manual. + + +############################################## +---------------------------------- +OWASP ModSecurity Core Rule Set (CRS) + + +Project Site: +https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project + + +Download: +https://github.com/SpiderLabs/owasp-modsecurity-crs + +---------------------------------- + +ModSecurity™ is a web application firewall engine that provides very +little protection on its own. In order to become useful, ModSecurity™ must +be configured with rules. In order to enable users to take full advantage +of ModSecurity™ out of the box, Trustwave's SpiderLabs is providing a free +certified rule set for ModSecurity™ 2.x. Unlike intrusion detection and +prevention systems, which rely on signatures specific to known +vulnerabilities, the Core Rules provide generic protection from unknown +vulnerabilities often found in web applications, which are in most cases +custom coded. The Core Rules are heavily commented to allow it to be used +as a step-by-step deployment guide for ModSecurity™. +Core Rules Content + +In order to provide generic web applications protection, the Core Rules +use the following techniques: + +* HTTP Protection - detecting violations of the HTTP protocol and a +locally defined usage policy. +* Real-time Blacklist Lookups - utilizes 3rd Party IP Reputation +* Web-based Malware Detection - identifies malicious web content by check +against the Google Safe Browsing API. +* HTTP Denial of Service Protections - defense against HTTP Flooding and +Slow HTTP DoS Attacks. +* Common Web Attacks Protection - detecting common web application +security attack. +* Automation Detection - Detecting bots, crawlers, scanners and other +surface malicious activity. +* Integration with AV Scanning for File Uploads - detects malicious files +uploaded through the web application. +* Tracking Sensitive Data - Tracks Credit Card usage and blocks leakages. +* Trojan Protection - Detecting access to Trojans horses. +* Identification of Application Defects - alerts on application +misconfigurations. +* Error Detection and Hiding - Disguising error messages sent by the +server. + + +---------------------------------- +ModSecurity Rules from Trustwave SpiderLabs + +Project Site: +https://www.trustwave.com/modsecurity-rules-support.php + +Download: +https://ssl.trustwave.com/web-application-firewall + +---------------------------------- + + + +Trustwave now provides a commercial certified rule set for ModSecurity 2.x +that protects against known attacks that target vulnerabilities in public +software and are based on intelligence gathered from real-world +investigations, honeypot data and research. + +1. More than 16,000 specific rules, broken out into the following attack +categories: + * SQL injection + * Cross-site Scripting (XSS) + * Local File Include + * Remote File Include + +2. User option for application specific rules, covering the same +vulnerability classes for applications such as: + * WordPress + * cPanel + * osCommerce + * Joomla + * For a complete listing of application coverage, please refer to this +link (which is updated daily). +https://modsecurity.org/application_coverage.html + +3. Complements and integrates with the OWASP Core Rule Set +4. IP Reputation capabilities which provide protection against malicious +clients identified by the Trustwave SpiderLabs Distributed Web Honeypots +5. Malware Detection capabilities which prevent your web site from +distributing malicious code to clients. +############################################## diff --git a/README_WINDOWS.TXT b/README_WINDOWS.TXT new file mode 100644 index 0000000..94c2bc9 --- /dev/null +++ b/README_WINDOWS.TXT @@ -0,0 +1,192 @@ +===================================================================== +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/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..872d429 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1501 @@ +# generated automatically by aclocal 1.15 -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. + +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +dnl serial 11 (pkg-config-0.29.1) +dnl +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.1]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.15' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.15], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.15])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# Copyright (C) 2011-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_AR([ACT-IF-FAIL]) +# ------------------------- +# Try to determine the archiver interface, and trigger the ar-lib wrapper +# if it is needed. If the detection of archiver interface fails, run +# ACT-IF-FAIL (default is to abort configure with a proper error message). +AC_DEFUN([AM_PROG_AR], +[AC_BEFORE([$0], [LT_INIT])dnl +AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([ar-lib])dnl +AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false]) +: ${AR=ar} + +AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface], + [AC_LANG_PUSH([C]) + am_cv_ar_interface=ar + AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])], + [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=ar + else + am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([am_ar_try]) + if test "$ac_status" -eq 0; then + am_cv_ar_interface=lib + else + am_cv_ar_interface=unknown + fi + fi + rm -f conftest.lib libconftest.a + ]) + AC_LANG_POP([C])]) + +case $am_cv_ar_interface in +ar) + ;; +lib) + # Microsoft lib, so override with the ar-lib wrapper script. + # FIXME: It is wrong to rewrite AR. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__AR in this case, + # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something + # similar. + AR="$am_aux_dir/ar-lib $AR" + ;; +unknown) + m4_default([$1], + [AC_MSG_ERROR([could not determine $AR interface])]) + ;; +esac +AC_SUBST([AR])dnl +]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Expand $ac_aux_dir to an absolute path. +am_aux_dir=`cd "$ac_aux_dir" && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Older Autoconf quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "$am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. +m4_define([AC_PROG_CC], +m4_defn([AC_PROG_CC]) +[_AM_PROG_CC_C_O +]) + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.65])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[AC_DIAGNOSE([obsolete], + [$0: two- and three-arguments forms are deprecated.]) +m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +# For better backward compatibility. To be removed once Automake 1.9.x +# dies out for good. For more background, see: +# +# +AC_SUBST([mkdir_p], ['$(MKDIR_P)']) +# We need awk for the "check" target (and possibly the TAP driver). The +# system "awk" is bad on some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [m4_define([AC_PROG_CC], + m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [m4_define([AC_PROG_CXX], + m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [m4_define([AC_PROG_OBJC], + m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], + [_AM_DEPENDENCIES([OBJCXX])], + [m4_define([AC_PROG_OBJCXX], + m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl +]) +AC_REQUIRE([AM_SILENT_RULES])dnl +dnl The testsuite driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This +dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl + +# POSIX will say in a future version that running "rm -f" with no argument +# is OK; and we want to be able to make that assumption in our Makefile +# recipes. So use an aggressive probe to check that the usage we want is +# actually supported "in the wild" to an acceptable degree. +# See automake bug#10828. +# To make any issue more visible, cause the running configure to be aborted +# by default if the 'rm' program in use doesn't match our expectations; the +# user can still override this though. +if rm -f && rm -fr && rm -rf; then : OK; else + cat >&2 <<'END' +Oops! + +Your 'rm' program seems unable to run without file operands specified +on the command line, even when the '-f' option is present. This is contrary +to the behaviour of most rm programs out there, and not conforming with +the upcoming POSIX standard: + +Please tell bug-automake@gnu.org about your system, including the value +of your $PATH and any error possibly output before this message. This +can help us improve future automake versions. + +END + if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then + echo 'Configuration will proceed anyway, since you have set the' >&2 + echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 + echo >&2 + else + cat >&2 <<'END' +Aborting the configuration process, to ensure you take notice of the issue. + +You can download and install GNU coreutils to get an 'rm' implementation +that behaves properly: . + +If you want to complete the configuration process using your problematic +'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM +to "yes", and re-run configure. + +END + AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) + fi +fi +dnl The trailing newline in this macro's definition is deliberate, for +dnl backward compatibility and to allow trailing 'dnl'-style comments +dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it is modern enough. +# If it is, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --is-lightweight"; then + am_missing_run="$MISSING " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_CC_C_O +# --------------- +# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC +# to automatically call this. +AC_DEFUN([_AM_PROG_CC_C_O], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +AC_LANG_PUSH([C])dnl +AC_CACHE_CHECK( + [whether $CC understands -c and -o together], + [am_cv_prog_cc_c_o], + [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) + # Make sure it works both with $CC and with simple cc. + # Following AC_PROG_CC_C_O, we do the test twice because some + # compilers refuse to overwrite an existing .o file with -o, + # though they will create one. + am_cv_prog_cc_c_o=yes + for am_i in 1 2; do + if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ + && test -f conftest2.$ac_objext; then + : OK + else + am_cv_prog_cc_c_o=no + break + fi + done + rm -f core conftest* + unset am_i]) +if test "$am_cv_prog_cc_c_o" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +AC_LANG_POP([C])]) + +# For backward compatibility. +AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_RUN_LOG(COMMAND) +# ------------------- +# Run COMMAND, save the exit status in ac_status, and log it. +# (This has been adapted from Autoconf's _AC_RUN_LOG macro.) +AC_DEFUN([AM_RUN_LOG], +[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD + ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + (exit $ac_status); }]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2009-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# ("yes" being less verbose, "no" or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], [dnl +AS_HELP_STRING( + [--enable-silent-rules], + [less verbose build output (undo: "make V=1")]) +AS_HELP_STRING( + [--disable-silent-rules], + [verbose build output (undo: "make V=0")])dnl +]) +case $enable_silent_rules in @%:@ ((( + yes) AM_DEFAULT_VERBOSITY=0;; + no) AM_DEFAULT_VERBOSITY=1;; + *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few 'make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using '$V' instead of '$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2014 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +# +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) + +# We'll loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' + +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + + [m4_case([$1], + [ustar], + [# The POSIX 1988 'ustar' format is defined with fixed-size fields. + # There is notably a 21 bits limit for the UID and the GID. In fact, + # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 + # and bug#13588). + am_max_uid=2097151 # 2^21 - 1 + am_max_gid=$am_max_uid + # The $UID and $GID variables are not portable, so we need to resort + # to the POSIX-mandated id(1) utility. Errors in the 'id' calls + # below are definitely unexpected, so allow the users to see them + # (that is, avoid stderr redirection). + am_uid=`id -u || echo unknown` + am_gid=`id -g || echo unknown` + AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) + if test $am_uid -le $am_max_uid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi + AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) + if test $am_gid -le $am_max_gid; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + _am_tools=none + fi], + + [pax], + [], + + [m4_fatal([Unknown tar format])]) + + AC_MSG_CHECKING([how to create a $1 tar archive]) + + # Go ahead even if we have the value already cached. We do so because we + # need to set the values for the 'am__tar' and 'am__untar' variables. + _am_tools=${am_cv_prog_tar_$1-$_am_tools} + + for _am_tool in $_am_tools; do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works. + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi + done + rm -rf conftest.dir + + AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) + AC_MSG_RESULT([$am_cv_prog_tar_$1])]) + +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([build/find_apr.m4]) +m4_include([build/find_apu.m4]) +m4_include([build/find_curl.m4]) +m4_include([build/find_lua.m4]) +m4_include([build/find_pcre.m4]) +m4_include([build/find_ssdeep.m4]) +m4_include([build/find_xml.m4]) +m4_include([build/find_yajl.m4]) +m4_include([build/libtool.m4]) +m4_include([build/ltoptions.m4]) +m4_include([build/ltsugar.m4]) +m4_include([build/ltversion.m4]) +m4_include([build/lt~obsolete.m4]) diff --git a/alp2/Makefile.am b/alp2/Makefile.am new file mode 100644 index 0000000..aaab629 --- /dev/null +++ b/alp2/Makefile.am @@ -0,0 +1,13 @@ +lib_LTLIBRARIES = libalp2.la + +include_HEADERS = alp2.h \ + alp2_pp.h + +libalp2_la_SOURCES = alp2.c \ + alp2_pp.c + +libalp2_la_CFLAGS = @APR_CFLAGS@ \ + @APU_CFLAGS@ + +libalp2_la_LDFLAGS = @APR_LDFLAGS@ \ + @APU_LDFLAGS@ diff --git a/alp2/Makefile.in b/alp2/Makefile.in new file mode 100644 index 0000000..9c7073f --- /dev/null +++ b/alp2/Makefile.in @@ -0,0 +1,785 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = alp2 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/find_apr.m4 \ + $(top_srcdir)/build/find_apu.m4 \ + $(top_srcdir)/build/find_curl.m4 \ + $(top_srcdir)/build/find_lua.m4 \ + $(top_srcdir)/build/find_pcre.m4 \ + $(top_srcdir)/build/find_ssdeep.m4 \ + $(top_srcdir)/build/find_xml.m4 \ + $(top_srcdir)/build/find_yajl.m4 \ + $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/apache2/modsecurity_config_auto.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libalp2_la_LIBADD = +am_libalp2_la_OBJECTS = libalp2_la-alp2.lo libalp2_la-alp2_pp.lo +libalp2_la_OBJECTS = $(am_libalp2_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libalp2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libalp2_la_CFLAGS) \ + $(CFLAGS) $(libalp2_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/apache2 +depcomp = $(SHELL) $(top_srcdir)/build/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libalp2_la_SOURCES) +DIST_SOURCES = $(libalp2_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(include_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/build/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APR_CFLAGS = @APR_CFLAGS@ +APR_CONFIG = @APR_CONFIG@ +APR_CPPFLAGS = @APR_CPPFLAGS@ +APR_INCLUDEDIR = @APR_INCLUDEDIR@ +APR_LDADD = @APR_LDADD@ +APR_LDFLAGS = @APR_LDFLAGS@ +APR_LINKLD = @APR_LINKLD@ +APR_VERSION = @APR_VERSION@ +APU_CFLAGS = @APU_CFLAGS@ +APU_CONFIG = @APU_CONFIG@ +APU_INCLUDEDIR = @APU_INCLUDEDIR@ +APU_LDADD = @APU_LDADD@ +APU_LDFLAGS = @APU_LDFLAGS@ +APU_LINKLD = @APU_LINKLD@ +APU_VERSION = @APU_VERSION@ +APXS = @APXS@ +APXS_BINDIR = @APXS_BINDIR@ +APXS_CC = @APXS_CC@ +APXS_CFLAGS = @APXS_CFLAGS@ +APXS_EXTRA_CFLAGS = @APXS_EXTRA_CFLAGS@ +APXS_HTTPD = @APXS_HTTPD@ +APXS_INCLUDEDIR = @APXS_INCLUDEDIR@ +APXS_INCLUDES = @APXS_INCLUDES@ +APXS_LDFLAGS = @APXS_LDFLAGS@ +APXS_LIBDIR = @APXS_LIBDIR@ +APXS_LIBEXECDIR = @APXS_LIBEXECDIR@ +APXS_LIBS = @APXS_LIBS@ +APXS_LIBTOOL = @APXS_LIBTOOL@ +APXS_MODULES = @APXS_MODULES@ +APXS_PROGNAME = @APXS_PROGNAME@ +APXS_SBINDIR = @APXS_SBINDIR@ +APXS_WRAPPER = @APXS_WRAPPER@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURL_CFLAGS = @CURL_CFLAGS@ +CURL_CONFIG = @CURL_CONFIG@ +CURL_CPPFLAGS = @CURL_CPPFLAGS@ +CURL_LDADD = @CURL_LDADD@ +CURL_LDFLAGS = @CURL_LDFLAGS@ +CURL_USES_GNUTLS = @CURL_USES_GNUTLS@ +CURL_VERSION = @CURL_VERSION@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENV_CMD = @ENV_CMD@ +EXEEXT = @EXEEXT@ +EXTRA_CFLAGS = @EXTRA_CFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ +LIBXML2_CONFIG = @LIBXML2_CONFIG@ +LIBXML2_CPPFLAGS = @LIBXML2_CPPFLAGS@ +LIBXML2_LDADD = @LIBXML2_LDADD@ +LIBXML2_LDFLAGS = @LIBXML2_LDFLAGS@ +LIBXML2_VERSION = @LIBXML2_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LDADD = @LUA_LDADD@ +LUA_LDFLAGS = @LUA_LDFLAGS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MODSEC_APXS_EXTRA_CFLAGS = @MODSEC_APXS_EXTRA_CFLAGS@ +MODSEC_EXTRA_CFLAGS = @MODSEC_EXTRA_CFLAGS@ +MSC_BASE_DIR = @MSC_BASE_DIR@ +MSC_PKGBASE_DIR = @MSC_PKGBASE_DIR@ +MSC_REGRESSION_CONF_DIR = @MSC_REGRESSION_CONF_DIR@ +MSC_REGRESSION_DIR = @MSC_REGRESSION_DIR@ +MSC_REGRESSION_DOCROOT_DIR = @MSC_REGRESSION_DOCROOT_DIR@ +MSC_REGRESSION_LOGS_DIR = @MSC_REGRESSION_LOGS_DIR@ +MSC_REGRESSION_SERVERROOT_DIR = @MSC_REGRESSION_SERVERROOT_DIR@ +MSC_TEST_DIR = @MSC_TEST_DIR@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_CONFIG = @PCRE_CONFIG@ +PCRE_CPPFLAGS = @PCRE_CPPFLAGS@ +PCRE_LDADD = @PCRE_LDADD@ +PCRE_LDFLAGS = @PCRE_LDFLAGS@ +PCRE_LD_PATH = @PCRE_LD_PATH@ +PCRE_VERSION = @PCRE_VERSION@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSDEEP_CFLAGS = @SSDEEP_CFLAGS@ +SSDEEP_LDADD = @SSDEEP_LDADD@ +SSDEEP_LDFLAGS = @SSDEEP_LDFLAGS@ +STRIP = @STRIP@ +TOPLEVEL_SUBDIRS = @TOPLEVEL_SUBDIRS@ +VERSION = @VERSION@ +YAJL_CFLAGS = @YAJL_CFLAGS@ +YAJL_LDADD = @YAJL_LDADD@ +YAJL_LDFLAGS = @YAJL_LDFLAGS@ +YAJL_LIBS = @YAJL_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libalp2.la +include_HEADERS = alp2.h \ + alp2_pp.h + +libalp2_la_SOURCES = alp2.c \ + alp2_pp.c + +libalp2_la_CFLAGS = @APR_CFLAGS@ \ + @APU_CFLAGS@ + +libalp2_la_LDFLAGS = @APR_LDFLAGS@ \ + @APU_LDFLAGS@ + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign alp2/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign alp2/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libalp2.la: $(libalp2_la_OBJECTS) $(libalp2_la_DEPENDENCIES) $(EXTRA_libalp2_la_DEPENDENCIES) + $(AM_V_CCLD)$(libalp2_la_LINK) -rpath $(libdir) $(libalp2_la_OBJECTS) $(libalp2_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalp2_la-alp2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libalp2_la-alp2_pp.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libalp2_la-alp2.lo: alp2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libalp2_la_CFLAGS) $(CFLAGS) -MT libalp2_la-alp2.lo -MD -MP -MF $(DEPDIR)/libalp2_la-alp2.Tpo -c -o libalp2_la-alp2.lo `test -f 'alp2.c' || echo '$(srcdir)/'`alp2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libalp2_la-alp2.Tpo $(DEPDIR)/libalp2_la-alp2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alp2.c' object='libalp2_la-alp2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libalp2_la_CFLAGS) $(CFLAGS) -c -o libalp2_la-alp2.lo `test -f 'alp2.c' || echo '$(srcdir)/'`alp2.c + +libalp2_la-alp2_pp.lo: alp2_pp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libalp2_la_CFLAGS) $(CFLAGS) -MT libalp2_la-alp2_pp.lo -MD -MP -MF $(DEPDIR)/libalp2_la-alp2_pp.Tpo -c -o libalp2_la-alp2_pp.lo `test -f 'alp2_pp.c' || echo '$(srcdir)/'`alp2_pp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libalp2_la-alp2_pp.Tpo $(DEPDIR)/libalp2_la-alp2_pp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alp2_pp.c' object='libalp2_la-alp2_pp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libalp2_la_CFLAGS) $(CFLAGS) -c -o libalp2_la-alp2_pp.lo `test -f 'alp2_pp.c' || echo '$(srcdir)/'`alp2_pp.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/alp2/alp2.c b/alp2/alp2.c new file mode 100755 index 0000000..8a40272 --- /dev/null +++ b/alp2/alp2.c @@ -0,0 +1,1418 @@ +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License.  You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include +#include +#include +#include +#include + +#include "alp2.h" + +#ifdef DEBUG +#define alp_debug(...) fprintf(stderr, __VA_ARGS__) +#else +#define alp_debug(...) +#endif /* DEBUG */ + +/** + * Add one error to the audit log entry. + */ +static void add_error(alp2_t *alp, int is_fatal, const char *text, ...) +{ + char *str = NULL; + va_list ap; + + if (is_fatal) { + alp->parse_error = 1; + } + + va_start(ap, text); + str = apr_pvsprintf(alp->auditlog->mp, text, ap); + va_end(ap); + + *(char **)apr_array_push(alp->errors) = str; +} + +/** + * Parse the Response-Body-Transformed trailer header. + */ +static int handle_part_H_parse_ResponseTFN(alp2_t *alp, const char *s) +{ + char *capture = NULL; + int ovector[33]; + int rc; + + // TODO This header is optional, but is not allowed to appear more than once. + + + return 1; +} + +/** + * Parse the Action trailer header. + */ +static int handle_part_H_parse_Action(alp2_t *alp, const char *s) +{ + char *capture = NULL; + int ovector[33]; + int rc; + + // TODO This header is optional, but is not allowed to appear more than once. + + alp->auditlog->was_intercepted = 1; + + rc = pcre_exec(alp->trailer_action_pattern, NULL, s, strlen(s), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part H: Failed to parse Action header"); + return -1; + } + + capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * 1], + ovector[2 * 1 + 1] - ovector[2 * 1]); + + alp->auditlog->intercept_phase = atoi(capture); + + return 1; +} + +/** + * Convert two hexadecimal characters into a character. + */ +static uint8_t x2c(uint8_t *what) +{ + register uint8_t digit; + + digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); + digit *= 16; + digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); + + return digit; +} + +/** + * Remove a layer of encoding from a string. This function needs to be used + * for every piece of data ModSecurity encoded for a message. + */ +static int remove_slashes(uint8_t *s) +{ + uint8_t *d = s; + + while(*s != '\0') { + if ((*s == '\\')&&(*(s + 1) != '\0')) { + s++; + + switch(*s) { + case 'b' : + *d = '\b'; + break; + case 'n' : + *d = '\n'; + break; + case 'r' : + *d = '\r'; + break; + case 't' : + *d = '\t'; + break; + case 'v' : + *d = '\v'; + break; + case '\\' : + *d = '\\'; + break; + case '"' : + *d = '"'; + break; + case 'x' : + if ( (*(s + 1) != '\0') + &&(*(s + 2) != '\0') + &&(isxdigit(*(s + 1))) + &&(isxdigit(*(s + 2))) + ) { + *d = x2c(s + 1); + s += 2; + } + else { + /* Invalid encoding. */ + return -1; + } + break; + default : + /* Invalid encoding. */ + return -1; + break; + } + } + else { + *d = *s; + } + + s++; + d++; + } + + *d = '\0'; + + return 1; +} + +/** + * Process one (ModSecurity message) meta-data fragment. + */ +static int handle_part_H_parse_Message_meta(alp2_t *alp, alp2_msg_t *message, + const char *l, const char *string_start, const char *string_end) +{ + const char *value; + + // XXX if ((*string_start != '"')||(*string_end != '"')||(string_end <= string_start)) { + if (string_end <= string_start) { + add_error(alp, 1, "Part H: Invalid handle_part_H_parse_Message_meta invocation"); + return -1; + } + + if ((*string_start != '"')||(*string_end != '"')) { + value = apr_pstrndup(alp->auditlog->mp, string_start, (string_end - string_start) + 1); + } + else { + value = apr_pstrndup(alp->auditlog->mp, string_start + 1, (string_end - string_start - 1)); + } + if (value == NULL) { + return -1; + } + + if (remove_slashes((uint8_t *)value) < 0) { + add_error(alp, 1, "Part H: Invalid encoding in meta-data fragment"); + return -1; + } + + /* Target ( at THE_TARGET) */ + if (strncmp(l, "at ", 3) == 0) { + if (message->target != NULL) { + add_error(alp, 1, "Part H: Already seen target"); + return -1; + } + + message->target = value; + + return 1; + } + + /* id */ + if (strncmp(l, "id ", 3) == 0) { + if (message->id != NULL) { + add_error(alp, 1, "Part H: Already seen meta-data: id"); + return -1; + } + + message->id = value; + + return 1; + } + + /* rev */ + if (strncmp(l, "rev ", 4) == 0) { + if (message->rev != NULL) { + add_error(alp, 1, "Part H: Already seen meta-data: rev"); + return -1; + } + + message->rev = value; + + return 1; + } + + /* msg */ + if (strncmp(l, "msg ", 4) == 0) { + if (message->msg != NULL) { + add_error(alp, 1, "Part H: Already seen meta-data: msg"); + return -1; + } + + message->msg = value; + + return 1; + } + + /* data */ + if (strncmp(l, "data ", 4) == 0) { + if (message->data != NULL) { + add_error(alp, 1, "Part H: Already seen meta-data: data"); + return -1; + } + + message->data = value; + + return 1; + } + + /* file */ + if (strncmp(l, "file ", 5) == 0) { + if (message->file != NULL) { + add_error(alp, 1, "Part H: Already seen meta-data: file"); + return -1; + } + + message->file = value; + + return 1; + } + + /* line */ + if (strncmp(l, "line ", 5) == 0) { + if (message->file_line != (unsigned long)-1) { + add_error(alp, 1, "Part H: Already seen meta-data: line"); + return -1; + } + + // TODO Validate. + message->file_line = atoi(value); + + return 1; + } + + /* tag */ + if (strncmp(l, "tag ", 4) == 0) { + *(char **)apr_array_push(message->tags) = (char *)value; + return 1; + } + + /* severity */ + if (strncmp(l, "severity ", 9) == 0) { + if ( (strcmp(value, "0") == 0) + ||(strcasecmp(value, "EMERGENCY") == 0)) + { + message->severity = 0; + return 1; + } + + if ( (strcmp(value, "1") == 0) + ||(strcasecmp(value, "ALERT") == 0)) + { + message->severity = 1; + return 1; + } + + if ( (strcmp(value, "2") == 0) + ||(strcasecmp(value, "CRITICAL") == 0)) + { + message->severity = 2; + return 1; + } + + if ( (strcmp(value, "3") == 0) + ||(strcasecmp(value, "ERROR") == 0)) + { + message->severity = 3; + return 1; + } + + if ( (strcmp(value, "4") == 0) + ||(strcasecmp(value, "WARNING") == 0)) + { + message->severity = 4; + return 1; + } + + if ( (strcmp(value, "5") == 0) + ||(strcasecmp(value, "NOTICE") == 0)) + { + message->severity = 5; + return 1; + } + + if ( (strcmp(value, "6") == 0) + ||(strcasecmp(value, "INFO") == 0)) + { + message->severity = 6; + return 1; + } + + if ( (strcmp(value, "7") == 0) + ||(strcasecmp(value, "DEBUG") == 0)) + { + message->severity = 7; + return 1; + } + + add_error(alp, 1, "Part H: Invalid severity value: %s", value); + + return -1; + } + + /* offset */ + if (strncmp(l, "offset ", 7) == 0) { + if (message->offset != (size_t)-1) { + /* Already seen "offset". */ + add_error(alp, 1, "Part H: Already seen fragment offset"); + return -1; + } + + // TODO Validate. + message->offset = atoi(value); + + return 1; + } + + /* Ignore unknown meta-data information. */ + + return 0; +} + +/** + * Parse the Message trailer header. More than one such header + * can exist in an audit log, and each represents one ModSecurity + * message. + */ +static int handle_part_H_parse_Message(alp2_t *alp, const char *s) +{ + alp2_msg_t *message = NULL; + char *l = (char *)(s + strlen(s) - 1); + char *engine_message_start = (char *)s; + char *engine_message_end = NULL; + char *string_start = NULL, *string_end = NULL; + char *fragment_end = NULL; + char *tptr; + int in_string; + int done; + + /* Create one new message structure. */ + message = apr_pcalloc(alp->auditlog->mp, sizeof(alp2_msg_t)); + if (message == NULL) { + return -1; + } + + message->file_line = (unsigned long)-1; + message->offset = (size_t)-1; + message->severity = -1; + message->warning = 0; + + if (strncasecmp("warning. ", s, 9) == 0) { + message->warning = 1; + engine_message_start += 9; + } + + message->tags = apr_array_make(alp->auditlog->mp, 4, sizeof(const char *)); + + /* Start at the end of the message and go back identifying + * the meta-data fragments as we go. Stop when we find the + * end of the engine message. + */ + done = in_string = 0; + while ((l >= s)&&(!done)) { + if (in_string == 0) { + /* Outside string. */ + + // TODO Make sure this is not an escaped char + switch(*l) { + case ' ' : + /* Do nothing. */ + break; + case ']' : + fragment_end = l; + break; + case '[' : + if (fragment_end) { + /* Found one meta-data fragment. */ + // TODO This parser implementation allows for invalid + // meta-data fragments to be accepted. It would be + // nice to check the format of the fragment (e.g. + // by matching it against a regular expression + // pattern) before we accept any data. At this point + // l points to the first byte of the fragment, and + // fragment_end to the last. + handle_part_H_parse_Message_meta(alp, message, + l + 1, string_start, string_end); + + fragment_end = NULL; + string_start = NULL; + string_end = NULL; + } + break; + case '"' : + /* Found the end of a string. */ + in_string = 1; + string_end = l; + break; + default : + if (!fragment_end) { + /* There are no more meta-data fragments. */ + engine_message_end = l; + done = 1; + } + break; + } + } + else { + /* In string. We are only interested + * in where the string ends. + */ + if ((*l == '"')&&((l - 1) >= s)&&(*(l - 1) != '\\')) { + in_string = 0; + string_start = l; + } + } + + l--; + } + + /* Target is between " at " and "." */ + tptr = engine_message_start; + while ((tptr = strstr(tptr, " at ")) && (tptr < engine_message_end)) { + char *tend = strchr(tptr, '.'); + if ((tend <= engine_message_end) && (tend - tptr > 5)) { + int rc = handle_part_H_parse_Message_meta(alp, message, tptr + 1, + tptr + 4, tend - 1); + if (rc == 1) { + /* Remove the target data from the message */ + engine_message_end = tptr; + } + } + break; + } + + if (engine_message_end == NULL) { + add_error(alp, 1, "Part H: Failed parsing ModSecurity message: %s", s); + return -1; + } + + message->engine_message = apr_pstrndup(alp->auditlog->mp, engine_message_start, (engine_message_end - engine_message_start + 1)); + + /* Add this message to the audit log. */ + *(alp2_msg_t **)apr_array_push(alp->auditlog->messages) = message; + + return 1; +} + +/** + * Parse the Stopwatch trailer header. + */ +static int handle_part_H_parse_Stopwatch(alp2_t *alp, const char *s) +{ + int ovector[33]; + int i, rc; + + // TODO This header is required (a check for its appearance is made when + // handling the end of an H part), and is not allowed to appear + // more than once. + + rc = pcre_exec(alp->trailer_stopwatch_pattern, NULL, s, strlen(s), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part H: Failed to parse Stopwatch header"); + return -1; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch (i) { + case 1 : /* timestamp */ + // TODO Validate + alp->auditlog->timestamp = apr_atoi64(capture); + break; + case 2 : /* duration */ + // TODO Validate + alp->auditlog->duration = apr_atoi64(capture); + break; + case 3 : /* ignore (group of three further time elements)*/ + break; + case 4 : /* t1 */ + break; + case 5 : /* t2 */ + break; + case 6 : /* t3 */ + break; + } + } + + return 1; +} + +/** + * Parse the WebApp-Info trailer header. + */ +static int handle_part_H_parse_WebAppInfo(alp2_t *alp, const char *s) +{ + int ovector[33]; + int i, rc; + + // TODO This header is optional, but it is not allowed to appear more than once. + + rc = pcre_exec(alp->trailer_webappinfo_pattern, NULL, s, strlen(s), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part H: Failed to parse WebApp-Info header"); + return -1; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, s + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch (i) { + case 1 : /* application ID */ + // TODO Validate + alp->auditlog->application_id = capture; + break; + case 2 : /* session ID */ + // TODO Validate + if (strcmp(capture, "-") != 0) { + alp->auditlog->session_id = capture; + } + break; + case 3 : /* user ID */ + // TODO Validate + if (strcmp(capture, "-") != 0) { + alp->auditlog->user_id = capture; + } + break; + } + } + + return 1; +} + +/** + * Handle part H events. + */ +static void handle_part_H(alp2_t *alp, int event_type) +{ + /* Part data. */ + if (event_type == ALP2_EVENT_PART_DATA) { + char *line = alp2_pp_line_chomp(alp->pp); + + /* This part ends with an empty line. */ + if (strlen(line) == 0) { + alp->part_data_done = 1; + return; + } + + /* Extract the header information. */ + { + char *name = NULL, *value = NULL; + int ovector[33]; + int i, rc; + + /* Header line. */ + + /* Extract the fields. */ + rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part H: Failed to parse header: %i", rc); + return; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 1 : + name = capture; + break; + case 2 : + value = capture; + break; + } + } + + /* Add header to the table. */ + apr_table_addn(alp->auditlog->trailer_headers, name, value); + } + + return; + } + + /* Part end. */ + if (event_type == ALP2_EVENT_PART_END) { + const apr_array_header_t *tarr = apr_table_elts(alp->auditlog->trailer_headers); + apr_table_entry_t *te = NULL; + const char *s = NULL; + int stopwatch = 0; + int rc = 0; + int i; + + if ((tarr == NULL) || (tarr->nelts == 0)) { + return; + } + + /* Here we are going to extract certain headers and + * parse them to populate the corresponding fields in + * the auditlog structure. + */ + + te = (apr_table_entry_t *)tarr->elts; + for (i = 0; i < tarr->nelts; i++) { + const char *key = te[i].key; + const char *val = te[i].val; + + if ((key == NULL) || (val == NULL)) { + continue; + } + + /* Action: optional */ + else if (strcmp("Action", key) == 0) { + rc = handle_part_H_parse_Action(alp, val); + } + + /* Message: optional */ + else if (strcmp("Message", key) == 0) { + rc = handle_part_H_parse_Message(alp, val); + } + + /* Apache-Handler: optional */ + else if (strcmp("Apache-Handler", key) == 0) { + rc = 0; + // TODO Only one allowed + alp->auditlog->handler = apr_pstrdup(alp->auditlog->mp, val); + } + + /* Producer: optional */ + else if (strcmp("Producer", key) == 0) { + rc = 0; + // TODO Only one allowed + alp->auditlog->producer = apr_pstrdup(alp->auditlog->mp, val); + } + + /* Server: optional */ + else if (strcmp("Server", key) == 0) { + rc = 0; + // TODO Only one allowed + alp->auditlog->server = apr_pstrdup(alp->auditlog->mp, val); + } + + /* Response-Body-Transformed: optional */ + else if (strcmp("Response-Body-Transformed", key) == 0) { + rc = 0; + // TODO Only one allowed + alp->auditlog->response_tfn = apr_pstrdup(alp->auditlog->mp, val); + } + + /* Stopwatch: required */ + else if (strcmp("Stopwatch", key) == 0) { + stopwatch = 1; + rc = handle_part_H_parse_Stopwatch(alp, val); + } + + /* WebApp-Info: optional */ + else if (strcmp("WebApp-Info", key) == 0) { + rc = handle_part_H_parse_WebAppInfo(alp, val); + } + + if (rc < 0) { + /* No need to report anything, it's already been reported. */ + } + } + + if (stopwatch == 0) { + add_error(alp, 1, "Part H: Stopwatch header missing"); + } + + return; + } +} + +/** + * Handle part F events. + */ +static void handle_part_F(alp2_t *alp, int event_type) +{ + /* Part data. */ + if (event_type == ALP2_EVENT_PART_DATA) { + char *line = alp2_pp_line_chomp(alp->pp); + + /* This part ends with an empty line. */ + if (strlen(line) == 0) { + alp->part_data_done = 1; + return; + } + + /* The first line should be the response line. */ + if (alp->part_line_counter == 1) { + int ovector[33]; + int i, rc; + + /* Response line. */ + + /* Extract the fields. */ + rc = pcre_exec(alp->response_line_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part F: Failed to parse response line: %i", rc); + return; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 1 : + alp->auditlog->response_protocol = capture; + break; + case 2 : + alp->auditlog->response_status = atoi(capture); + break; + case 4 : + alp->auditlog->response_message = capture; + break; + break; + } + } + } + else { + char *name = NULL, *value = NULL; + int ovector[33]; + int i, rc; + + /* Response header line. */ + + /* Extract the fields. */ + rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part F: Failed to parse response header: %i", rc); + return; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 1 : + name = capture; + break; + case 2 : + value = capture; + break; + } + } + + /* Add header to the table. */ + apr_table_addn(alp->auditlog->response_headers, name, value); + } + + return; + } + + /* Part end. */ + if (event_type == ALP2_EVENT_PART_END) { + /* If any of the response headers need + * special handling, place the code here. + */ + return; + } +} + +/** + * Parse the URI. APR-Util does most of the work here. + */ +static int handle_part_B_parse_uri(alp2_t *alp) +{ + char *u = (char *)alp->auditlog->request_uri; + apr_uri_t *uri = NULL; + + if (( alp->auditlog->request_method == NULL) + ||(alp->auditlog->request_uri == NULL)) + { + return 0; + } + + /* Since this is not a proper URI but a path, handle + * the leading double slash. + */ + while ((u[0] == '/') && (u[1] == '/')) { + u++; + } + + uri = apr_pcalloc(alp->auditlog->mp, sizeof(apr_uri_t)); + + if (strcasecmp(alp->auditlog->request_method, "CONNECT") == 0) { + if (apr_uri_parse_hostinfo(alp->auditlog->mp, u, uri) != APR_SUCCESS) { + add_error(alp, 0, "Info: Failed to parse request URI (hostinfo)"); + return -1; + } + } + else { + if (apr_uri_parse(alp->auditlog->mp, u, uri) != APR_SUCCESS) { + add_error(alp, 0, "Info: Failed to parse request URI"); + return -1; + } + } + + alp->auditlog->parsed_uri = uri; + + return 1; +} + +/** + * Handle part B events. + */ +static void handle_part_B(alp2_t *alp, int event_type) +{ + /* Part data. */ + if (event_type == ALP2_EVENT_PART_DATA) { + char *line = alp2_pp_line_chomp(alp->pp); + + /* This part ends with an empty line. */ + if (strlen(line) == 0) { + alp->part_data_done = 1; + return; + } + + /* The first line should be the request line. */ + if (alp->part_line_counter == 1) { + int ovector[33]; + int i, rc; + + /* Request line. */ + + /* Extract the fields. */ + rc = pcre_exec(alp->request_line_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part B: Failed to parse request line: %i", rc); + return; + } + + alp->auditlog->request_line_valid = 1; + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 0 : + alp->auditlog->request_line = capture; + break; + case 1 : + alp->auditlog->request_method = capture; + break; + case 2 : + alp->auditlog->request_uri = capture; + if (handle_part_B_parse_uri(alp) != 1) { + // TODO Do we want to do anything on error? + } + break; + case 3 : + alp->auditlog->request_protocol = capture; + break; + } + } + } + else { + char *name = NULL, *value = NULL; + int ovector[33]; + int i, rc; + + /* Header line. */ + + /* Extract the fields. */ + rc = pcre_exec(alp->header_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part B: Failed to parse request header: %i", rc); + return; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 1 : + name = capture; + break; + case 2 : + value = capture; + break; + } + } + + /* ModSecurity 1.9.x adds some requests headers of + * its own, and we don't want them. + */ + if (strncmp(name, "mod_security-", 13) != 0) { + /* Add header to the table. */ + apr_table_addn(alp->auditlog->request_headers, name, value); + } + } + + return; + } + + /* Part end. */ + if (event_type == ALP2_EVENT_PART_END) { + /* Determine hostname. */ + + // TODO I think the right thing to do is use the port numbers + // only when the host itself is a numerical IP. + + /* Try the URI first. */ + if ( (alp->auditlog->parsed_uri != NULL) + &&(alp->auditlog->parsed_uri->hostname != NULL)) + { + if ( (alp->auditlog->parsed_uri->port != 0) + && (alp->auditlog->parsed_uri->port != 80) + && (alp->auditlog->parsed_uri->port != 443) ) + { + // TODO Do not use the port number if the hostname + // is not numeric. + alp->auditlog->hostname = apr_psprintf(alp->auditlog->mp, "%s:%i", + alp->auditlog->parsed_uri->hostname, alp->auditlog->parsed_uri->port); + } + else { + // TODO Always use the port number if the hostname + // is numeric. + alp->auditlog->hostname = alp->auditlog->parsed_uri->hostname; + } + } + else { + /* Try the Host header. */ + char *s = (char *)apr_table_get(alp->auditlog->request_headers, "Host"); + if (s != NULL) { + // TODO If the hostname is not numeric, remove the port + // numbers if present. + alp->auditlog->hostname = s; + } + else { + /* Use the destination IP and port. */ + alp->auditlog->hostname = apr_psprintf(alp->auditlog->mp, "%s:%i", + alp->auditlog->dst_ip, alp->auditlog->dst_port); + } + } + + return; + } +} + +/** + * Handle part A events. + */ +static void handle_part_A(alp2_t *alp, int event_type) +{ + /* Part data. */ + if (event_type == ALP2_EVENT_PART_DATA) { + char *line = alp2_pp_line_chomp(alp->pp); + int ovector[33]; + int i, rc; + + /* This part can have only one line, + * so we don't expect to be here again. + */ + alp->part_data_done = 1; + + /* Extract the fields. */ + rc = pcre_exec(alp->part_a_pattern, NULL, line, strlen(line), 0, 0, ovector, 30); + if (rc < 0) { + add_error(alp, 1, "Part A: Parsing failed: %i", rc); + return; + } + + /* Loop through the captures. */ + for (i = 0; i < rc; i++) { + char *capture = apr_pstrmemdup(alp->auditlog->mp, line + ovector[2 * i], + ovector[2 * i + 1] - ovector[2 * i]); + + switch(i) { + case 1 : /* timestamp in Apache format */ + /* We don't need it as we use the one from the H part. */ + break; + case 2 : /* transaction ID */ + alp->auditlog->id = capture; + break; + case 3 : /* source address */ + // TODO Validate + alp->auditlog->src_ip = capture; + break; + case 4 : /* source port */ + // TODO Validate + alp->auditlog->src_port = atoi(capture); + break; + case 5 : /* destination address */ + // TODO Validate + alp->auditlog->dst_ip = capture; + break; + case 6 : /* destinatio port */ + // TODO Validate + alp->auditlog->dst_port = atoi(capture); + break; + } + } + + return; + } + + /* Part end. */ + if (event_type == ALP2_EVENT_PART_END) { + /* Place part post-validation here. */ + return; + } +} + +/** + * Create a new audit log data structure, allocating + * memory from the provided memory pool. + */ +auditlog2_t *alp2_auditlog_create(apr_pool_t *mp) +{ + auditlog2_t *al; + + /* Create a new memory pool and the + * auditlog structure in it. We will use the + * parent pool of the parser pool, in order to + * ensure the auditlog memory structures survive + * the death of the parser. + */ + al = apr_pcalloc(mp, sizeof(auditlog2_t)); + al->mp = mp; + + + al->request_headers = apr_table_make(al->mp, 20); + al->response_headers = apr_table_make(al->mp, 20); + al->trailer_headers = apr_table_make(al->mp, 20); + al->messages = apr_array_make(al->mp, 10, sizeof(const alp2_msg_t *)); + al->intercept_phase = -1; + + return al; +} + +/** + * Destroy the provided audit log entry. + */ +void alp2_auditlog_destroy(auditlog2_t *al) +{ + apr_pool_destroy(al->mp); +} + +/** + * Handle ALP2_EVENT_ENTRY_START. + */ +static void handle_entry_start(alp2_t *alp) +{ + /* Create a new data structure to hold the entry. */ + alp->auditlog = alp2_auditlog_create(alp->pp->current_entry->mp); + alp->auditlog->pp_entry = alp->pp->current_entry; + + /* Reset entry flags. */ + alp->previous_part_id = 0; + alp->seen_part_h = 0; + alp->parse_error = 0; + alp->errors = apr_array_make(alp->auditlog->mp, 4, sizeof(const char *)); +} + +/** + * Handle ALP2_EVENT_ENTRY_END. + */ +static void handle_entry_end(alp2_t *alp) +{ + if (alp->parse_error) { + /* No need to validate the entry since we've + * previously encountered a problem with it. + */ + } + else { + /* Final entry validation. */ + + /* Have we seen the H part? (We must have seen the A + * part, otherwise the entry would have begain in + * the first place. + */ + if (alp->seen_part_h == 0) { + add_error(alp, 1, "Entry does not have part H."); + } + } + + /* Invoke the upstream callback to handle the entry. */ + if (alp->user_callback(alp) == 0) { + alp->done = 1; + } + + /* Upstream owns the audit log entry now. */ + alp->auditlog = NULL; +} + +/** + * Handle ALP2_EVENT_PART_START. + */ +static void handle_part_start(alp2_t *alp) +{ + if (alp->parse_error) { + return; + } + + /* Reset part flags. */ + alp->part_line_counter = 0; + alp->part_data_done = 0; + + /* Is this part allowed/expected? */ + if (alp->previous_part_id == 0) { + if (alp->pp->current_part->id != 'A') { + add_error(alp, 1, "Expected part A but got %c.", alp->pp->current_part->id); + return; + } + } + + /* Invoke the appropriate part handler. */ + switch(alp->pp->current_part->id) { + case 'A' : + handle_part_A(alp, ALP2_EVENT_PART_START); + break; + case 'B' : + handle_part_B(alp, ALP2_EVENT_PART_START); + break; + case 'F' : + handle_part_F(alp, ALP2_EVENT_PART_START); + break; + case 'H' : + alp->seen_part_h = 1; + handle_part_H(alp, ALP2_EVENT_PART_START); + break; + default : + /* Ignore unknown part. */ + break; + } +} + +/* + * Handle ALP2_EVENT_PART_END. + */ +static void handle_part_end(alp2_t *alp) +{ + if (alp->parse_error) { + return; + } + + /* Invoke the appropriate part handler. */ + switch(alp->pp->current_part->id) { + case 'A' : + handle_part_A(alp, ALP2_EVENT_PART_END); + break; + case 'B' : + handle_part_B(alp, ALP2_EVENT_PART_END); + case 'F' : + handle_part_F(alp, ALP2_EVENT_PART_END); + break; + case 'H' : + handle_part_H(alp, ALP2_EVENT_PART_END); + break; + default : + /* Ignore unknown part. */ + break; + } + + /* Remember the last part processed. */ + alp->previous_part_id = alp->pp->current_part->id; +} + +/* + * Handle ALP2_EVENT_PART_DATA. + */ +static void handle_part_data(alp2_t *alp) +{ + if (alp->parse_error) { + return; + } + + alp->part_line_counter++; + + if (alp->part_data_done) { + add_error(alp, 1, "Unexpected data for part %c.", alp->pp->current_part->id); + return; + } + + /* Invoke the appropriate part handler. */ + switch(alp->pp->current_part->id) { + case 'A' : + handle_part_A(alp, ALP2_EVENT_PART_DATA); + break; + case 'B' : + handle_part_B(alp, ALP2_EVENT_PART_DATA); + break; + case 'F' : + handle_part_F(alp, ALP2_EVENT_PART_DATA); + break; + case 'H' : + handle_part_H(alp, ALP2_EVENT_PART_DATA); + break; + default : + /* Ignore unknown part. */ + break; + } +} + +/** + * This function handles callbacks from + * the lower-level (part) parser. + */ +static int alp2_callback(alp2_pp_t *pp, int event_type) +{ + alp2_t *alp = (alp2_t *)pp->user_data; + + /* Choose where to dispatch the event based + * on the event type. + */ + switch(event_type) { + case ALP2_EVENT_ENTRY_START : + handle_entry_start(alp); + break; + case ALP2_EVENT_ENTRY_END : + handle_entry_end(alp); + break; + case ALP2_EVENT_PART_START : + handle_part_start(alp); + break; + case ALP2_EVENT_PART_END : + handle_part_end(alp); + break; + case ALP2_EVENT_PART_DATA : + handle_part_data(alp); + break; + default : + /* Unexpected event type. */ + break; + } + + if (alp->done) { + /* Stop parsing. */ + return 0; + } + else { + /* Go on. */ + return 1; + } +} + +/** + * Initialise parser. + */ +// XXX Make callback a typedef +int alp2_create(alp2_t **_alp, apr_pool_t *mp, + void *user_data, int (*user_callback)(alp2_t *alp)) +{ + alp2_t *alp; + apr_pool_t *new_pool; + const char *errptr = NULL; + int erroffset; + + /* We require a callback. */ + if (user_callback == NULL) { + return -1; + } + + /* We will use our own memory pool. */ + apr_pool_create(&new_pool, mp); + alp = apr_pcalloc(mp, sizeof(alp2_t)); + *_alp = alp; + alp->mp = new_pool; + + alp->user_data = user_data; + alp->user_callback = user_callback; + + /* Initialise the part parser. */ + alp->pp = apr_pcalloc(mp, sizeof(alp2_pp_t)); + if (alp->pp == NULL) return -1; + if (alp2_pp_init(alp->pp, alp, alp2_callback, mp) < 0) { + return -2; + } + + /* Compile the patterns we use for parsing. */ + + /* part A pattern */ + if ((alp->part_a_pattern = pcre_compile( + "^\\[(.+)\\] (\\S+) ([.:0-9a-f]+) (\\d+) ([.:0-9a-f]+) (\\d+)$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -3; + } + + /* request line pattern */ + if ((alp->request_line_pattern = pcre_compile( + // TODO Needs improving (e.g. to support simplified HTTP/0.9 requests + "^(\\S+) (.*?) (HTTP/\\d\\.\\d)$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -4; + } + + /* header pattern */ + if ((alp->header_pattern = pcre_compile( + "^([^:]+):\\s*(.+)$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -5; + } + + /* response line pattern */ + if ((alp->response_line_pattern = pcre_compile( + "^(HTTP/\\d\\.\\d) (\\d{3})( (.+))?$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -6; + } + + /* Action trailer header pattern */ + if ((alp->trailer_action_pattern = pcre_compile( + "^Intercepted \\(phase (\\d)\\)$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -7; + } + + /* Stopwatch trailer header pattern */ + if ((alp->trailer_stopwatch_pattern = pcre_compile( + "^(\\d+) (\\d+)( \\((-|\\d+)\\*? (-|\\d+) (-|\\d+)\\))?$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -8; + } + + /* WebApp-Info trailer header pattern */ + if ((alp->trailer_webappinfo_pattern = pcre_compile( + "^\"(.*)\" \"(.*)\" \"(.*)\"$", + PCRE_DOTALL, &errptr, &erroffset, NULL)) == NULL) + { + return -9; + } + + return 1; +} + +/** + * Process a piece of a stream of audit log entries. + */ +int alp2_process(alp2_t *alp, const char *data, size_t len) +{ + alp2_pp_process(alp->pp, data, len); + + if (alp->done) { + return 0; + } + else { + return 1; + } +} + +/** + * Destroy the parser. + */ +void alp2_destroy(alp2_t *alp) +{ + apr_pool_destroy(alp->mp); +} + diff --git a/alp2/alp2.h b/alp2/alp2.h new file mode 100644 index 0000000..2a159d5 --- /dev/null +++ b/alp2/alp2.h @@ -0,0 +1,164 @@ +/* +* 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. +*/ + +#ifndef _ALP2_H_ +#define _ALP2_H_ + +#include +#include + +#include "alp2_pp.h" +#include "pcre.h" + +/* -- Data structures -- */ + +typedef struct alp2_msg_t alp2_msg_t; + +struct alp2_msg_t { + const char *engine_message; + const char *target; + const char *id; + const char *rev; + const char *msg; + const char *data; + const char *file; + unsigned long file_line; + size_t offset; + int severity; + int warning; + apr_array_header_t *tags; +}; + +typedef struct auditlog2_t auditlog2_t; + +struct auditlog2_t { + apr_pool_t *mp; + + /* Transaction data */ + + const char *id; + + apr_time_t timestamp; + unsigned int duration; + + const char *src_ip; + unsigned int src_port; + const char *dst_ip; + unsigned int dst_port; + + /* Request */ + + unsigned int request_line_valid; + const char *request_line; + const char *request_method; + const char *request_uri; + apr_uri_t *parsed_uri; + const char *request_protocol; + apr_table_t *request_headers; + + /* Determine the hostname: The hostname from the URI is + * used where present, otherwise the value of the Host + * request header is used. + * + * If neither of these two is available we will use the + * combination of the destination IP and port as hostname. + * + * The resulting hostname may have the port attached. + */ + const char *hostname; + + /* Response */ + + const char *response_protocol; + unsigned int response_status; + const char *response_message; + apr_table_t *response_headers; + const char *response_tfn; + + /* Other */ + + apr_table_t *trailer_headers; + + unsigned int was_intercepted; + unsigned int intercept_phase; /* -1 if interception did not happen */ + + const char *producer; + const char *server; + const char *handler; + + const char *application_id; + const char *session_id; + const char *user_id; + + apr_array_header_t *messages; + + alp2_pp_entry_t *pp_entry; +}; + +typedef struct alp2_t alp2_t; + +struct alp2_t { + apr_pool_t *mp; + + void *user_data; + int (*user_callback)(alp2_t *alp); + + alp2_pp_t *pp; + + unsigned int previous_part_id; + unsigned int part_line_counter; + unsigned int part_data_done; + unsigned int seen_part_h; + + unsigned int done; + unsigned int parse_error; + apr_array_header_t *errors; + + /* Regular expression patterns. */ + // TODO All these need reviewing + pcre *part_a_pattern; + pcre *request_line_pattern; + pcre *header_pattern; + pcre *response_line_pattern; + + pcre *trailer_action_pattern; + pcre *trailer_stopwatch_pattern; + pcre *trailer_webappinfo_pattern; + + auditlog2_t *auditlog; +}; + +/* Higher-level (user) parser. */ + +/* NOTE Parser will create a subpool for its own use, but each + * entry will be created in a separate subpool directly + * under the main pool. This allows the created audit log + * entries to survive the death of the parser. + */ + + +/* -- Functions -- */ + +int alp2_create(alp2_t **_alp, apr_pool_t *mp, + void *user_data, int (*user_callback)(alp2_t *alp)); + +int alp2_process(alp2_t *alp, const char *data, size_t len); + +void alp2_destroy(alp2_t *alp); + +auditlog2_t *alp2_auditlog_create(apr_pool_t *mp); + +void alp2_auditlog_destroy(auditlog2_t *al); + +#endif diff --git a/alp2/alp2_pp.c b/alp2/alp2_pp.c new file mode 100755 index 0000000..5649dc1 --- /dev/null +++ b/alp2/alp2_pp.c @@ -0,0 +1,362 @@ +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License.  You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include +#include +#include + +#include "alp2_pp.h" + +/** + * Take the line in the buffer and replace the new line + * at the end with a NUL byte. + */ +char *alp2_pp_line_chomp(alp2_pp_t *pp) { + if (pp->line_pos == 0) { + pp->line_buf[0] = '\0'; + } + else { + pp->line_buf[pp->line_pos - 1] = '\0'; + } + + return &(pp->line_buf[0]); +} + +/** + * Look into the line buffer to determine if it + * contains a boundary line. + */ +static int alp2_pp_is_boundary_line(alp2_pp_t *alp_pp) { + char *new_boundary = NULL; + unsigned int id; + size_t i; + + /* A boundary line cannot be less than 14 characters long. */ + if (alp_pp->line_pos < 15) { + return 0; + } + + /* The first two characters must both be dashes. */ + if ((alp_pp->line_buf[0] != '-')||(alp_pp->line_buf[1] != '-')) { + return 0; + } + + /* Extract the boundary. */ + i = 2; /* Start after the second dash. */ + while((isxdigit(alp_pp->line_buf[i]))&&(i < alp_pp->line_pos)) { + i++; + } + + /* The boundary cannot be shorter than 8 characters. */ + if (i - 2 < 8) { + return 0; + } + + // TODO Memory leak; use a single parser buffer to avoid per-entry + // allocation from the parser pool. + new_boundary = apr_pstrndup(alp_pp->mp, &(alp_pp->line_buf[2]), i - 2); + + /* Check if the rest of the line is valid. */ + if ( (i + 5 < alp_pp->line_pos) /* Need at lest 5 more bytes. */ + ||(alp_pp->line_buf[i + 0] != '-') + ||(alp_pp->line_buf[i + 1] < 'A') + ||(alp_pp->line_buf[i + 1] > 'Z') + ||(alp_pp->line_buf[i + 2] != '-') + ||(alp_pp->line_buf[i + 3] != '-') + ||(alp_pp->line_buf[i + 4] != '\n') ) + { + return 0; + } + + id = alp_pp->line_buf[i + 1]; + + /* Are we in a middle of an entry right now? */ + if (alp_pp->current_entry == NULL) { + /* We will accept a new boundary. */ + alp_pp->boundary = new_boundary; + + return id; + } + else { + /* The boundary must match the boundary of + * the entry we are currently working on. + */ + if (strcmp(alp_pp->current_entry->boundary, new_boundary) != 0) { + return 0; + } + else { + return id; + } + } + + return 0; +} + +/** + * Process data belonging to a single part. + */ +static void alp2_pp_process_part_data(alp2_pp_t *alp_pp) { + if (alp_pp->current_part == NULL) { + return; + } + + /* Invoke part processor. */ + if (alp_pp->callback != NULL) { + if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_DATA) == 0) { + alp_pp->done = 1; + } + } + + /* Keep track of part size. */ + alp_pp->current_part->size += alp_pp->line_pos; + + /* Update the MD5 hash calculation. */ + if ((alp_pp->current_entry != NULL)&&(alp_pp->line_pos > 0)) { + apr_md5_update(alp_pp->current_entry->md5_context, &alp_pp->line_buf[0], alp_pp->line_pos - 1); + } +} + +/** + * Initialise parser. + */ +int alp2_pp_init(alp2_pp_t *alp_pp, void *user_data, + int (*callback)(alp2_pp_t *alp_pp, int event_type), apr_pool_t *mp) +{ + memset(alp_pp, 0, sizeof(alp2_pp_t)); + + alp_pp->user_data = user_data; + alp_pp->callback = callback; + alp_pp->mp = mp; /* Use the parent pool directly. */ + + /* Set-up the line buffer. */ + alp_pp->line_buf = apr_pcalloc(mp, ALP2_MAX_LINE_SIZE); + alp_pp->line_size = ALP2_MAX_LINE_SIZE; + alp_pp->line_has_start = 1; + alp_pp->line_offset = 0; + + return 1; +} + +/** + * Process data the parser has stored in the input buffer. + */ +static apr_status_t alp2_pp_process_internal(alp2_pp_t *alp_pp) { + /* Do not proceed if we've previously + * encountered a fatal error. + */ + if (alp_pp->errored != 0) { + return ALP2_ERROR_FATAL; + } + + if (alp_pp->done) { + return ALP2_DONE; + } + + /* Go back straight away if we don't have anything to work with. */ + if (alp_pp->input_len == 0) { + return ALP2_NEED_DATA; + } + + while (alp_pp->input_pos < alp_pp->input_len) { + int c; + + if (alp_pp->done) { + return ALP2_DONE; + } + + if (alp_pp->line_pos >= alp_pp->line_size) { + /* Our line buffer is full with the + * line incomplete. + */ + alp2_pp_process_part_data(alp_pp); + + /* Reset line buffer . */ + alp_pp->line_pos = 0; + alp_pp->line_has_start = 0; + alp_pp->line_offset = alp_pp->current_offset; + } + + /* Consume one byte. */ + c = alp_pp->input_buf[alp_pp->input_pos]; + alp_pp->input_pos++; + alp_pp->current_offset++; + + /* Copy the byte to the line buffer. */ + alp_pp->line_buf[alp_pp->line_pos] = c; + alp_pp->line_pos++; + + /* Are we at the end of a line? */ + if (c == '\n') { + if (alp_pp->line_has_start) { + /* We have one complete line. */ + + int id = alp2_pp_is_boundary_line(alp_pp); + + if (id != 0) { + /* The line is a boundary. */ + + /* Finish with the previous part, if any. */ + if (alp_pp->current_part != NULL) { + /* Update the MD5 context. */ + apr_md5_update(alp_pp->current_entry->md5_context, + &alp_pp->line_buf[0], alp_pp->line_pos - 1); + + /* Event PART_END. */ + if (alp_pp->callback != NULL) { + if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_END) == 0) { + alp_pp->done = 1; + } + } + + /* Add part to the current entry. */ + *(alp2_pp_part_t **)apr_array_push(alp_pp->current_entry->parts) + = alp_pp->current_part; + + /* Delete part. */ + alp_pp->current_part = NULL; + + /* If the new part is part Z, then finish + * with the current entry. */ + if (id == 'Z') { + alp_pp->current_entry->size = alp_pp->current_offset - alp_pp->current_entry->offset; + + /* Create the MD5 digest. */ + apr_md5_final(alp_pp->current_entry->md5_digest, + alp_pp->current_entry->md5_context); + + /* Event ENTRY_END. */ + if (alp_pp->callback != NULL) { + if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_END) == 0) { + alp_pp->done = 1; + } + } + + /* We are about to destroy our only reference to the per-entry + * memory pool, but that is all right since we've passed all + * responsibility for the entry to the higher-level handler. + */ + alp_pp->current_entry = NULL; + } + } + + if (id != 'Z') { + /* Create new entry if necessary. */ + if (alp_pp->current_entry == NULL) { + apr_pool_t *new_pool = NULL; + + /* Create a per-entry pool directly from the main memory pool. */ + apr_pool_create(&new_pool, apr_pool_parent_get(alp_pp->mp)); + + alp_pp->current_entry = apr_pcalloc(new_pool, sizeof(alp2_pp_entry_t)); + alp_pp->current_entry->mp = new_pool; + alp_pp->current_entry->offset = alp_pp->line_offset; + alp_pp->current_entry->boundary = apr_pstrdup(new_pool, alp_pp->boundary); + alp_pp->boundary = NULL; + + alp_pp->current_entry->parts = apr_array_make(alp_pp->current_entry->mp, + 16, sizeof(alp2_pp_part_t *)); + + /* Initialise the MD5 context. */ + alp_pp->current_entry->md5_context = apr_pcalloc(alp_pp->current_entry->mp, + sizeof(apr_md5_ctx_t)); + apr_md5_init(alp_pp->current_entry->md5_context); + + /* Start calculating the has with the first line. */ + apr_md5_update(alp_pp->current_entry->md5_context, &alp_pp->line_buf[0], alp_pp->line_pos - 1); + + /* Event ENTRY_START. */ + if (alp_pp->callback != NULL) { + if (alp_pp->callback(alp_pp, ALP2_EVENT_ENTRY_START) == 0) { + alp_pp->done = 1; + } + } + } + + /* Create new part, but only if we are not + * dealing with an entry terminator. + */ + alp_pp->current_part = apr_pcalloc(alp_pp->current_entry->mp, sizeof(alp2_pp_part_t)); + alp_pp->current_part->id = id; + alp_pp->current_part->offset = alp_pp->current_offset; + + /* Event PART_START. */ + if (alp_pp->callback != NULL) { + if (alp_pp->callback(alp_pp, ALP2_EVENT_PART_START) == 0) { + alp_pp->done = 1; + } + } + } + } + else { + /* The line does not contain a boundary, + * so process it as part data. + */ + alp2_pp_process_part_data(alp_pp); + } + } + else { + /* We have a chunk of data that is not a line, which + * probably means that our buffer was not big enough, either + * because the line (is a line and it) was too big, or because + * we are processing binary data. Ideally the latter. + */ + alp2_pp_process_part_data(alp_pp); + } + + /* Reset the line buffer. */ + alp_pp->line_pos = 0; + alp_pp->line_has_start = 1; + alp_pp->line_offset = alp_pp->current_offset; + } + } + + if (alp_pp->done) { + return ALP2_DONE; + } + else { + return ALP2_NEED_DATA; + } +} + +/** + * Process the provided data. + */ +int alp2_pp_process(alp2_pp_t *alp_pp, const char *data, size_t len) { + /* Do not proceed if we've previously + * encountered a fatal error. + */ + if (alp_pp->errored != 0) { + return ALP2_ERROR_FATAL; + } + + /* Check that we've used up the existing buffer. */ + if (alp_pp->input_pos < alp_pp->input_len) { + return ALP2_ERROR_INCORRECT_STATE; + } + + alp_pp->input_buf = data; + alp_pp->input_len = len; + alp_pp->input_pos = 0; + + return alp2_pp_process_internal(alp_pp); +} + +/** + * Clean-up the parser structures. + */ +void alp2_pp_terminate(alp2_pp_t *alp_pp) { + /* Nothing to do, but we may need + * to do something in the future. + */ +} diff --git a/alp2/alp2_pp.h b/alp2/alp2_pp.h new file mode 100644 index 0000000..ba5c090 --- /dev/null +++ b/alp2/alp2_pp.h @@ -0,0 +1,124 @@ +/* +* 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. +*/ + +#ifndef _ALP2_LL_H_ +#define _ALP2_LL_H_ + +#include +#include +#include +#include +#include + +/* -- Constants -- */ + +#define ALP2_MAX_LINE_SIZE 16384 + +#define ALP2_ERROR_INCORRECT_STATE -1001 +#define ALP2_ERROR_FATAL -1002 + +#define ALP2_DONE 0 +#define ALP2_NEED_DATA 1 + +#define ALP2_EVENT_ENTRY_START 1 +#define ALP2_EVENT_ENTRY_END 2 +#define ALP2_EVENT_PART_START 3 +#define ALP2_EVENT_PART_END 4 +#define ALP2_EVENT_PART_DATA 5 + + +/* -- Data structures -- */ + +typedef struct alp2_pp_part_t alp2_pp_part_t; + +struct alp2_pp_part_t { + int id; // XXX int here but unsigned int other places??? + + /* Relative to the beginning of the entry, not + * including the boundary lines. Just content. + */ + size_t offset; + + size_t size; +}; + +typedef struct alp2_pp_entry_t alp2_pp_entry_t; + +struct alp2_pp_entry_t { + apr_pool_t *mp; + apr_array_header_t *parts; + + /* Entry offset and size include + * the delimiting boundaries. + */ + size_t offset; + size_t size; + + const char *boundary; + + apr_md5_ctx_t *md5_context; + uint8_t md5_digest[APR_MD5_DIGESTSIZE]; +}; + +typedef struct alp2_pp_t alp2_pp_t; + +struct alp2_pp_t { + void *user_data; + int (*callback)(alp2_pp_t *alp, int event_type); + + /* The memory pool used during the parsing of + * individual audit log entries. Cleared between + * entries. + */ + apr_pool_t *mp; + + unsigned int errored; + unsigned int done; + + const char *boundary; + char *last_processed_part; + char *current_line; + + /* The number of bytes processed since + * the beginning or the last reset. + */ + size_t current_offset; + + const char *input_buf; + size_t input_len; + size_t input_pos; + + char *line_buf; + size_t line_pos; + size_t line_size; + unsigned int line_has_start; + size_t line_offset; + + alp2_pp_part_t *current_part; + alp2_pp_entry_t *current_entry; +}; + + +/* Functions. */ + +int alp2_pp_init(alp2_pp_t *alp_pp, void *user_data, + int (*callback)(alp2_pp_t *alp, int event_type), apr_pool_t *mp); + +int alp2_pp_process(alp2_pp_t *alp_pp, const char *data, size_t len); + +void alp2_pp_terminate(alp2_pp_t *alp_pp); + +char *alp2_pp_line_chomp(alp2_pp_t *alp_pp); + +#endif diff --git a/apache2/Makefile.am b/apache2/Makefile.am new file mode 100644 index 0000000..e7bf787 --- /dev/null +++ b/apache2/Makefile.am @@ -0,0 +1,192 @@ +pkglibdir = $(prefix)/lib +pkglib_LTLIBRARIES = mod_security2.la + +mod_security2_la_SOURCES = acmp.c \ + apache2_config.c \ + apache2_io.c \ + apache2_util.c \ + libinjection/libinjection_html5.c \ + libinjection/libinjection_sqli.c \ + libinjection/libinjection_xss.c \ + mod_security2.c \ + modsecurity.c \ + msc_status_engine.c \ + msc_crypt.c \ + msc_geo.c \ + msc_gsb.c \ + msc_json.c \ + msc_logging.c \ + msc_lua.c \ + msc_multipart.c \ + msc_parsers.c \ + msc_pcre.c \ + msc_release.c \ + msc_remote_rules.c \ + msc_reqbody.c \ + msc_tree.c \ + msc_unicode.c \ + msc_util.c \ + msc_xml.c \ + persist_dbm.c \ + re_actions.c \ + re.c \ + re_operators.c \ + re_tfns.c \ + re_variables.c + +mod_security2_la_CFLAGS = @APR_CFLAGS@ \ + @APU_CFLAGS@ \ + @APXS_CFLAGS@ \ + @CURL_CFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LUA_CFLAGS@ \ + @MODSEC_EXTRA_CFLAGS@ \ + @PCRE_CFLAGS@ \ + @YAJL_CFLAGS@ \ + @SSDEEP_CFLAGS@ + + +mod_security2_la_CPPFLAGS = @APR_CPPFLAGS@ \ + @CURL_CPPFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_CPPFLAGS@ \ + @PCRE_CPPFLAGS@ + +mod_security2_la_LIBADD = @APR_LDADD@ \ + @APU_LDADD@ \ + @CURL_LDADD@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDADD@ \ + @LUA_LDADD@ \ + @PCRE_LDADD@ \ + @YAJL_LDADD@ + +if AIX +mod_security2_la_LDFLAGS = -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if HPUX +mod_security2_la_LDFLAGS = -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if MACOSX +mod_security2_la_LDFLAGS = -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if SOLARIS +mod_security2_la_LDFLAGS = -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if LINUX +mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH@ \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if FREEBSD +mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if OPENBSD +mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if NETBSD +mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ + @APR_LDFLAGS@ \ + @APU_LDFLAGS@ \ + @APXS_LDFLAGS@ \ + @CURL_LDFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDFLAGS@ \ + @LUA_LDFLAGS@ \ + @PCRE_LDFLAGS@ \ + @YAJL_LDFLAGS@ \ + @SSDEEP_LDFLAGS@ +endif + +if LINUX +install-exec-hook: $(pkglib_LTLIBRARIES) + @echo "Removing unused static libraries..."; \ + for m in $(pkglib_LTLIBRARIES); do \ + base=`echo $$m | sed 's/\..*//'`; \ + rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \ + install -D -m444 $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES)/$$base.so; \ + done +else +install-exec-hook: $(pkglib_LTLIBRARIES) + @echo "Removing unused static libraries..."; \ + for m in $(pkglib_LTLIBRARIES); do \ + base=`echo $$m | sed 's/\..*//'`; \ + rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \ + cp -p $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES); \ + done +endif diff --git a/apache2/Makefile.in b/apache2/Makefile.in new file mode 100644 index 0000000..49ccbf0 --- /dev/null +++ b/apache2/Makefile.in @@ -0,0 +1,1223 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = apache2 +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/build/find_apr.m4 \ + $(top_srcdir)/build/find_apu.m4 \ + $(top_srcdir)/build/find_curl.m4 \ + $(top_srcdir)/build/find_lua.m4 \ + $(top_srcdir)/build/find_pcre.m4 \ + $(top_srcdir)/build/find_ssdeep.m4 \ + $(top_srcdir)/build/find_xml.m4 \ + $(top_srcdir)/build/find_yajl.m4 \ + $(top_srcdir)/build/libtool.m4 \ + $(top_srcdir)/build/ltoptions.m4 \ + $(top_srcdir)/build/ltsugar.m4 \ + $(top_srcdir)/build/ltversion.m4 \ + $(top_srcdir)/build/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = modsecurity_config_auto.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkglibdir)" +LTLIBRARIES = $(pkglib_LTLIBRARIES) +mod_security2_la_DEPENDENCIES = +am__dirstamp = $(am__leading_dot)dirstamp +am_mod_security2_la_OBJECTS = mod_security2_la-acmp.lo \ + mod_security2_la-apache2_config.lo \ + mod_security2_la-apache2_io.lo \ + mod_security2_la-apache2_util.lo \ + libinjection/mod_security2_la-libinjection_html5.lo \ + libinjection/mod_security2_la-libinjection_sqli.lo \ + libinjection/mod_security2_la-libinjection_xss.lo \ + mod_security2_la-mod_security2.lo \ + mod_security2_la-modsecurity.lo \ + mod_security2_la-msc_status_engine.lo \ + mod_security2_la-msc_crypt.lo mod_security2_la-msc_geo.lo \ + mod_security2_la-msc_gsb.lo mod_security2_la-msc_json.lo \ + mod_security2_la-msc_logging.lo mod_security2_la-msc_lua.lo \ + mod_security2_la-msc_multipart.lo \ + mod_security2_la-msc_parsers.lo mod_security2_la-msc_pcre.lo \ + mod_security2_la-msc_release.lo \ + mod_security2_la-msc_remote_rules.lo \ + mod_security2_la-msc_reqbody.lo mod_security2_la-msc_tree.lo \ + mod_security2_la-msc_unicode.lo mod_security2_la-msc_util.lo \ + mod_security2_la-msc_xml.lo mod_security2_la-persist_dbm.lo \ + mod_security2_la-re_actions.lo mod_security2_la-re.lo \ + mod_security2_la-re_operators.lo mod_security2_la-re_tfns.lo \ + mod_security2_la-re_variables.lo +mod_security2_la_OBJECTS = $(am_mod_security2_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +mod_security2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(mod_security2_la_CFLAGS) $(CFLAGS) \ + $(mod_security2_la_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/build/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(mod_security2_la_SOURCES) +DIST_SOURCES = $(mod_security2_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ + $(LISP)modsecurity_config_auto.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(srcdir)/modsecurity_config_auto.h.in \ + $(top_srcdir)/build/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +pkglibdir = $(prefix)/lib +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +APR_CFLAGS = @APR_CFLAGS@ +APR_CONFIG = @APR_CONFIG@ +APR_CPPFLAGS = @APR_CPPFLAGS@ +APR_INCLUDEDIR = @APR_INCLUDEDIR@ +APR_LDADD = @APR_LDADD@ +APR_LDFLAGS = @APR_LDFLAGS@ +APR_LINKLD = @APR_LINKLD@ +APR_VERSION = @APR_VERSION@ +APU_CFLAGS = @APU_CFLAGS@ +APU_CONFIG = @APU_CONFIG@ +APU_INCLUDEDIR = @APU_INCLUDEDIR@ +APU_LDADD = @APU_LDADD@ +APU_LDFLAGS = @APU_LDFLAGS@ +APU_LINKLD = @APU_LINKLD@ +APU_VERSION = @APU_VERSION@ +APXS = @APXS@ +APXS_BINDIR = @APXS_BINDIR@ +APXS_CC = @APXS_CC@ +APXS_CFLAGS = @APXS_CFLAGS@ +APXS_EXTRA_CFLAGS = @APXS_EXTRA_CFLAGS@ +APXS_HTTPD = @APXS_HTTPD@ +APXS_INCLUDEDIR = @APXS_INCLUDEDIR@ +APXS_INCLUDES = @APXS_INCLUDES@ +APXS_LDFLAGS = @APXS_LDFLAGS@ +APXS_LIBDIR = @APXS_LIBDIR@ +APXS_LIBEXECDIR = @APXS_LIBEXECDIR@ +APXS_LIBS = @APXS_LIBS@ +APXS_LIBTOOL = @APXS_LIBTOOL@ +APXS_MODULES = @APXS_MODULES@ +APXS_PROGNAME = @APXS_PROGNAME@ +APXS_SBINDIR = @APXS_SBINDIR@ +APXS_WRAPPER = @APXS_WRAPPER@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CURL_CFLAGS = @CURL_CFLAGS@ +CURL_CONFIG = @CURL_CONFIG@ +CURL_CPPFLAGS = @CURL_CPPFLAGS@ +CURL_LDADD = @CURL_LDADD@ +CURL_LDFLAGS = @CURL_LDFLAGS@ +CURL_USES_GNUTLS = @CURL_USES_GNUTLS@ +CURL_VERSION = @CURL_VERSION@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DOXYGEN = @DOXYGEN@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ENV_CMD = @ENV_CMD@ +EXEEXT = @EXEEXT@ +EXTRA_CFLAGS = @EXTRA_CFLAGS@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ +LIBXML2_CONFIG = @LIBXML2_CONFIG@ +LIBXML2_CPPFLAGS = @LIBXML2_CPPFLAGS@ +LIBXML2_LDADD = @LIBXML2_LDADD@ +LIBXML2_LDFLAGS = @LIBXML2_LDFLAGS@ +LIBXML2_VERSION = @LIBXML2_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +LUA_CFLAGS = @LUA_CFLAGS@ +LUA_LDADD = @LUA_LDADD@ +LUA_LDFLAGS = @LUA_LDFLAGS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MODSEC_APXS_EXTRA_CFLAGS = @MODSEC_APXS_EXTRA_CFLAGS@ +MODSEC_EXTRA_CFLAGS = @MODSEC_EXTRA_CFLAGS@ +MSC_BASE_DIR = @MSC_BASE_DIR@ +MSC_PKGBASE_DIR = @MSC_PKGBASE_DIR@ +MSC_REGRESSION_CONF_DIR = @MSC_REGRESSION_CONF_DIR@ +MSC_REGRESSION_DIR = @MSC_REGRESSION_DIR@ +MSC_REGRESSION_DOCROOT_DIR = @MSC_REGRESSION_DOCROOT_DIR@ +MSC_REGRESSION_LOGS_DIR = @MSC_REGRESSION_LOGS_DIR@ +MSC_REGRESSION_SERVERROOT_DIR = @MSC_REGRESSION_SERVERROOT_DIR@ +MSC_TEST_DIR = @MSC_TEST_DIR@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PCRE_CFLAGS = @PCRE_CFLAGS@ +PCRE_CONFIG = @PCRE_CONFIG@ +PCRE_CPPFLAGS = @PCRE_CPPFLAGS@ +PCRE_LDADD = @PCRE_LDADD@ +PCRE_LDFLAGS = @PCRE_LDFLAGS@ +PCRE_LD_PATH = @PCRE_LD_PATH@ +PCRE_VERSION = @PCRE_VERSION@ +PERL = @PERL@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +SSDEEP_CFLAGS = @SSDEEP_CFLAGS@ +SSDEEP_LDADD = @SSDEEP_LDADD@ +SSDEEP_LDFLAGS = @SSDEEP_LDFLAGS@ +STRIP = @STRIP@ +TOPLEVEL_SUBDIRS = @TOPLEVEL_SUBDIRS@ +VERSION = @VERSION@ +YAJL_CFLAGS = @YAJL_CFLAGS@ +YAJL_LDADD = @YAJL_LDADD@ +YAJL_LDFLAGS = @YAJL_LDFLAGS@ +YAJL_LIBS = @YAJL_LIBS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +pkglib_LTLIBRARIES = mod_security2.la +mod_security2_la_SOURCES = acmp.c \ + apache2_config.c \ + apache2_io.c \ + apache2_util.c \ + libinjection/libinjection_html5.c \ + libinjection/libinjection_sqli.c \ + libinjection/libinjection_xss.c \ + mod_security2.c \ + modsecurity.c \ + msc_status_engine.c \ + msc_crypt.c \ + msc_geo.c \ + msc_gsb.c \ + msc_json.c \ + msc_logging.c \ + msc_lua.c \ + msc_multipart.c \ + msc_parsers.c \ + msc_pcre.c \ + msc_release.c \ + msc_remote_rules.c \ + msc_reqbody.c \ + msc_tree.c \ + msc_unicode.c \ + msc_util.c \ + msc_xml.c \ + persist_dbm.c \ + re_actions.c \ + re.c \ + re_operators.c \ + re_tfns.c \ + re_variables.c + +mod_security2_la_CFLAGS = @APR_CFLAGS@ \ + @APU_CFLAGS@ \ + @APXS_CFLAGS@ \ + @CURL_CFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LUA_CFLAGS@ \ + @MODSEC_EXTRA_CFLAGS@ \ + @PCRE_CFLAGS@ \ + @YAJL_CFLAGS@ \ + @SSDEEP_CFLAGS@ + +mod_security2_la_CPPFLAGS = @APR_CPPFLAGS@ \ + @CURL_CPPFLAGS@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_CPPFLAGS@ \ + @PCRE_CPPFLAGS@ + +mod_security2_la_LIBADD = @APR_LDADD@ \ + @APU_LDADD@ \ + @CURL_LDADD@ \ + @LIBXML2_CFLAGS@ \ + @LIBXML2_LDADD@ \ + @LUA_LDADD@ \ + @PCRE_LDADD@ \ + @YAJL_LDADD@ + +@AIX_TRUE@mod_security2_la_LDFLAGS = -module -avoid-version \ +@AIX_TRUE@ @APR_LDFLAGS@ \ +@AIX_TRUE@ @APU_LDFLAGS@ \ +@AIX_TRUE@ @APXS_LDFLAGS@ \ +@AIX_TRUE@ @CURL_LDFLAGS@ \ +@AIX_TRUE@ @LIBXML2_CFLAGS@ \ +@AIX_TRUE@ @LIBXML2_LDFLAGS@ \ +@AIX_TRUE@ @LUA_LDFLAGS@ \ +@AIX_TRUE@ @PCRE_LDFLAGS@ \ +@AIX_TRUE@ @YAJL_LDFLAGS@ \ +@AIX_TRUE@ @SSDEEP_LDFLAGS@ + +@FREEBSD_TRUE@mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ +@FREEBSD_TRUE@ @APR_LDFLAGS@ \ +@FREEBSD_TRUE@ @APU_LDFLAGS@ \ +@FREEBSD_TRUE@ @APXS_LDFLAGS@ \ +@FREEBSD_TRUE@ @CURL_LDFLAGS@ \ +@FREEBSD_TRUE@ @LIBXML2_CFLAGS@ \ +@FREEBSD_TRUE@ @LIBXML2_LDFLAGS@ \ +@FREEBSD_TRUE@ @LUA_LDFLAGS@ \ +@FREEBSD_TRUE@ @PCRE_LDFLAGS@ \ +@FREEBSD_TRUE@ @YAJL_LDFLAGS@ \ +@FREEBSD_TRUE@ @SSDEEP_LDFLAGS@ + +@HPUX_TRUE@mod_security2_la_LDFLAGS = -module -avoid-version \ +@HPUX_TRUE@ @APR_LDFLAGS@ \ +@HPUX_TRUE@ @APU_LDFLAGS@ \ +@HPUX_TRUE@ @APXS_LDFLAGS@ \ +@HPUX_TRUE@ @CURL_LDFLAGS@ \ +@HPUX_TRUE@ @LIBXML2_CFLAGS@ \ +@HPUX_TRUE@ @LIBXML2_LDFLAGS@ \ +@HPUX_TRUE@ @LUA_LDFLAGS@ \ +@HPUX_TRUE@ @PCRE_LDFLAGS@ \ +@HPUX_TRUE@ @YAJL_LDFLAGS@ \ +@HPUX_TRUE@ @SSDEEP_LDFLAGS@ + +@LINUX_TRUE@mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH@ \ +@LINUX_TRUE@ @APR_LDFLAGS@ \ +@LINUX_TRUE@ @APU_LDFLAGS@ \ +@LINUX_TRUE@ @APXS_LDFLAGS@ \ +@LINUX_TRUE@ @CURL_LDFLAGS@ \ +@LINUX_TRUE@ @LIBXML2_CFLAGS@ \ +@LINUX_TRUE@ @LIBXML2_LDFLAGS@ \ +@LINUX_TRUE@ @LUA_LDFLAGS@ \ +@LINUX_TRUE@ @PCRE_LDFLAGS@ \ +@LINUX_TRUE@ @YAJL_LDFLAGS@ \ +@LINUX_TRUE@ @SSDEEP_LDFLAGS@ + +@MACOSX_TRUE@mod_security2_la_LDFLAGS = -module -avoid-version \ +@MACOSX_TRUE@ @APR_LDFLAGS@ \ +@MACOSX_TRUE@ @APU_LDFLAGS@ \ +@MACOSX_TRUE@ @APXS_LDFLAGS@ \ +@MACOSX_TRUE@ @CURL_LDFLAGS@ \ +@MACOSX_TRUE@ @LIBXML2_CFLAGS@ \ +@MACOSX_TRUE@ @LIBXML2_LDFLAGS@ \ +@MACOSX_TRUE@ @LUA_LDFLAGS@ \ +@MACOSX_TRUE@ @PCRE_LDFLAGS@ \ +@MACOSX_TRUE@ @YAJL_LDFLAGS@ \ +@MACOSX_TRUE@ @SSDEEP_LDFLAGS@ + +@NETBSD_TRUE@mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ +@NETBSD_TRUE@ @APR_LDFLAGS@ \ +@NETBSD_TRUE@ @APU_LDFLAGS@ \ +@NETBSD_TRUE@ @APXS_LDFLAGS@ \ +@NETBSD_TRUE@ @CURL_LDFLAGS@ \ +@NETBSD_TRUE@ @LIBXML2_CFLAGS@ \ +@NETBSD_TRUE@ @LIBXML2_LDFLAGS@ \ +@NETBSD_TRUE@ @LUA_LDFLAGS@ \ +@NETBSD_TRUE@ @PCRE_LDFLAGS@ \ +@NETBSD_TRUE@ @YAJL_LDFLAGS@ \ +@NETBSD_TRUE@ @SSDEEP_LDFLAGS@ + +@OPENBSD_TRUE@mod_security2_la_LDFLAGS = -no-undefined -module -avoid-version \ +@OPENBSD_TRUE@ @APR_LDFLAGS@ \ +@OPENBSD_TRUE@ @APU_LDFLAGS@ \ +@OPENBSD_TRUE@ @APXS_LDFLAGS@ \ +@OPENBSD_TRUE@ @CURL_LDFLAGS@ \ +@OPENBSD_TRUE@ @LIBXML2_CFLAGS@ \ +@OPENBSD_TRUE@ @LIBXML2_LDFLAGS@ \ +@OPENBSD_TRUE@ @LUA_LDFLAGS@ \ +@OPENBSD_TRUE@ @PCRE_LDFLAGS@ \ +@OPENBSD_TRUE@ @YAJL_LDFLAGS@ \ +@OPENBSD_TRUE@ @SSDEEP_LDFLAGS@ + +@SOLARIS_TRUE@mod_security2_la_LDFLAGS = -module -avoid-version \ +@SOLARIS_TRUE@ @APR_LDFLAGS@ \ +@SOLARIS_TRUE@ @APU_LDFLAGS@ \ +@SOLARIS_TRUE@ @APXS_LDFLAGS@ \ +@SOLARIS_TRUE@ @CURL_LDFLAGS@ \ +@SOLARIS_TRUE@ @LIBXML2_CFLAGS@ \ +@SOLARIS_TRUE@ @LIBXML2_LDFLAGS@ \ +@SOLARIS_TRUE@ @LUA_LDFLAGS@ \ +@SOLARIS_TRUE@ @PCRE_LDFLAGS@ \ +@SOLARIS_TRUE@ @YAJL_LDFLAGS@ \ +@SOLARIS_TRUE@ @SSDEEP_LDFLAGS@ + +all: modsecurity_config_auto.h + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign apache2/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign apache2/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +modsecurity_config_auto.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/modsecurity_config_auto.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status apache2/modsecurity_config_auto.h +$(srcdir)/modsecurity_config_auto.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f modsecurity_config_auto.h stamp-h1 + +install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ + } + +uninstall-pkglibLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ + done + +clean-pkglibLTLIBRARIES: + -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) + @list='$(pkglib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } +libinjection/$(am__dirstamp): + @$(MKDIR_P) libinjection + @: > libinjection/$(am__dirstamp) +libinjection/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) libinjection/$(DEPDIR) + @: > libinjection/$(DEPDIR)/$(am__dirstamp) +libinjection/mod_security2_la-libinjection_html5.lo: \ + libinjection/$(am__dirstamp) \ + libinjection/$(DEPDIR)/$(am__dirstamp) +libinjection/mod_security2_la-libinjection_sqli.lo: \ + libinjection/$(am__dirstamp) \ + libinjection/$(DEPDIR)/$(am__dirstamp) +libinjection/mod_security2_la-libinjection_xss.lo: \ + libinjection/$(am__dirstamp) \ + libinjection/$(DEPDIR)/$(am__dirstamp) + +mod_security2.la: $(mod_security2_la_OBJECTS) $(mod_security2_la_DEPENDENCIES) $(EXTRA_mod_security2_la_DEPENDENCIES) + $(AM_V_CCLD)$(mod_security2_la_LINK) -rpath $(pkglibdir) $(mod_security2_la_OBJECTS) $(mod_security2_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + -rm -f libinjection/*.$(OBJEXT) + -rm -f libinjection/*.lo + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-acmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-apache2_config.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-apache2_io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-apache2_util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-mod_security2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-modsecurity.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_crypt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_geo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_gsb.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_json.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_logging.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_lua.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_multipart.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_parsers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_pcre.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_release.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_remote_rules.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_reqbody.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_status_engine.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_unicode.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-msc_xml.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-persist_dbm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-re.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-re_actions.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-re_operators.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-re_tfns.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_security2_la-re_variables.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@libinjection/$(DEPDIR)/mod_security2_la-libinjection_html5.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@libinjection/$(DEPDIR)/mod_security2_la-libinjection_sqli.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@libinjection/$(DEPDIR)/mod_security2_la-libinjection_xss.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mod_security2_la-acmp.lo: acmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-acmp.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-acmp.Tpo -c -o mod_security2_la-acmp.lo `test -f 'acmp.c' || echo '$(srcdir)/'`acmp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-acmp.Tpo $(DEPDIR)/mod_security2_la-acmp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acmp.c' object='mod_security2_la-acmp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-acmp.lo `test -f 'acmp.c' || echo '$(srcdir)/'`acmp.c + +mod_security2_la-apache2_config.lo: apache2_config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-apache2_config.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-apache2_config.Tpo -c -o mod_security2_la-apache2_config.lo `test -f 'apache2_config.c' || echo '$(srcdir)/'`apache2_config.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-apache2_config.Tpo $(DEPDIR)/mod_security2_la-apache2_config.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apache2_config.c' object='mod_security2_la-apache2_config.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-apache2_config.lo `test -f 'apache2_config.c' || echo '$(srcdir)/'`apache2_config.c + +mod_security2_la-apache2_io.lo: apache2_io.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-apache2_io.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-apache2_io.Tpo -c -o mod_security2_la-apache2_io.lo `test -f 'apache2_io.c' || echo '$(srcdir)/'`apache2_io.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-apache2_io.Tpo $(DEPDIR)/mod_security2_la-apache2_io.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apache2_io.c' object='mod_security2_la-apache2_io.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-apache2_io.lo `test -f 'apache2_io.c' || echo '$(srcdir)/'`apache2_io.c + +mod_security2_la-apache2_util.lo: apache2_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-apache2_util.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-apache2_util.Tpo -c -o mod_security2_la-apache2_util.lo `test -f 'apache2_util.c' || echo '$(srcdir)/'`apache2_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-apache2_util.Tpo $(DEPDIR)/mod_security2_la-apache2_util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apache2_util.c' object='mod_security2_la-apache2_util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-apache2_util.lo `test -f 'apache2_util.c' || echo '$(srcdir)/'`apache2_util.c + +libinjection/mod_security2_la-libinjection_html5.lo: libinjection/libinjection_html5.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT libinjection/mod_security2_la-libinjection_html5.lo -MD -MP -MF libinjection/$(DEPDIR)/mod_security2_la-libinjection_html5.Tpo -c -o libinjection/mod_security2_la-libinjection_html5.lo `test -f 'libinjection/libinjection_html5.c' || echo '$(srcdir)/'`libinjection/libinjection_html5.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libinjection/$(DEPDIR)/mod_security2_la-libinjection_html5.Tpo libinjection/$(DEPDIR)/mod_security2_la-libinjection_html5.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libinjection/libinjection_html5.c' object='libinjection/mod_security2_la-libinjection_html5.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o libinjection/mod_security2_la-libinjection_html5.lo `test -f 'libinjection/libinjection_html5.c' || echo '$(srcdir)/'`libinjection/libinjection_html5.c + +libinjection/mod_security2_la-libinjection_sqli.lo: libinjection/libinjection_sqli.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT libinjection/mod_security2_la-libinjection_sqli.lo -MD -MP -MF libinjection/$(DEPDIR)/mod_security2_la-libinjection_sqli.Tpo -c -o libinjection/mod_security2_la-libinjection_sqli.lo `test -f 'libinjection/libinjection_sqli.c' || echo '$(srcdir)/'`libinjection/libinjection_sqli.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libinjection/$(DEPDIR)/mod_security2_la-libinjection_sqli.Tpo libinjection/$(DEPDIR)/mod_security2_la-libinjection_sqli.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libinjection/libinjection_sqli.c' object='libinjection/mod_security2_la-libinjection_sqli.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o libinjection/mod_security2_la-libinjection_sqli.lo `test -f 'libinjection/libinjection_sqli.c' || echo '$(srcdir)/'`libinjection/libinjection_sqli.c + +libinjection/mod_security2_la-libinjection_xss.lo: libinjection/libinjection_xss.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT libinjection/mod_security2_la-libinjection_xss.lo -MD -MP -MF libinjection/$(DEPDIR)/mod_security2_la-libinjection_xss.Tpo -c -o libinjection/mod_security2_la-libinjection_xss.lo `test -f 'libinjection/libinjection_xss.c' || echo '$(srcdir)/'`libinjection/libinjection_xss.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) libinjection/$(DEPDIR)/mod_security2_la-libinjection_xss.Tpo libinjection/$(DEPDIR)/mod_security2_la-libinjection_xss.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libinjection/libinjection_xss.c' object='libinjection/mod_security2_la-libinjection_xss.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o libinjection/mod_security2_la-libinjection_xss.lo `test -f 'libinjection/libinjection_xss.c' || echo '$(srcdir)/'`libinjection/libinjection_xss.c + +mod_security2_la-mod_security2.lo: mod_security2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-mod_security2.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-mod_security2.Tpo -c -o mod_security2_la-mod_security2.lo `test -f 'mod_security2.c' || echo '$(srcdir)/'`mod_security2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-mod_security2.Tpo $(DEPDIR)/mod_security2_la-mod_security2.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mod_security2.c' object='mod_security2_la-mod_security2.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-mod_security2.lo `test -f 'mod_security2.c' || echo '$(srcdir)/'`mod_security2.c + +mod_security2_la-modsecurity.lo: modsecurity.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-modsecurity.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-modsecurity.Tpo -c -o mod_security2_la-modsecurity.lo `test -f 'modsecurity.c' || echo '$(srcdir)/'`modsecurity.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-modsecurity.Tpo $(DEPDIR)/mod_security2_la-modsecurity.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='modsecurity.c' object='mod_security2_la-modsecurity.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-modsecurity.lo `test -f 'modsecurity.c' || echo '$(srcdir)/'`modsecurity.c + +mod_security2_la-msc_status_engine.lo: msc_status_engine.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_status_engine.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_status_engine.Tpo -c -o mod_security2_la-msc_status_engine.lo `test -f 'msc_status_engine.c' || echo '$(srcdir)/'`msc_status_engine.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_status_engine.Tpo $(DEPDIR)/mod_security2_la-msc_status_engine.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_status_engine.c' object='mod_security2_la-msc_status_engine.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_status_engine.lo `test -f 'msc_status_engine.c' || echo '$(srcdir)/'`msc_status_engine.c + +mod_security2_la-msc_crypt.lo: msc_crypt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_crypt.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_crypt.Tpo -c -o mod_security2_la-msc_crypt.lo `test -f 'msc_crypt.c' || echo '$(srcdir)/'`msc_crypt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_crypt.Tpo $(DEPDIR)/mod_security2_la-msc_crypt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_crypt.c' object='mod_security2_la-msc_crypt.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_crypt.lo `test -f 'msc_crypt.c' || echo '$(srcdir)/'`msc_crypt.c + +mod_security2_la-msc_geo.lo: msc_geo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_geo.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_geo.Tpo -c -o mod_security2_la-msc_geo.lo `test -f 'msc_geo.c' || echo '$(srcdir)/'`msc_geo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_geo.Tpo $(DEPDIR)/mod_security2_la-msc_geo.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_geo.c' object='mod_security2_la-msc_geo.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_geo.lo `test -f 'msc_geo.c' || echo '$(srcdir)/'`msc_geo.c + +mod_security2_la-msc_gsb.lo: msc_gsb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_gsb.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_gsb.Tpo -c -o mod_security2_la-msc_gsb.lo `test -f 'msc_gsb.c' || echo '$(srcdir)/'`msc_gsb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_gsb.Tpo $(DEPDIR)/mod_security2_la-msc_gsb.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_gsb.c' object='mod_security2_la-msc_gsb.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_gsb.lo `test -f 'msc_gsb.c' || echo '$(srcdir)/'`msc_gsb.c + +mod_security2_la-msc_json.lo: msc_json.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_json.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_json.Tpo -c -o mod_security2_la-msc_json.lo `test -f 'msc_json.c' || echo '$(srcdir)/'`msc_json.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_json.Tpo $(DEPDIR)/mod_security2_la-msc_json.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_json.c' object='mod_security2_la-msc_json.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_json.lo `test -f 'msc_json.c' || echo '$(srcdir)/'`msc_json.c + +mod_security2_la-msc_logging.lo: msc_logging.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_logging.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_logging.Tpo -c -o mod_security2_la-msc_logging.lo `test -f 'msc_logging.c' || echo '$(srcdir)/'`msc_logging.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_logging.Tpo $(DEPDIR)/mod_security2_la-msc_logging.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_logging.c' object='mod_security2_la-msc_logging.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_logging.lo `test -f 'msc_logging.c' || echo '$(srcdir)/'`msc_logging.c + +mod_security2_la-msc_lua.lo: msc_lua.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_lua.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_lua.Tpo -c -o mod_security2_la-msc_lua.lo `test -f 'msc_lua.c' || echo '$(srcdir)/'`msc_lua.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_lua.Tpo $(DEPDIR)/mod_security2_la-msc_lua.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_lua.c' object='mod_security2_la-msc_lua.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_lua.lo `test -f 'msc_lua.c' || echo '$(srcdir)/'`msc_lua.c + +mod_security2_la-msc_multipart.lo: msc_multipart.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_multipart.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_multipart.Tpo -c -o mod_security2_la-msc_multipart.lo `test -f 'msc_multipart.c' || echo '$(srcdir)/'`msc_multipart.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_multipart.Tpo $(DEPDIR)/mod_security2_la-msc_multipart.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_multipart.c' object='mod_security2_la-msc_multipart.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_multipart.lo `test -f 'msc_multipart.c' || echo '$(srcdir)/'`msc_multipart.c + +mod_security2_la-msc_parsers.lo: msc_parsers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_parsers.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_parsers.Tpo -c -o mod_security2_la-msc_parsers.lo `test -f 'msc_parsers.c' || echo '$(srcdir)/'`msc_parsers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_parsers.Tpo $(DEPDIR)/mod_security2_la-msc_parsers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_parsers.c' object='mod_security2_la-msc_parsers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_parsers.lo `test -f 'msc_parsers.c' || echo '$(srcdir)/'`msc_parsers.c + +mod_security2_la-msc_pcre.lo: msc_pcre.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_pcre.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_pcre.Tpo -c -o mod_security2_la-msc_pcre.lo `test -f 'msc_pcre.c' || echo '$(srcdir)/'`msc_pcre.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_pcre.Tpo $(DEPDIR)/mod_security2_la-msc_pcre.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_pcre.c' object='mod_security2_la-msc_pcre.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_pcre.lo `test -f 'msc_pcre.c' || echo '$(srcdir)/'`msc_pcre.c + +mod_security2_la-msc_release.lo: msc_release.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_release.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_release.Tpo -c -o mod_security2_la-msc_release.lo `test -f 'msc_release.c' || echo '$(srcdir)/'`msc_release.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_release.Tpo $(DEPDIR)/mod_security2_la-msc_release.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_release.c' object='mod_security2_la-msc_release.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_release.lo `test -f 'msc_release.c' || echo '$(srcdir)/'`msc_release.c + +mod_security2_la-msc_remote_rules.lo: msc_remote_rules.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_remote_rules.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_remote_rules.Tpo -c -o mod_security2_la-msc_remote_rules.lo `test -f 'msc_remote_rules.c' || echo '$(srcdir)/'`msc_remote_rules.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_remote_rules.Tpo $(DEPDIR)/mod_security2_la-msc_remote_rules.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_remote_rules.c' object='mod_security2_la-msc_remote_rules.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_remote_rules.lo `test -f 'msc_remote_rules.c' || echo '$(srcdir)/'`msc_remote_rules.c + +mod_security2_la-msc_reqbody.lo: msc_reqbody.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_reqbody.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_reqbody.Tpo -c -o mod_security2_la-msc_reqbody.lo `test -f 'msc_reqbody.c' || echo '$(srcdir)/'`msc_reqbody.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_reqbody.Tpo $(DEPDIR)/mod_security2_la-msc_reqbody.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_reqbody.c' object='mod_security2_la-msc_reqbody.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_reqbody.lo `test -f 'msc_reqbody.c' || echo '$(srcdir)/'`msc_reqbody.c + +mod_security2_la-msc_tree.lo: msc_tree.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_tree.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_tree.Tpo -c -o mod_security2_la-msc_tree.lo `test -f 'msc_tree.c' || echo '$(srcdir)/'`msc_tree.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_tree.Tpo $(DEPDIR)/mod_security2_la-msc_tree.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_tree.c' object='mod_security2_la-msc_tree.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_tree.lo `test -f 'msc_tree.c' || echo '$(srcdir)/'`msc_tree.c + +mod_security2_la-msc_unicode.lo: msc_unicode.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_unicode.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_unicode.Tpo -c -o mod_security2_la-msc_unicode.lo `test -f 'msc_unicode.c' || echo '$(srcdir)/'`msc_unicode.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_unicode.Tpo $(DEPDIR)/mod_security2_la-msc_unicode.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_unicode.c' object='mod_security2_la-msc_unicode.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_unicode.lo `test -f 'msc_unicode.c' || echo '$(srcdir)/'`msc_unicode.c + +mod_security2_la-msc_util.lo: msc_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_util.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_util.Tpo -c -o mod_security2_la-msc_util.lo `test -f 'msc_util.c' || echo '$(srcdir)/'`msc_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_util.Tpo $(DEPDIR)/mod_security2_la-msc_util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_util.c' object='mod_security2_la-msc_util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_util.lo `test -f 'msc_util.c' || echo '$(srcdir)/'`msc_util.c + +mod_security2_la-msc_xml.lo: msc_xml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-msc_xml.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-msc_xml.Tpo -c -o mod_security2_la-msc_xml.lo `test -f 'msc_xml.c' || echo '$(srcdir)/'`msc_xml.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-msc_xml.Tpo $(DEPDIR)/mod_security2_la-msc_xml.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='msc_xml.c' object='mod_security2_la-msc_xml.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-msc_xml.lo `test -f 'msc_xml.c' || echo '$(srcdir)/'`msc_xml.c + +mod_security2_la-persist_dbm.lo: persist_dbm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-persist_dbm.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-persist_dbm.Tpo -c -o mod_security2_la-persist_dbm.lo `test -f 'persist_dbm.c' || echo '$(srcdir)/'`persist_dbm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-persist_dbm.Tpo $(DEPDIR)/mod_security2_la-persist_dbm.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='persist_dbm.c' object='mod_security2_la-persist_dbm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-persist_dbm.lo `test -f 'persist_dbm.c' || echo '$(srcdir)/'`persist_dbm.c + +mod_security2_la-re_actions.lo: re_actions.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-re_actions.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-re_actions.Tpo -c -o mod_security2_la-re_actions.lo `test -f 're_actions.c' || echo '$(srcdir)/'`re_actions.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-re_actions.Tpo $(DEPDIR)/mod_security2_la-re_actions.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='re_actions.c' object='mod_security2_la-re_actions.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-re_actions.lo `test -f 're_actions.c' || echo '$(srcdir)/'`re_actions.c + +mod_security2_la-re.lo: re.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-re.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-re.Tpo -c -o mod_security2_la-re.lo `test -f 're.c' || echo '$(srcdir)/'`re.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-re.Tpo $(DEPDIR)/mod_security2_la-re.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='re.c' object='mod_security2_la-re.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-re.lo `test -f 're.c' || echo '$(srcdir)/'`re.c + +mod_security2_la-re_operators.lo: re_operators.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-re_operators.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-re_operators.Tpo -c -o mod_security2_la-re_operators.lo `test -f 're_operators.c' || echo '$(srcdir)/'`re_operators.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-re_operators.Tpo $(DEPDIR)/mod_security2_la-re_operators.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='re_operators.c' object='mod_security2_la-re_operators.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-re_operators.lo `test -f 're_operators.c' || echo '$(srcdir)/'`re_operators.c + +mod_security2_la-re_tfns.lo: re_tfns.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-re_tfns.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-re_tfns.Tpo -c -o mod_security2_la-re_tfns.lo `test -f 're_tfns.c' || echo '$(srcdir)/'`re_tfns.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-re_tfns.Tpo $(DEPDIR)/mod_security2_la-re_tfns.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='re_tfns.c' object='mod_security2_la-re_tfns.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-re_tfns.lo `test -f 're_tfns.c' || echo '$(srcdir)/'`re_tfns.c + +mod_security2_la-re_variables.lo: re_variables.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -MT mod_security2_la-re_variables.lo -MD -MP -MF $(DEPDIR)/mod_security2_la-re_variables.Tpo -c -o mod_security2_la-re_variables.lo `test -f 're_variables.c' || echo '$(srcdir)/'`re_variables.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mod_security2_la-re_variables.Tpo $(DEPDIR)/mod_security2_la-re_variables.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='re_variables.c' object='mod_security2_la-re_variables.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_security2_la_CPPFLAGS) $(CPPFLAGS) $(mod_security2_la_CFLAGS) $(CFLAGS) -c -o mod_security2_la-re_variables.lo `test -f 're_variables.c' || echo '$(srcdir)/'`re_variables.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + -rm -rf libinjection/.libs libinjection/_libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) modsecurity_config_auto.h +installdirs: + for dir in "$(DESTDIR)$(pkglibdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f libinjection/$(DEPDIR)/$(am__dirstamp) + -rm -f libinjection/$(am__dirstamp) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) libinjection/$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-pkglibLTLIBRARIES + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) libinjection/$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-pkglibLTLIBRARIES + +.MAKE: all install-am install-exec-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \ + ctags-am distclean distclean-compile distclean-generic \ + distclean-hdr distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-hook install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkglibLTLIBRARIES \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-pkglibLTLIBRARIES + +.PRECIOUS: Makefile + + +@LINUX_TRUE@install-exec-hook: $(pkglib_LTLIBRARIES) +@LINUX_TRUE@ @echo "Removing unused static libraries..."; \ +@LINUX_TRUE@ for m in $(pkglib_LTLIBRARIES); do \ +@LINUX_TRUE@ base=`echo $$m | sed 's/\..*//'`; \ +@LINUX_TRUE@ rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \ +@LINUX_TRUE@ install -D -m444 $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES)/$$base.so; \ +@LINUX_TRUE@ done +@LINUX_FALSE@install-exec-hook: $(pkglib_LTLIBRARIES) +@LINUX_FALSE@ @echo "Removing unused static libraries..."; \ +@LINUX_FALSE@ for m in $(pkglib_LTLIBRARIES); do \ +@LINUX_FALSE@ base=`echo $$m | sed 's/\..*//'`; \ +@LINUX_FALSE@ rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \ +@LINUX_FALSE@ cp -p $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES); \ +@LINUX_FALSE@ done + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/apache2/Makefile.win b/apache2/Makefile.win new file mode 100644 index 0000000..ed4bfc9 --- /dev/null +++ b/apache2/Makefile.win @@ -0,0 +1,93 @@ +########################################################################### +# +# Usage: NMAKE -f Makefile.win APACHE={httpd installion dir} PCRE={pcre dir} LIBXML2={LibXML2 dir} [ LUA={Lua dir} ] +# +!IF "$(APACHE)" == "" || "$(PCRE)" == "" || "$(LIBXML2)" == "" || "$(CURL)" == "" +!ERROR NMAKE arguments: APACHE=dir PCRE=dir LIBXML2=dir CURL=dir are required to build mod_security2 for Windows +!ENDIF + +# Linking libraries +LIBS = $(APACHE)\lib\libhttpd.lib \ + $(APACHE)\lib\libapr-1.lib \ + $(APACHE)\lib\libaprutil-1.lib \ + $(PCRE)\pcre.lib \ + $(CURL)\libcurl.lib \ + $(LIBXML2)\win32\bin.msvc\libxml2.lib \ + Ws2_32.lib \ + "iphlpapi.lib" + +########################################################################### +########################################################################### + + +!IF "$(IIS_BUILD)" == "yes" +DEFS=$(DEFS) -DVERSION_IIS +!ENDIF + +CC = CL + +MT = mt + +DEFS = /nologo /O2 /LD /W3 /wd4244 /wd4018 -DWIN32 -DWINNT -Dinline=APR_INLINE -D$(VERSION) + +DLL = mod_security2.so + +INCLUDES = -I. -I.. \ + -I$(CURL)\include -I$(CURL) \ + -I$(PCRE)\include -I$(PCRE) \ + -I$(LIBXML2)\include \ + -I$(APACHE)\include + +# Enables support for SecRemoteRules and external resources. +DEFS=$(DEFS) -DWITH_CURL -DWITH_REMOTE_RULES + +# Lua is optional +!IF "$(LUA)" != "" +LIBS = $(LIBS) $(LUA)\lua5.1.lib +DEFS=$(DEFS) -DWITH_LUA +INCLUDES = $(INCLUDES) -I$(LUA)\include -I$(LUA) \ +!ENDIF + +# Yajl/Json is optional +!IF "$(YAJL)" != "" +LIBS = $(LIBS) $(YAJL)\lib\yajl.lib +DEFS=$(DEFS) -DWITH_YAJL +INCLUDES = $(INCLUDES) -I$(YAJL)\include -I$(YAJL) \ +!ENDIF + +CFLAGS= -MD $(INCLUDES) $(DEFS) + +LDFLAGS = + +OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \ + re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \ + msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj \ + msc_parsers.obj msc_util.obj msc_pcre.obj persist_dbm.obj \ + msc_reqbody.obj msc_geo.obj msc_gsb.obj msc_crypt.obj msc_tree.obj msc_unicode.obj acmp.obj msc_lua.obj \ + msc_release.obj \ + msc_status_engine.obj \ + msc_remote_rules.obj \ + msc_json.obj \ + libinjection/libinjection_html5.obj \ + libinjection/libinjection_sqli.obj \ + libinjection/libinjection_xss.obj + +all: $(DLL) + +dll: $(DLL) + +.c.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +.cpp.obj: + $(CC) $(CFLAGS) -c $< -Fo$@ + +$(DLL): $(OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -LD $(OBJS) -Fe$(DLL) $(LIBS) /link + IF EXIST $(DLL).manifest $(MT) -manifest $(DLL).manifest -outputresource:$(DLL);2 + +install: $(DLL) + copy /Y $(DLL) $(APACHE)\modules + +clean: + del $(OBJS) $(DLL) *.dll *.lib *.pdb *.idb *.ilk *.exp *.res *.rc *.bin *.manifest diff --git a/apache2/acmp.c b/apache2/acmp.c new file mode 100644 index 0000000..6e796b3 --- /dev/null +++ b/apache2/acmp.c @@ -0,0 +1,597 @@ +/* +* 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. +*/ + +/* Aho-Corasick Matching */ + +#include "acmp.h" + +#ifdef ACMP_USE_UTF8 +/* UTF support */ +#include "utf8tables.h" +#else +/* No UTF support */ +#define acmp_utf8_char_t long +#include +#define utf8_lcase(a) apr_tolower(a) +#endif + +#include +#include +#include + + +/* + ******************************************************************************* + ******************************************************************************* + * Data structures for acmp parser + */ + +/** + * One node in trie + */ +typedef struct acmp_node_t acmp_node_t; +typedef struct acmp_btree_node_t acmp_btree_node_t; +struct acmp_node_t { + acmp_utf8_char_t letter; + int is_last; + acmp_callback_t callback; + void *callback_data; + int depth; + + acmp_node_t *child; + acmp_node_t *sibling; + acmp_node_t *fail; + acmp_node_t *parent; + acmp_node_t *o_match; + + acmp_btree_node_t *btree; + + apr_size_t hit_count; + + char *text; + char *pattern; +}; + +struct acmp_btree_node_t { + acmp_utf8_char_t letter; + acmp_btree_node_t *left; + acmp_btree_node_t *right; + acmp_node_t *node; +}; + +/** + * Data related to parser, not to individual nodes + */ +struct ACMP { +#ifdef ACMP_USE_UTF8 + int is_utf8; +#endif + int is_case_sensitive; + apr_pool_t *parent_pool; + apr_pool_t *pool; + + int dict_count; + apr_size_t longest_entry; + + acmp_node_t *root_node; + + const char *data_start; + const char *data_end; + const char *data_pos; + apr_size_t data_len; + + apr_size_t *bp_buffer; + apr_size_t bp_buff_len; + + acmp_node_t *active_node; + char u8_buff[6]; + apr_size_t u8buff_len; + apr_size_t hit_count; + int is_failtree_done; + int is_active; + apr_size_t byte_pos; + apr_size_t char_pos; +}; + +/* + ******************************************************************************* + ******************************************************************************* + * Functions for UTF-8 support + */ + +#ifdef ACMP_USE_UTF8 +/** + * Returns length of utf-8 sequence based on its first byte + */ +static int utf8_seq_len(const char *first_byte) { + return utf8_seq_lengths[(unsigned int)(unsigned char)first_byte[0]]; +} + +/** + * Returns length of utf8-encoded text + */ +static size_t utf8_strlen(const char *str) { + int len = 0; + const char *c = str; + while (*c != 0) { + c += utf8_seq_len(c); + len++; + } + return len; +} + +/** + * Returns ucs code for given utf-8 sequence + */ +static acmp_utf8_char_t utf8_decodechar(const char *str) { + int len = utf8_seq_len(str); + acmp_utf8_char_t ch = 0; + switch (len) { + case 6: ch += (unsigned char)*str++; ch <<= 6; + case 5: ch += (unsigned char)*str++; ch <<= 6; + case 4: ch += (unsigned char)*str++; ch <<= 6; + case 3: ch += (unsigned char)*str++; ch <<= 6; + case 2: ch += (unsigned char)*str++; ch <<= 6; + case 1: ch += (unsigned char)*str++; + } + ch -= utf8_offsets[len - 1]; + return ch; +} + +/** + * Returns lowercase for given unicode character. Searches through + * utf8_lcase_map table, if it doesn't find the code assumes + * it doesn't have a lowercase variant and returns code itself. + */ +static long utf8_lcase(acmp_utf8_char_t ucs_code) { + long mid, left, right; + left = 1; + right = UTF8_LCASEMAP_LEN * 2 + 1; + + while (left <= right) { + mid = (left + right) >> 1; + mid -= (mid % 2); mid++; + if (ucs_code > utf8_lcase_map[mid]) + left = mid + 2; + else if (ucs_code < utf8_lcase_map[mid]) + right = mid - 2; + else if (ucs_code == utf8_lcase_map[mid]) + return utf8_lcase_map[mid - 1]; + } + return ucs_code; +} +#endif + +/* + ******************************************************************************* + ******************************************************************************* + * Code for local / static utility functions + */ + +/** + * Returns length of given string for parser's encoding + */ +static size_t acmp_strlen(ACMP *parser, const char *str) { +#ifdef ACMP_USE_UTF8 + return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str); +#else + return strlen(str); +#endif +} + +/** + * Turns string to array of ucs values, depending on parser's encoding + * str - string to convert, doesn't have to be NULL-terminated + * ucs_chars - where to write ucs values + * len - length of input string + */ +static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_chars, int len) { + int i; + const char *c = str; + +#ifdef ACMP_USE_UTF8 + if (parser->is_utf8) { + for (i = 0; i < len; i++) { + *(ucs_chars++) = utf8_decodechar(c); + c += utf8_seq_len(c); + } + } else +#endif + { + for (i = 0; i < len; i++) { + *(ucs_chars++) = *(c++); + } + } +} + +/** + * Returns node with given letter, or null if not found + */ +static acmp_node_t *acmp_child_for_code(acmp_node_t *parent_node, acmp_utf8_char_t ucs_code) { + acmp_node_t *node = parent_node->child; + if (node == NULL) return NULL; + for (;;) { + if (node->letter == ucs_code) return node; + node = node->sibling; + if (node == NULL) return NULL; + } +} + +/** + * Adds node to parent node, if it is not already there + */ +static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) { + acmp_node_t *node = NULL; + + child->parent = parent; + if (parent->child == NULL) { + parent->child = child; + return; + } + + node = parent->child; + for (;;) { + if (node == child) return; + if (node->sibling == NULL) { + node->sibling = child; + return; + } + node = node->sibling; + } +} + +/** + * Copies values from one node to another, without child/sibling/fail pointers + * and without state variables. + */ +static void acmp_clone_node_no_state(acmp_node_t *from, acmp_node_t *to) { + memcpy(to, from, sizeof(acmp_node_t)); + to->child = NULL; + to->sibling = NULL; + to->fail = NULL; + to->hit_count = 0; +} + +static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t letter) { + acmp_btree_node_t *bnode = node->btree; + for (;;) { + if (bnode == NULL) return NULL; + if (bnode->letter == letter) return bnode->node; + if (bnode->letter > letter) { + bnode = bnode->left; + } else { + bnode = bnode->right; + } + } +} + +/** + * + */ +static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) { + return acmp_btree_find(node, letter); +} + +/** + * Connects each node with its first fail node that is end of a phrase. + */ +static void acmp_connect_other_matches(ACMP *parser, acmp_node_t *node) { + acmp_node_t *child, *om; + + for (child = node->child; child != NULL; child = child->sibling) { + if (child->fail == NULL) continue; + for (om = child->fail; om != parser->root_node; om = om->fail) { + if (om->is_last) { + child->o_match = om; + break; + } + } + } + + /* Go recursively through children of this node that have a child node */ + for(child = node->child; child != NULL; child = child->sibling) { + if (child->child != NULL) acmp_connect_other_matches(parser, child); + } +} + +/** + * Adds leaves to binary tree, working from sorted array of keyword tree nodes + */ +static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[], + int pos, int lb, int rb, apr_pool_t *pool) { + + int left = 0, right = 0; + if ((pos - lb) > 1) { + left = lb + (pos - lb) / 2; + node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + node->left->node = nodes[left]; + node->left->letter = nodes[left]->letter; +#ifdef DEBUG_ACMP + fprintf(stderr, "%lc ->left %lc\n", (wint_t)node->node->letter, (wint_t)node->left->node->letter); +#endif + } + if ((rb - pos) > 1) { + right = pos + (rb - pos) / 2; + node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + node->right->node = nodes[right]; + node->right->letter = nodes[right]->letter; +#ifdef DEBUG_ACMP + fprintf(stderr, "%lc ->right %lc\n", (wint_t)node->node->letter, (wint_t)node->right->node->letter); +#endif + } + if (node->right != NULL) { + acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool); + } + if (node->left != NULL) { + acmp_add_btree_leaves(node->left, nodes, left, lb, pos, pool); + } +} + +/** + * Builds balanced binary tree from children nodes of given node. + */ +static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) { + apr_size_t count, i, j; + acmp_node_t *child = node->child; + acmp_node_t **nodes; + apr_size_t pos; + + /* Build an array big enough */ + for (count = 0; child != NULL; child = child->sibling) count++; + nodes = apr_pcalloc(parser->pool, count * sizeof(acmp_node_t *)); + /* ENH: Check alloc succeded */ + + /* ENH: Combine this in the loop below - we do not need two loops */ + child = node->child; + for (i = 0; i < count; i++) { + nodes[i] = child; + child = child->sibling; + }; + + /* We have array with all children of the node and number of those children + */ + for (i = 0; i < count - 1; i++) + for (j = i + 1; j < count; j++) { + acmp_node_t *tmp; + + if (nodes[i]->letter < nodes[j]->letter) continue; + + tmp = nodes[i]; + nodes[i] = nodes[j]; + nodes[j] = tmp; + } + node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t)); + /* ENH: Check alloc succeded */ + pos = count / 2; + node->btree->node = nodes[pos]; + node->btree->letter = nodes[pos]->letter; + acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool); + for (i = 0; i < count; i++) { + if (nodes[i]->child != NULL) acmp_build_binary_tree(parser, nodes[i]); + } +} + +/** + * Constructs fail paths on keyword trie + */ +static apr_status_t acmp_connect_fail_branches(ACMP *parser) { + /* Already connected ? */ + acmp_node_t *child, *node, *goto_node; + apr_array_header_t *arr, *arr2, *tmp; + + if (parser->is_failtree_done != 0) return APR_SUCCESS; + + parser->root_node->text = ""; + arr = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *)); + arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *)); + + parser->root_node->fail = parser->root_node; + + /* All first-level children will fail back to root node */ + for (child = parser->root_node->child; child != NULL; child = child->sibling) { + child->fail = parser->root_node; + *(acmp_node_t **)apr_array_push(arr) = child; +#ifdef DEBUG_ACMP + fprintf(stderr, "fail direction: *%s* => *%s*\n", child->text, child->fail->text); +#endif + } + + for (;;) { + while (apr_is_empty_array(arr) == 0) { + node = *(acmp_node_t **)apr_array_pop(arr); + node->fail = parser->root_node; + if (node->parent != parser->root_node) { + goto_node = acmp_child_for_code(node->parent->fail, node->letter); + node->fail = (goto_node != NULL) ? goto_node : parser->root_node; + } +#ifdef DEBUG_ACMP + fprintf(stderr, "fail direction: *%s* => *%s*\n", node->text, node->fail->text); +#endif + child = node->child; + while (child != NULL) { + *(acmp_node_t **)apr_array_push(arr2) = child; + child = child->sibling; + } + } + if (apr_is_empty_array(arr2) != 0) break; + + tmp = arr; + arr = arr2; + arr2 = tmp; + } + acmp_connect_other_matches(parser, parser->root_node); + if (parser->root_node->child != NULL) acmp_build_binary_tree(parser, parser->root_node); + parser->is_failtree_done = 1; + return APR_SUCCESS; +} + +/* + ******************************************************************************* + ******************************************************************************* + * Code for functions from header file + */ + + +/** + * flags - OR-ed values of ACMP_FLAG constants + * pool - apr_pool to use as parent pool, can be set to NULL + */ +ACMP *acmp_create(int flags, apr_pool_t *pool) { + apr_status_t rc; + apr_pool_t *p; + ACMP *parser; + + rc = apr_pool_create(&p, pool); + if (rc != APR_SUCCESS) return NULL; + + parser = apr_pcalloc(p, sizeof(ACMP)); + /* ENH: Check alloc succeded */ + parser->pool = p; + parser->parent_pool = pool; +#ifdef ACMP_USE_UTF8 + parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1; +#endif + parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1; + parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + return parser; +} + +/** + * Creates fail tree and initializes buffer + */ +apr_status_t acmp_prepare(ACMP *parser) { + apr_status_t st; + + if (parser->bp_buff_len < parser->longest_entry) { + parser->bp_buff_len = parser->longest_entry * 2; + parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len); + /* ENH: Check alloc succeded */ + } + + st = acmp_connect_fail_branches(parser); + parser->active_node = parser->root_node; + if (st != APR_SUCCESS) return st; + parser->is_active = 1; + return APR_SUCCESS; +} + +/** + * Adds pattern to parser + * parser - ACMP parser + * pattern - string with pattern to match + * callback - Optional, pointer to an acmp_callback_t function + * data - pointer to data that will be passed to callback function, only used if callback + * is supplied + * len - Length of pattern in characters, if zero string length is used. + */ +apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern, + acmp_callback_t callback, void *data, apr_size_t len) +{ + size_t length, i, j; + acmp_utf8_char_t *ucs_chars; + acmp_node_t *parent, *child; + + if (parser->is_active != 0) return APR_EGENERAL; + + length = (len == 0) ? acmp_strlen(parser, pattern) : len; + ucs_chars = apr_pcalloc(parser->pool, length * sizeof(acmp_utf8_char_t)); + /* ENH: Check alloc succeded */ + + parent = parser->root_node; + acmp_strtoucs(parser, pattern, ucs_chars, length); + + for (i = 0; i < length; i++) { + acmp_utf8_char_t letter = ucs_chars[i]; + if (parser->is_case_sensitive == 0) { + letter = utf8_lcase(letter); + } + child = acmp_child_for_code(parent, letter); + if (child == NULL) { + child = apr_pcalloc(parser->pool, sizeof(acmp_node_t)); + /* ENH: Check alloc succeded */ + child->pattern = ""; + child->letter = letter; + child->depth = i; + child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2); + /* ENH: Check alloc succeded */ + for (j = 0; j <= i; j++) child->text[j] = pattern[j]; + } + if (i == length - 1) { + if (child->is_last == 0) { + parser->dict_count++; + child->is_last = 1; + child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2); + /* ENH: Check alloc succeded */ + strcpy(child->pattern, pattern); + } + child->callback = callback; + child->callback_data = data; + } + acmp_add_node_to_parent(parent, child); + parent = child; + } + if (length > parser->longest_entry) parser->longest_entry = length; + parser->is_failtree_done = 0; + + return APR_SUCCESS; +} + +/** + * Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree + */ +apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len) { + ACMP *parser; + acmp_node_t *node, *go_to; + const char *end; + + if (acmpt->parser->is_failtree_done == 0) { + acmp_prepare(acmpt->parser); + }; + + parser = acmpt->parser; + if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node; + node = acmpt->ptr; + end = data + len; + + while (data < end) { + acmp_utf8_char_t letter = (unsigned char)*data++; + + if (parser->is_case_sensitive == 0) letter = utf8_lcase(letter); + + go_to = NULL; + while (go_to == NULL) { + go_to = acmp_goto(node, letter); + if (go_to != NULL) { + if (go_to->is_last) { + *match = go_to->text; + return 1; + } + } + if (node == parser->root_node) break; + if (go_to == NULL) node = node->fail; + } + if (go_to != NULL) node = go_to; + + /* If node has o_match, then we found a pattern */ + if (node->o_match != NULL) { + *match = node->text; + return 1; + } + } + acmpt->ptr = node; + return 0; +} diff --git a/apache2/acmp.h b/apache2/acmp.h new file mode 100644 index 0000000..6566516 --- /dev/null +++ b/apache2/acmp.h @@ -0,0 +1,121 @@ +/* +* 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. +*/ + +#ifndef ACMP_H_ +#define ACMP_H_ + +#include +#include + +#define ACMP_FLAG_BYTE 0 +#define ACMP_FLAG_CASE_SENSITIVE 1 +#define ACMP_FLAG_CASE_INSENSITIVE 0 +#ifdef ACMP_USE_UTF8 +#define ACMP_FLAG_UTF8 0x100 +#endif + +/** + * Opaque struct with parser data + */ +typedef struct ACMP ACMP; + +/** + * Used to separate state from the trie for acmp_process_quick function + */ +typedef struct { + ACMP *parser; + void *ptr; +} ACMPT; + +/** + * Callback function. Arguments are: + * ACMP * - acmp parser that initiated callback + * void * - custom data you supplied when adding callback + * apr_size_t - position in bytes where pattern was found + * apr_size_t - position in chars where pattern was found, for multibyte strings + */ +typedef void (*acmp_callback_t)(ACMP *, void *, apr_size_t, apr_size_t); + +/** + * flags - OR-ed values of ACMP_FLAG constants + * pool - apr_pool to use as parent pool, can be set to NULL + */ +ACMP *acmp_create(int flags, apr_pool_t *pool); + +/** + * Destroys previously created parser + */ +void acmp_destroy(ACMP *parser); + +/** + * Creates parser with same options and same patterns + * parser - ACMP parser to duplicate + * pool - parent pool to use, if left as NULL original parser's parent pool is used + */ +ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool); + +/** + * Adds pattern to parser. Cannot be done after starting the search. + * parser - ACMP parser + * pattern - string with pattern to match + * callback - Optional, pointer to an acmp_callback_t function + * data - pointer to data that will be passed to callback function, only used if callback + * is supplied + * len - Length of pattern in characters, if zero string length is used. + */ +apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern, + acmp_callback_t callback, void *data, apr_size_t len); + +/** + * Called to process incoming data stream. You must call acmp_done after sending + * last data packet + * + * data - ptr to incoming data + * len - size of data in bytes + */ +apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len); + +/** + * Returns number of matches on all patterns combined + */ +apr_size_t acmp_match_count_total(ACMP *parser); + +/** + * Returns number of matches for given pattern + */ +apr_size_t acmp_match_count(ACMP *parser, const char *pattern); + +/** + * Resets the state of parser so you can start using it with new set of data, + * or add new patterns. + */ +void acmp_reset(ACMP *parser); + +/** + * Creates an ACMPT struct that will use parser's tree, without duplicating its data + */ +ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool); + +/** + * Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree + */ +apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len); + +/** + * Prepares parser for searching + */ +apr_status_t acmp_prepare(ACMP *parser); + + +#endif /*ACMP_H_*/ diff --git a/apache2/apache2.h b/apache2/apache2.h new file mode 100644 index 0000000..87a17ed --- /dev/null +++ b/apache2/apache2.h @@ -0,0 +1,99 @@ +/* +* 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. +*/ + +#ifndef _APACHE2_H_ +#define _APACHE2_H_ + +#include "http_core.h" +#include "http_request.h" +#include "httpd.h" +#include "ap_release.h" + +#include +#include + + +#if (!defined(NO_MODSEC_API)) +/* Optional functions. */ + +APR_DECLARE_OPTIONAL_FN(void, modsec_register_tfn, (const char *name, void *fn)); +APR_DECLARE_OPTIONAL_FN(void, modsec_register_operator, (const char *name, void *fn_init, void *fn_exec)); +APR_DECLARE_OPTIONAL_FN(void, modsec_register_variable, + (const char *name, unsigned int type, + unsigned int argc_min, unsigned int argc_max, + void *fn_validate, void *fn_generate, + unsigned int is_cacheable, unsigned int availability)); +APR_DECLARE_OPTIONAL_FN(void, modsec_register_reqbody_processor, (const char *name, void *fn_init, void *fn_process, void *fn_complete)); +#endif + +/* ap_get_server_version() is gone in 2.3.0. + * It was replaced by two calls in 2.2.4 and higher: + * ap_get_server_banner() + * ap_get_server_description() + */ +#if (AP_SERVER_MAJORVERSION_NUMBER > 2) \ + || ((AP_SERVER_MAJORVERSION_NUMBER == 2)&& (AP_SERVER_MINORVERSION_NUMBER > 2)) \ + || ((AP_SERVER_MAJORVERSION_NUMBER == 2) && (AP_SERVER_MINORVERSION_NUMBER == 2) && (AP_SERVER_PATCHLEVEL_NUMBER >= 4)) +#define apache_get_server_version() ap_get_server_banner() +#else +#define apache_get_server_version() ap_get_server_version() +#endif + + +/* Configuration functions. */ + +void DSOLOCAL *create_directory_config(apr_pool_t *mp, char *path); + +void DSOLOCAL *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child); + +void DSOLOCAL init_directory_config(directory_config *dcfg); + + +/* IO functions. */ + +apr_status_t DSOLOCAL input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes); + +apr_status_t DSOLOCAL output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in); + +apr_status_t DSOLOCAL read_request_body(modsec_rec *msr, char **error_msg); + + +/* Utility functions */ + +int DSOLOCAL perform_interception(modsec_rec *msr); + +apr_status_t DSOLOCAL send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status); + +int DSOLOCAL apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output); + +void DSOLOCAL record_time_checkpoint(modsec_rec *msr, int checkpoint_no); + +char DSOLOCAL *get_apr_error(apr_pool_t *p, apr_status_t rc); + +char DSOLOCAL *get_env_var(request_rec *r, char *name); + +void DSOLOCAL msr_log(modsec_rec *msr, int level, const char *text, ...) PRINTF_ATTRIBUTE(3,4); + +void DSOLOCAL msr_log_error(modsec_rec *msr, const char *text, ...) PRINTF_ATTRIBUTE(2,3); + +void DSOLOCAL msr_log_warn(modsec_rec *msr, const char *text, ...) PRINTF_ATTRIBUTE(2,3); + +char DSOLOCAL *format_error_log_message(apr_pool_t *mp, error_message_t *em); + +const DSOLOCAL char *get_response_protocol(request_rec *r); + + +#endif + diff --git a/apache2/apache2_config.c b/apache2/apache2_config.c new file mode 100644 index 0000000..ce97950 --- /dev/null +++ b/apache2/apache2_config.c @@ -0,0 +1,3923 @@ +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License.  You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include + +#include "modsecurity.h" +#include "msc_logging.h" +#include "msc_util.h" +#include "http_log.h" +#include "apr_lib.h" +#include "acmp.h" +#include "msc_crypt.h" + +#if defined(WITH_LUA) +#include "msc_lua.h" +#endif + + +/* -- Directory context creation and initialisation -- */ + +/** + * Creates a fresh directory configuration. + */ +void *create_directory_config(apr_pool_t *mp, char *path) +{ + directory_config *dcfg = (directory_config *)apr_pcalloc(mp, sizeof(directory_config)); + if (dcfg == NULL) return NULL; + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Created directory config %pp path %s", dcfg, path); + #endif + + dcfg->mp = mp; + dcfg->is_enabled = NOT_SET; + + dcfg->reqbody_access = NOT_SET; + dcfg->reqintercept_oe = NOT_SET; + dcfg->reqbody_buffering = NOT_SET; + dcfg->reqbody_inmemory_limit = NOT_SET; + dcfg->reqbody_limit = NOT_SET; + dcfg->reqbody_no_files_limit = NOT_SET; + dcfg->resbody_access = NOT_SET; + + dcfg->debuglog_name = NOT_SET_P; + dcfg->debuglog_level = NOT_SET; + dcfg->debuglog_fd = NOT_SET_P; + + dcfg->of_limit = NOT_SET; + dcfg->if_limit_action = NOT_SET; + dcfg->of_limit_action = NOT_SET; + dcfg->of_mime_types = NOT_SET_P; + dcfg->of_mime_types_cleared = NOT_SET; + + dcfg->cookie_format = NOT_SET; + dcfg->argument_separator = NOT_SET; + dcfg->cookiev0_separator = NOT_SET_P; + + dcfg->rule_inheritance = NOT_SET; + dcfg->rule_exceptions = apr_array_make(mp, 16, sizeof(rule_exception *)); + dcfg->hash_method = apr_array_make(mp, 16, sizeof(hash_method *)); + + /* 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; + dcfg->auditlog_name = NOT_SET_P; + dcfg->auditlog2_name = NOT_SET_P; + dcfg->auditlog_fd = NOT_SET_P; + dcfg->auditlog2_fd = NOT_SET_P; + dcfg->auditlog_storage_dir = NOT_SET_P; + dcfg->auditlog_parts = NOT_SET_P; + dcfg->auditlog_relevant_regex = NOT_SET_P; + + dcfg->ruleset = NULL; + + /* Upload */ + dcfg->tmp_dir = NOT_SET_P; + dcfg->upload_dir = NOT_SET_P; + dcfg->upload_keep_files = NOT_SET; + dcfg->upload_validates_files = NOT_SET; + dcfg->upload_filemode = NOT_SET; + dcfg->upload_file_limit = NOT_SET; + + /* These are only used during the configuration process. */ + dcfg->tmp_chain_starter = NULL; + dcfg->tmp_default_actionset = NULL; + dcfg->tmp_rule_placeholders = NULL; + + /* Misc */ + dcfg->data_dir = NOT_SET_P; + dcfg->webappid = NOT_SET_P; + dcfg->sensor_id = NOT_SET_P; + dcfg->httpBlkey = NOT_SET_P; + + /* Content injection. */ + dcfg->content_injection_enabled = NOT_SET; + + /* Stream inspection */ + dcfg->stream_inbody_inspection = NOT_SET; + dcfg->stream_outbody_inspection = NOT_SET; + + /* Geo Lookups */ + dcfg->geo = NOT_SET_P; + + /* Gsb Lookups */ + dcfg->gsb = NOT_SET_P; + + /* Unicode Map */ + dcfg->u_map = NOT_SET_P; + + /* Cache */ + dcfg->cache_trans = NOT_SET; + dcfg->cache_trans_incremental = NOT_SET; + dcfg->cache_trans_min = NOT_SET; + dcfg->cache_trans_max = NOT_SET; + dcfg->cache_trans_maxitems = NOT_SET; + + /* Rule ids */ + dcfg->rule_id_htab = apr_hash_make(mp); + dcfg->component_signatures = apr_array_make(mp, 16, sizeof(char *)); + + dcfg->request_encoding = NOT_SET_P; + dcfg->disable_backend_compression = NOT_SET; + + /* Collection timeout */ + dcfg->col_timeout = NOT_SET; + + dcfg->crypto_key = NOT_SET_P; + dcfg->crypto_key_len = NOT_SET; + dcfg->crypto_key_add = NOT_SET; + dcfg->crypto_param_name = NOT_SET_P; + dcfg->hash_is_enabled = NOT_SET; + dcfg->hash_enforcement = NOT_SET; + dcfg->crypto_hash_href_rx = NOT_SET; + dcfg->crypto_hash_faction_rx = NOT_SET; + dcfg->crypto_hash_location_rx = NOT_SET; + dcfg->crypto_hash_iframesrc_rx = NOT_SET; + dcfg->crypto_hash_framesrc_rx = NOT_SET; + dcfg->crypto_hash_href_pm = NOT_SET; + dcfg->crypto_hash_faction_pm = NOT_SET; + dcfg->crypto_hash_location_pm = NOT_SET; + dcfg->crypto_hash_iframesrc_pm = NOT_SET; + dcfg->crypto_hash_framesrc_pm = NOT_SET; + + + /* xml external entity */ + dcfg->xml_external_entity = NOT_SET; + + return dcfg; +} + +/** + * Copies rules between one phase of two configuration contexts, + * taking exceptions into account. + */ +static void copy_rules_phase(apr_pool_t *mp, + apr_array_header_t *parent_phase_arr, + apr_array_header_t *child_phase_arr, + apr_array_header_t *exceptions_arr) +{ + rule_exception **exceptions; + msre_rule **rules; + int i, j; + int mode = 0; + + rules = (msre_rule **)parent_phase_arr->elts; + for(i = 0; i < parent_phase_arr->nelts; i++) { + msre_rule *rule = (msre_rule *)rules[i]; + int copy = 1; + + if (mode == 0) { + /* First rule in the chain. */ + exceptions = (rule_exception **)exceptions_arr->elts; + for(j = 0; j < exceptions_arr->nelts; j++) { + + /* Process exceptions. */ + switch(exceptions[j]->type) { + case RULE_EXCEPTION_REMOVE_ID : + if ((rule->actionset != NULL)&&(rule->actionset->id != NULL)) { + int ruleid = atoi(rule->actionset->id); + if (rule_id_in_range(ruleid, exceptions[j]->param)) copy--; + } + break; + case RULE_EXCEPTION_REMOVE_MSG : + if ((rule->actionset != NULL)&&(rule->actionset->msg != NULL)) { + char *my_error_msg = NULL; + + int rc = msc_regexec(exceptions[j]->param_data, + rule->actionset->msg, strlen(rule->actionset->msg), + &my_error_msg); + if (rc >= 0) copy--; + } + break; + case RULE_EXCEPTION_REMOVE_TAG : + if ((rule->actionset != NULL)&&(apr_is_empty_table(rule->actionset->actions) == 0)) { + char *my_error_msg = NULL; + const apr_array_header_t *tarr = NULL; + const apr_table_entry_t *telts = NULL; + int c; + + tarr = apr_table_elts(rule->actionset->actions); + telts = (const apr_table_entry_t*)tarr->elts; + + for (c = 0; c < tarr->nelts; c++) { + msre_action *action = (msre_action *)telts[c].val; + if(strcmp("tag", action->metadata->name) == 0) { + + int rc = msc_regexec(exceptions[j]->param_data, + action->param, strlen(action->param), + &my_error_msg); + if (rc >= 0) copy--; + } + } + } + break; + } + } + + if (copy > 0) { +#ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy rule %pp [id \"%s\"]", rule, rule->actionset->id); +#endif + + /* Copy the rule. */ + *(msre_rule **)apr_array_push(child_phase_arr) = rule; + if (rule->actionset->is_chained) mode = 2; + } else { + if (rule->actionset->is_chained) mode = 1; + } + } else { + if (mode == 2) { +#ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Copy chain %pp for rule %pp [id \"%s\"]", rule, rule->chain_starter, rule->chain_starter->actionset->id); +#endif + + /* Copy the rule (it belongs to the chain we want to include. */ + *(msre_rule **)apr_array_push(child_phase_arr) = rule; + } + + if ((rule->actionset == NULL)||(rule->actionset->is_chained == 0)) mode = 0; + } + } +} + +/** + * @brief Copies rules between one phase of two configuration contexts. + * + * Copies rules between one phase of two configuration contexts, + * taking exceptions into account. + * + * @param mp apr pool structure + * @param parent_ruleset Parent's msre_ruleset + * @param child_ruleset Child's msre_ruleset + * @param exceptions_arr Exceptions' apr_array_header_t + * @retval 0 Everything went well. + * @retval -1 Something went wrong. + * + */ +static int copy_rules(apr_pool_t *mp, msre_ruleset *parent_ruleset, + msre_ruleset *child_ruleset, + apr_array_header_t *exceptions_arr) +{ + int ret = 0; + + if (parent_ruleset == NULL || child_ruleset == NULL || + exceptions_arr == NULL) { + ret = -1; + goto failed; + } + + copy_rules_phase(mp, parent_ruleset->phase_request_headers, + child_ruleset->phase_request_headers, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_request_body, + child_ruleset->phase_request_body, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_response_headers, + child_ruleset->phase_response_headers, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_response_body, + child_ruleset->phase_response_body, exceptions_arr); + copy_rules_phase(mp, parent_ruleset->phase_logging, + child_ruleset->phase_logging, exceptions_arr); + +failed: + return ret; +} + +/** + * Merges two directory configurations. + */ +void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) +{ + directory_config *parent = (directory_config *)_parent; + directory_config *child = (directory_config *)_child; + directory_config *merged = create_directory_config(mp, NULL); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Merge parent %pp child %pp RESULT %pp", _parent, _child, merged); + #endif + + if (merged == NULL) return NULL; + + /* Use values from the child configuration where possible, + * otherwise use the parent's. + */ + + merged->is_enabled = (child->is_enabled == NOT_SET + ? parent->is_enabled : child->is_enabled); + + /* IO parameters */ + merged->reqbody_access = (child->reqbody_access == NOT_SET + ? parent->reqbody_access : child->reqbody_access); + merged->reqbody_buffering = (child->reqbody_buffering == NOT_SET + ? parent->reqbody_buffering : child->reqbody_buffering); + merged->reqbody_inmemory_limit = (child->reqbody_inmemory_limit == NOT_SET + ? parent->reqbody_inmemory_limit : child->reqbody_inmemory_limit); + merged->reqbody_limit = (child->reqbody_limit == NOT_SET + ? parent->reqbody_limit : child->reqbody_limit); + merged->reqbody_no_files_limit = (child->reqbody_no_files_limit == NOT_SET + ? parent->reqbody_no_files_limit : child->reqbody_no_files_limit); + merged->resbody_access = (child->resbody_access == NOT_SET + ? parent->resbody_access : child->resbody_access); + + merged->of_limit = (child->of_limit == NOT_SET + ? parent->of_limit : child->of_limit); + merged->if_limit_action = (child->if_limit_action == NOT_SET + ? parent->if_limit_action : child->if_limit_action); + merged->of_limit_action = (child->of_limit_action == NOT_SET + ? parent->of_limit_action : child->of_limit_action); + merged->reqintercept_oe = (child->reqintercept_oe == NOT_SET + ? parent->reqintercept_oe : child->reqintercept_oe); + + if (child->of_mime_types != NOT_SET_P) { + /* Child added to the table */ + + if (child->of_mime_types_cleared == 1) { + /* The list of MIME types was cleared in the child, + * which means the parent's MIME types went away and + * we should not take them into consideration here. + */ + merged->of_mime_types = child->of_mime_types; + merged->of_mime_types_cleared = 1; + } else { + /* Add MIME types defined in the child to those + * defined in the parent context. + */ + if (parent->of_mime_types == NOT_SET_P) { + merged->of_mime_types = child->of_mime_types; + merged->of_mime_types_cleared = NOT_SET; + } else { + merged->of_mime_types = apr_table_overlay(mp, parent->of_mime_types, + child->of_mime_types); + if (merged->of_mime_types == NULL) return NULL; + } + } + } else { + /* Child did not add to the table */ + + if (child->of_mime_types_cleared == 1) { + merged->of_mime_types_cleared = 1; + } else { + merged->of_mime_types = parent->of_mime_types; + merged->of_mime_types_cleared = parent->of_mime_types_cleared; + } + } + + /* debug log */ + if (child->debuglog_fd == NOT_SET_P) { + merged->debuglog_name = parent->debuglog_name; + merged->debuglog_fd = parent->debuglog_fd; + } else { + merged->debuglog_name = child->debuglog_name; + merged->debuglog_fd = child->debuglog_fd; + } + + merged->debuglog_level = (child->debuglog_level == NOT_SET + ? parent->debuglog_level : child->debuglog_level); + + merged->cookie_format = (child->cookie_format == NOT_SET + ? parent->cookie_format : child->cookie_format); + merged->argument_separator = (child->argument_separator == NOT_SET + ? parent->argument_separator : child->argument_separator); + merged->cookiev0_separator = (child->cookiev0_separator == NOT_SET_P + ? parent->cookiev0_separator : child->cookiev0_separator); + + + /* rule inheritance */ + if ((child->rule_inheritance == NOT_SET)||(child->rule_inheritance == 1)) { + merged->rule_inheritance = parent->rule_inheritance; + if ((child->ruleset == NULL)&&(parent->ruleset == NULL)) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "No rules in this context."); + #endif + + /* Do nothing, there are no rules in either context. */ + } else + if (child->ruleset == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent rules in this context."); + #endif + + /* Copy the rules from the parent context. */ + merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); + /* TODO: copy_rules return code should be taken into consideration. */ + copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); + } else + if (parent->ruleset == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using child rules in this context."); + #endif + + /* Copy child rules. */ + merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp); + merged->ruleset->phase_request_headers = apr_array_copy(mp, + child->ruleset->phase_request_headers); + merged->ruleset->phase_request_body = apr_array_copy(mp, + child->ruleset->phase_request_body); + merged->ruleset->phase_response_headers = apr_array_copy(mp, + child->ruleset->phase_response_headers); + merged->ruleset->phase_response_body = apr_array_copy(mp, + child->ruleset->phase_response_body); + merged->ruleset->phase_logging = apr_array_copy(mp, + child->ruleset->phase_logging); + } else { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, mp, "Using parent then child rules in this context."); + #endif + + /* Copy parent rules, then add child rules to it. */ + merged->ruleset = msre_ruleset_create(parent->ruleset->engine, mp); + /* TODO: copy_rules return code should be taken into consideration. */ + copy_rules(mp, parent->ruleset, merged->ruleset, child->rule_exceptions); + + apr_array_cat(merged->ruleset->phase_request_headers, + child->ruleset->phase_request_headers); + apr_array_cat(merged->ruleset->phase_request_body, + child->ruleset->phase_request_body); + apr_array_cat(merged->ruleset->phase_response_headers, + child->ruleset->phase_response_headers); + apr_array_cat(merged->ruleset->phase_response_body, + child->ruleset->phase_response_body); + apr_array_cat(merged->ruleset->phase_logging, + child->ruleset->phase_logging); + } + } else { + merged->rule_inheritance = 0; + if (child->ruleset != NULL) { + /* Copy child rules. */ + merged->ruleset = msre_ruleset_create(child->ruleset->engine, mp); + merged->ruleset->phase_request_headers = apr_array_copy(mp, + child->ruleset->phase_request_headers); + merged->ruleset->phase_request_body = apr_array_copy(mp, + child->ruleset->phase_request_body); + merged->ruleset->phase_response_headers = apr_array_copy(mp, + child->ruleset->phase_response_headers); + merged->ruleset->phase_response_body = apr_array_copy(mp, + child->ruleset->phase_response_body); + merged->ruleset->phase_logging = apr_array_copy(mp, + child->ruleset->phase_logging); + } + } + + /* Merge rule exceptions. */ + merged->rule_exceptions = apr_array_append(mp, parent->rule_exceptions, + child->rule_exceptions); + + merged->hash_method = apr_array_append(mp, parent->hash_method, + child->hash_method); + + /* audit log variables */ + merged->auditlog_flag = (child->auditlog_flag == NOT_SET + ? parent->auditlog_flag : child->auditlog_flag); + merged->auditlog_type = (child->auditlog_type == NOT_SET + ? parent->auditlog_type : child->auditlog_type); + merged->max_rule_time = (child->max_rule_time == NOT_SET + ? parent->max_rule_time : child->max_rule_time); + merged->auditlog_dirperms = (child->auditlog_dirperms == NOT_SET + ? parent->auditlog_dirperms : child->auditlog_dirperms); + merged->auditlog_fileperms = (child->auditlog_fileperms == NOT_SET + ? parent->auditlog_fileperms : child->auditlog_fileperms); + if (child->auditlog_fd != NOT_SET_P) { + merged->auditlog_fd = child->auditlog_fd; + merged->auditlog_name = child->auditlog_name; + } else { + merged->auditlog_fd = parent->auditlog_fd; + merged->auditlog_name = parent->auditlog_name; + } + if (child->auditlog2_fd != NOT_SET_P) { + merged->auditlog2_fd = child->auditlog2_fd; + merged->auditlog2_name = child->auditlog2_name; + } else { + 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 + ? parent->auditlog_parts : child->auditlog_parts); + merged->auditlog_relevant_regex = (child->auditlog_relevant_regex == NOT_SET_P + ? parent->auditlog_relevant_regex : child->auditlog_relevant_regex); + + /* Upload */ + merged->tmp_dir = (child->tmp_dir == NOT_SET_P + ? parent->tmp_dir : child->tmp_dir); + merged->upload_dir = (child->upload_dir == NOT_SET_P + ? parent->upload_dir : child->upload_dir); + merged->upload_keep_files = (child->upload_keep_files == NOT_SET + ? parent->upload_keep_files : child->upload_keep_files); + merged->upload_validates_files = (child->upload_validates_files == NOT_SET + ? parent->upload_validates_files : child->upload_validates_files); + merged->upload_filemode = (child->upload_filemode == NOT_SET + ? parent->upload_filemode : child->upload_filemode); + merged->upload_file_limit = (child->upload_file_limit == NOT_SET + ? parent->upload_file_limit : child->upload_file_limit); + + /* Misc */ + merged->data_dir = (child->data_dir == NOT_SET_P + ? parent->data_dir : child->data_dir); + merged->webappid = (child->webappid == NOT_SET_P + ? parent->webappid : child->webappid); + merged->sensor_id = (child->sensor_id == NOT_SET_P + ? parent->sensor_id : child->sensor_id); + merged->httpBlkey = (child->httpBlkey == NOT_SET_P + ? parent->httpBlkey : child->httpBlkey); + + /* Content injection. */ + merged->content_injection_enabled = (child->content_injection_enabled == NOT_SET + ? parent->content_injection_enabled : child->content_injection_enabled); + + /* Stream inspection */ + merged->stream_inbody_inspection = (child->stream_inbody_inspection == NOT_SET + ? parent->stream_inbody_inspection : child->stream_inbody_inspection); + merged->stream_outbody_inspection = (child->stream_outbody_inspection == NOT_SET + ? parent->stream_outbody_inspection : child->stream_outbody_inspection); + + /* Geo Lookup */ + merged->geo = (child->geo == NOT_SET_P + ? parent->geo : child->geo); + + /* Gsb Lookup */ + merged->gsb = (child->gsb == NOT_SET_P + ? parent->gsb : child->gsb); + + /* Unicode Map */ + merged->u_map = (child->u_map == NOT_SET_P + ? parent->u_map : child->u_map); + + /* Cache */ + merged->cache_trans = (child->cache_trans == NOT_SET + ? parent->cache_trans : child->cache_trans); + merged->cache_trans_incremental = (child->cache_trans_incremental == NOT_SET + ? parent->cache_trans_incremental : child->cache_trans_incremental); + merged->cache_trans_min = (child->cache_trans_min == (apr_size_t)NOT_SET + ? parent->cache_trans_min : child->cache_trans_min); + merged->cache_trans_max = (child->cache_trans_max == (apr_size_t)NOT_SET + ? parent->cache_trans_max : child->cache_trans_max); + merged->cache_trans_maxitems = (child->cache_trans_maxitems == (apr_size_t)NOT_SET + ? parent->cache_trans_maxitems : child->cache_trans_maxitems); + + /* Merge component signatures. */ + merged->component_signatures = apr_array_append(mp, parent->component_signatures, + child->component_signatures); + + merged->request_encoding = (child->request_encoding == NOT_SET_P + ? parent->request_encoding : child->request_encoding); + + merged->disable_backend_compression = (child->disable_backend_compression == NOT_SET + ? parent->disable_backend_compression : child->disable_backend_compression); + + merged->col_timeout = (child->col_timeout == NOT_SET + ? parent->col_timeout : child->col_timeout); + + /* Hash */ + merged->crypto_key = (child->crypto_key == NOT_SET_P + ? parent->crypto_key : child->crypto_key); + merged->crypto_key_len = (child->crypto_key_len == NOT_SET + ? parent->crypto_key_len : child->crypto_key_len); + merged->crypto_key_add = (child->crypto_key_add == NOT_SET + ? parent->crypto_key_add : child->crypto_key_add); + merged->crypto_param_name = (child->crypto_param_name == NOT_SET_P + ? parent->crypto_param_name : child->crypto_param_name); + merged->hash_is_enabled = (child->hash_is_enabled == NOT_SET + ? parent->hash_is_enabled : child->hash_is_enabled); + merged->hash_enforcement = (child->hash_enforcement == NOT_SET + ? parent->hash_enforcement : child->hash_enforcement); + merged->crypto_hash_href_rx = (child->crypto_hash_href_rx == NOT_SET + ? parent->crypto_hash_href_rx : child->crypto_hash_href_rx); + merged->crypto_hash_faction_rx = (child->crypto_hash_faction_rx == NOT_SET + ? parent->crypto_hash_faction_rx : child->crypto_hash_faction_rx); + merged->crypto_hash_location_rx = (child->crypto_hash_location_rx == NOT_SET + ? parent->crypto_hash_location_rx : child->crypto_hash_location_rx); + merged->crypto_hash_iframesrc_rx = (child->crypto_hash_iframesrc_rx == NOT_SET + ? parent->crypto_hash_iframesrc_rx : child->crypto_hash_iframesrc_rx); + merged->crypto_hash_framesrc_rx = (child->crypto_hash_framesrc_rx == NOT_SET + ? parent->crypto_hash_framesrc_rx : child->crypto_hash_framesrc_rx); + merged->crypto_hash_href_pm = (child->crypto_hash_href_pm == NOT_SET + ? parent->crypto_hash_href_pm : child->crypto_hash_href_pm); + merged->crypto_hash_faction_pm = (child->crypto_hash_faction_pm == NOT_SET + ? parent->crypto_hash_faction_pm : child->crypto_hash_faction_pm); + merged->crypto_hash_location_pm = (child->crypto_hash_location_pm == NOT_SET + ? parent->crypto_hash_location_pm : child->crypto_hash_location_pm); + merged->crypto_hash_iframesrc_pm = (child->crypto_hash_iframesrc_pm == NOT_SET + ? parent->crypto_hash_iframesrc_pm : child->crypto_hash_iframesrc_pm); + merged->crypto_hash_framesrc_pm = (child->crypto_hash_framesrc_pm == NOT_SET + ? parent->crypto_hash_framesrc_pm : child->crypto_hash_framesrc_pm); + + /* xml external entity */ + merged->xml_external_entity = (child->xml_external_entity == NOT_SET + ? parent->xml_external_entity : child->xml_external_entity); + + return merged; +} + +/** + * Initialise directory configuration. This function is *not* meant + * to be called for directory configuration instances created during + * the configuration phase. It can only be called on copies of those + * (created fresh for every transaction). + */ +void init_directory_config(directory_config *dcfg) +{ + if (dcfg == NULL) return; + + if (dcfg->is_enabled == NOT_SET) dcfg->is_enabled = 0; + + if (dcfg->reqbody_access == NOT_SET) dcfg->reqbody_access = 0; + if (dcfg->reqintercept_oe == NOT_SET) dcfg->reqintercept_oe = 0; + if (dcfg->reqbody_buffering == NOT_SET) dcfg->reqbody_buffering = REQUEST_BODY_FORCEBUF_OFF; + if (dcfg->reqbody_inmemory_limit == NOT_SET) + dcfg->reqbody_inmemory_limit = REQUEST_BODY_DEFAULT_INMEMORY_LIMIT; + if (dcfg->reqbody_limit == NOT_SET) dcfg->reqbody_limit = REQUEST_BODY_DEFAULT_LIMIT; + if (dcfg->reqbody_no_files_limit == NOT_SET) dcfg->reqbody_no_files_limit = REQUEST_BODY_NO_FILES_DEFAULT_LIMIT; + if (dcfg->resbody_access == NOT_SET) dcfg->resbody_access = 0; + if (dcfg->of_limit == NOT_SET) dcfg->of_limit = RESPONSE_BODY_DEFAULT_LIMIT; + if (dcfg->if_limit_action == NOT_SET) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT; + if (dcfg->of_limit_action == NOT_SET) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT; + + if (dcfg->of_mime_types == NOT_SET_P) { + dcfg->of_mime_types = apr_table_make(dcfg->mp, 3); + if (dcfg->of_mime_types_cleared != 1) { + apr_table_setn(dcfg->of_mime_types, "text/plain", "1"); + apr_table_setn(dcfg->of_mime_types, "text/html", "1"); + } + } + + if (dcfg->debuglog_fd == NOT_SET_P) dcfg->debuglog_fd = NULL; + if (dcfg->debuglog_name == NOT_SET_P) dcfg->debuglog_name = NULL; + if (dcfg->debuglog_level == NOT_SET) dcfg->debuglog_level = 0; + + if (dcfg->cookie_format == NOT_SET) dcfg->cookie_format = 0; + if (dcfg->argument_separator == NOT_SET) dcfg->argument_separator = '&'; + if (dcfg->cookiev0_separator == NOT_SET_P) dcfg->cookiev0_separator = NULL; + + if (dcfg->rule_inheritance == NOT_SET) dcfg->rule_inheritance = 1; + + /* 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; + if (dcfg->auditlog_fd == NOT_SET_P) dcfg->auditlog_fd = NULL; + if (dcfg->auditlog2_fd == NOT_SET_P) dcfg->auditlog2_fd = NULL; + if (dcfg->auditlog_name == NOT_SET_P) dcfg->auditlog_name = NULL; + if (dcfg->auditlog2_name == NOT_SET_P) dcfg->auditlog2_name = NULL; + if (dcfg->auditlog_storage_dir == NOT_SET_P) dcfg->auditlog_storage_dir = NULL; + if (dcfg->auditlog_parts == NOT_SET_P) dcfg->auditlog_parts = "ABCFHZ"; + if (dcfg->auditlog_relevant_regex == NOT_SET_P) dcfg->auditlog_relevant_regex = NULL; + + /* Upload */ + if (dcfg->tmp_dir == NOT_SET_P) dcfg->tmp_dir = guess_tmp_dir(dcfg->mp); + if (dcfg->upload_dir == NOT_SET_P) dcfg->upload_dir = NULL; + if (dcfg->upload_keep_files == NOT_SET) dcfg->upload_keep_files = KEEP_FILES_OFF; + if (dcfg->upload_validates_files == NOT_SET) dcfg->upload_validates_files = 0; + if (dcfg->upload_filemode == NOT_SET) dcfg->upload_filemode = 0600; + if (dcfg->upload_file_limit == NOT_SET) dcfg->upload_file_limit = 100; + + /* Misc */ + if (dcfg->data_dir == NOT_SET_P) dcfg->data_dir = NULL; + if (dcfg->webappid == NOT_SET_P) dcfg->webappid = "default"; + if (dcfg->sensor_id == NOT_SET_P) dcfg->sensor_id = "default"; + if (dcfg->httpBlkey == NOT_SET_P) dcfg->httpBlkey = NULL; + + /* Content injection. */ + if (dcfg->content_injection_enabled == NOT_SET) dcfg->content_injection_enabled = 0; + + /* Stream inspection */ + if (dcfg->stream_inbody_inspection == NOT_SET) dcfg->stream_inbody_inspection = 0; + if (dcfg->stream_outbody_inspection == NOT_SET) dcfg->stream_outbody_inspection = 0; + + /* Geo Lookup */ + if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL; + + /* Gsb Lookup */ + if (dcfg->gsb == NOT_SET_P) dcfg->gsb = NULL; + + /* Unicode Map */ + if (dcfg->u_map == NOT_SET_P) dcfg->u_map = NULL; + + /* Cache */ + if (dcfg->cache_trans == NOT_SET) dcfg->cache_trans = MODSEC_CACHE_DISABLED; + if (dcfg->cache_trans_incremental == NOT_SET) dcfg->cache_trans_incremental = 0; + if (dcfg->cache_trans_min == (apr_size_t)NOT_SET) dcfg->cache_trans_min = 32; + if (dcfg->cache_trans_max == (apr_size_t)NOT_SET) dcfg->cache_trans_max = 1024; + if (dcfg->cache_trans_maxitems == (apr_size_t)NOT_SET) dcfg->cache_trans_maxitems = 512; + + if (dcfg->request_encoding == NOT_SET_P) dcfg->request_encoding = NULL; + + if (dcfg->disable_backend_compression == NOT_SET) dcfg->disable_backend_compression = 0; + + 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->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; + if (dcfg->hash_enforcement == NOT_SET) dcfg->hash_enforcement = HASH_DISABLED; + if (dcfg->crypto_hash_href_rx == NOT_SET) dcfg->crypto_hash_href_rx = 0; + if (dcfg->crypto_hash_faction_rx == NOT_SET) dcfg->crypto_hash_faction_rx = 0; + if (dcfg->crypto_hash_location_rx == NOT_SET) dcfg->crypto_hash_location_rx = 0; + if (dcfg->crypto_hash_iframesrc_rx == NOT_SET) dcfg->crypto_hash_iframesrc_rx = 0; + if (dcfg->crypto_hash_framesrc_rx == NOT_SET) dcfg->crypto_hash_framesrc_rx = 0; + if (dcfg->crypto_hash_href_pm == NOT_SET) dcfg->crypto_hash_href_pm = 0; + if (dcfg->crypto_hash_faction_pm == NOT_SET) dcfg->crypto_hash_faction_pm = 0; + if (dcfg->crypto_hash_location_pm == NOT_SET) dcfg->crypto_hash_location_pm = 0; + if (dcfg->crypto_hash_iframesrc_pm == NOT_SET) dcfg->crypto_hash_iframesrc_pm = 0; + if (dcfg->crypto_hash_framesrc_pm == NOT_SET) dcfg->crypto_hash_framesrc_pm = 0; + + /* xml external entity */ + if (dcfg->xml_external_entity == NOT_SET) dcfg->xml_external_entity = 0; + +} + +/** + * + */ +static const char *add_rule(cmd_parms *cmd, directory_config *dcfg, int type, + const char *p1, const char *p2, const char *p3) +{ + char *my_error_msg = NULL; + //msre_rule *rule = NULL, *tmp_rule = NULL; + 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 + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", type, p1, p2, p3); + #endif + + /* Create a ruleset if one does not exist. */ + if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { + dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); + if (dcfg->ruleset == NULL) return FATAL_ERROR; + } + + /* Create the rule now. */ + switch(type) { + #if defined(WITH_LUA) + case RULE_TYPE_LUA : + rule = msre_rule_lua_create(dcfg->ruleset, cmd->directive->filename, + cmd->directive->line_num, p1, p2, &my_error_msg); + break; + #endif + default : + rule = msre_rule_create(dcfg->ruleset, type, cmd->directive->filename, + cmd->directive->line_num, p1, p2, p3, &my_error_msg); + break; + } + + if (rule == NULL) { + return my_error_msg; + } + +#ifndef ALLOW_ID_NOT_UNIQUE + /* Rules must have uniq ID */ + type_rule = (dcfg->tmp_chain_starter == NULL); +#if defined(WITH_LUA) + type_rule = (type != RULE_TYPE_LUA && type_rule); +#endif + 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)) { + rule_actionset = (rule->actionset->id == NOT_SET_P); +#if defined(WITH_LUA) + rule_actionset = (rule_actionset && (type != RULE_TYPE_LUA)); +#endif + if (rule_actionset) + return "ModSecurity: No action id present within the rule"; +#if defined(WITH_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"; + } else { + apr_hash_set(dcfg->rule_id_htab, apr_pstrdup(dcfg->mp, rule->actionset->id), APR_HASH_KEY_STRING, apr_pstrdup(dcfg->mp, "1")); + } + + //tmp_rule = msre_ruleset_fetch_rule(dcfg->ruleset, rule->actionset->id, offset); + //if(tmp_rule != NULL) + // 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) { + dcfg->tmp_default_actionset = msre_actionset_create_default(modsecurity->msre); + if (dcfg->tmp_default_actionset == NULL) return FATAL_ERROR; + } + + /* Check some cases prior to merging so we know where it came from */ + + /* Check syntax for chained rules */ + if ((rule->actionset != NULL) && (dcfg->tmp_chain_starter != NULL)) { + /* Must NOT specify a disruptive action. */ + if (rule->actionset->intercept_action != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions can only " + "be specified by chain starter rules."); + } + + /* Must NOT specify a skipafter action. */ + if (rule->actionset->skip_after != NOT_SET_P) { + return apr_psprintf(cmd->pool, "ModSecurity: SkipAfter actions can only " + "be specified by chain starter rules."); + } + + /* Must NOT specify a phase. */ + if (rule->actionset->phase != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: Execution phases can only be " + "specified by chain starter rules."); + } + + /* Must NOT use metadata actions. */ + /* ENH: loop through to check for tags */ + if ((rule->actionset->id != NOT_SET_P) + ||(rule->actionset->rev != NOT_SET_P) + ||(rule->actionset->msg != NOT_SET_P) + ||(rule->actionset->severity != NOT_SET) + ||(rule->actionset->version != NOT_SET_P) + ||(rule->actionset->accuracy != NOT_SET) + ||(rule->actionset->maturity != NOT_SET) + ||(rule->actionset->logdata != NOT_SET_P)) + { + return apr_psprintf(cmd->pool, "ModSecurity: Metadata actions (id, rev, msg, tag, severity, ver, accuracy, maturity, logdata) " + " can only be specified by chain starter rules."); + } + + /* Must NOT use skip. */ + if (rule->actionset->skip_count != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: The skip action can only be used " + " by chain starter rules. "); + } + } + + /* Merge actions with the parent. + * + * ENH Probably do not want this done fully for chained rules. + */ + rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, dcfg->tmp_default_actionset, + 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; + + /* Must NOT specify a disruptive action in logging phase. */ + if ((rule->actionset != NULL) + && (rule->actionset->phase == PHASE_LOGGING) + && (rule->actionset->intercept_action != ACTION_ALLOW) + && (rule->actionset->intercept_action != ACTION_ALLOW_REQUEST) + && (rule->actionset->intercept_action != ACTION_NONE) + ) { + return apr_psprintf(cmd->pool, "ModSecurity: Disruptive actions " + "cannot be specified in the logging phase."); + } + + if (dcfg->tmp_chain_starter != NULL) { + rule->chain_starter = dcfg->tmp_chain_starter; + rule->actionset->phase = rule->chain_starter->actionset->phase; + } + + if (rule->actionset->is_chained != 1) { + /* If this rule is part of the chain but does + * not want more rules to follow in the chain + * then cut it (the chain). + */ + dcfg->tmp_chain_starter = NULL; + } else { + /* On the other hand, if this rule wants other + * rules to follow it, then start a new chain + * if there isn't one already. + */ + if (dcfg->tmp_chain_starter == NULL) { + dcfg->tmp_chain_starter = rule; + } + } + + /* Create skip table if one does not already exist. */ + if (dcfg->tmp_rule_placeholders == NULL) { + dcfg->tmp_rule_placeholders = apr_table_make(cmd->pool, 10); + if (dcfg->tmp_rule_placeholders == NULL) return FATAL_ERROR; + } + + /* Keep track of any rule IDs we need to skip after */ + if (rule->actionset->skip_after != NOT_SET_P) { + char *tmp_id = apr_pstrdup(cmd->pool, rule->actionset->skip_after); + apr_table_setn(dcfg->tmp_rule_placeholders, tmp_id, tmp_id); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Watching for skipafter target rule id=\"%s\".", tmp_id); + #endif + + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding rule %pp phase=%d id=\"%s\".", rule, rule->actionset->phase, (rule->actionset->id == NOT_SET_P + ? "(none)" : rule->actionset->id)); + #endif + + /* Add rule to the recipe. */ + if (msre_ruleset_rule_add(dcfg->ruleset, rule, rule->actionset->phase) < 0) { + return "Internal Error: Failed to add rule to the ruleset."; + } + + /* Add an additional placeholder if this rule ID is on the list */ + if ((rule->actionset->id != NULL) && apr_table_get(dcfg->tmp_rule_placeholders, rule->actionset->id)) { + msre_rule *phrule = apr_palloc(rule->ruleset->mp, sizeof(msre_rule)); + if (phrule == NULL) { + return FATAL_ERROR; + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding placeholder %pp for rule %pp id=\"%s\".", phrule, rule, rule->actionset->id); + #endif + + /* shallow copy of original rule with placeholder marked as target */ + memcpy(phrule, rule, sizeof(msre_rule)); + phrule->placeholder = RULE_PH_SKIPAFTER; + + /* Add placeholder. */ + if (msre_ruleset_rule_add(dcfg->ruleset, phrule, phrule->actionset->phase) < 0) { + return "Internal Error: Failed to add placeholder to the ruleset."; + } + + /* No longer need to search for the ID */ + apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + } + + /* Update the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(dcfg->ruleset->mp, rule, NULL, NULL, NULL); + + return NULL; +} + +/** + * + */ +static const char *add_marker(cmd_parms *cmd, directory_config *dcfg, + const char *p1, const char *p2, const char *p3) +{ + char *my_error_msg = NULL; + msre_rule *rule = NULL; + extern msc_engine *modsecurity; + int p; + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Rule: type=%d p1='%s' p2='%s' p3='%s'", RULE_TYPE_MARKER, p1, p2, p3); + #endif + + /* Create a ruleset if one does not exist. */ + if ((dcfg->ruleset == NULL)||(dcfg->ruleset == NOT_SET_P)) { + dcfg->ruleset = msre_ruleset_create(modsecurity->msre, cmd->pool); + if (dcfg->ruleset == NULL) return FATAL_ERROR; + } + + /* Create the rule now. */ + rule = msre_rule_create(dcfg->ruleset, RULE_TYPE_MARKER, cmd->directive->filename, cmd->directive->line_num, p1, p2, p3, &my_error_msg); + if (rule == NULL) { + return my_error_msg; + } + + /* This is a marker */ + rule->placeholder = RULE_PH_MARKER; + + /* Add placeholder to each phase */ + for (p = PHASE_FIRST; p <= PHASE_LAST; p++) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Adding marker %pp phase=%d id=\"%s\".", rule, p, (rule->actionset->id == NOT_SET_P + ? "(none)" : rule->actionset->id)); + #endif + + if (msre_ruleset_rule_add(dcfg->ruleset, rule, p) < 0) { + return "Internal Error: Failed to add marker to the ruleset."; + } + } + + /* No longer need to search for the ID */ + if (dcfg->tmp_rule_placeholders != NULL) { + apr_table_unset(dcfg->tmp_rule_placeholders, rule->actionset->id); + } + + return NULL; +} + +/** + * + */ +static const char *update_rule_action(cmd_parms *cmd, directory_config *dcfg, + const char *p1, const char *p2, int offset) +{ + char *my_error_msg = NULL; + msre_rule *rule = NULL; + msre_actionset *new_actionset = NULL; + msre_ruleset *ruleset = dcfg->ruleset; + extern msc_engine *modsecurity; + + /* Get the ruleset if one exists */ + if ((ruleset == NULL)||(ruleset == NOT_SET_P)) { + return NULL; + } + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule id=\"%s\" with action \"%s\".", p1, p2); + #endif + + /* Fetch the rule */ + rule = msre_ruleset_fetch_rule(ruleset, p1, offset); + if (rule == NULL) { + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule id=\"%s\" with action \"%s\" failed: Rule not found.", p1, p2); + #endif + return NULL; + } + + /* Check the rule actionset */ + /* ENH: Can this happen? */ + if (rule->actionset == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Attempt to update action for rule \"%s\" failed: Rule does not have an actionset.", p1); + } + + /* Create a new actionset */ + new_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p2, &my_error_msg); + if (new_actionset == NULL) return FATAL_ERROR; + if (my_error_msg != NULL) return my_error_msg; + + /* Must NOT change an id */ + if ((new_actionset->id != NOT_SET_P) && (rule->actionset->id != NULL) && (strcmp(rule->actionset->id, new_actionset->id) != 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Rule IDs cannot be updated via SecRuleUpdateActionById."); + } + + /* Must NOT alter the phase */ + if ((new_actionset->phase != NOT_SET) && (rule->actionset->phase != new_actionset->phase)) { + return apr_psprintf(cmd->pool, "ModSecurity: Rule phases cannot be updated via SecRuleUpdateActionById."); + } + + #ifdef DEBUG_CONF + { + char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule %pp id=\"%s\" old action: \"%s\"", + rule, + (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), + actions); + } + #endif + + /* Merge new actions with the rule */ + /* ENH: Will this leak the old actionset? */ + rule->actionset = msre_actionset_merge(modsecurity->msre, cmd->pool, rule->actionset, + new_actionset, 1); + msre_actionset_set_defaults(rule->actionset); + + /* Update the unparsed rule */ + rule->unparsed = msre_rule_generate_unparsed(ruleset->mp, rule, NULL, NULL, NULL); + + #ifdef DEBUG_CONF + { + char *actions = msre_actionset_generate_action_string(ruleset->mp, rule->actionset); + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "Update rule %pp id=\"%s\" new action: \"%s\"", + rule, + (rule->actionset->id == NOT_SET_P ? "(none)" : rule->actionset->id), + actions); + } + #endif + + return NULL; +} + +/* -- Configuration directives -- */ + +static const char *cmd_action(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_ACTION, SECACTION_TARGETS, SECACTION_ARGS, p1); +} + +static const char *cmd_marker(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + const char *action = apr_pstrcat(dcfg->mp, SECMARKER_BASE_ACTIONS, p1, NULL); + return add_marker(cmd, (directory_config *)_dcfg, SECMARKER_TARGETS, SECMARKER_ARGS, action); +} + +static const char *cmd_cookiev0_separator(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (strlen(p1) != 1) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie v0 separator: %s", p1); + } + + dcfg->cookiev0_separator = p1; + + return NULL; +} + +static const char *cmd_argument_separator(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (strlen(p1) != 1) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid argument separator: %s", p1); + } + + dcfg->argument_separator = p1[0]; + + return NULL; +} + +static const char *cmd_audit_engine(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "On") == 0) dcfg->auditlog_flag = AUDITLOG_ON; + else + if (strcasecmp(p1, "Off") == 0) dcfg->auditlog_flag = AUDITLOG_OFF; + else + if (strcasecmp(p1, "RelevantOnly") == 0) dcfg->auditlog_flag = AUDITLOG_RELEVANT; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditEngine: %s", p1); + + return NULL; +} + +static const char *cmd_audit_log(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = _dcfg; + + dcfg->auditlog_name = (char *)p1; + + if (dcfg->auditlog_name[0] == '|') { + const char *pipe_name = dcfg->auditlog_name + 1; + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log pipe: %s", + pipe_name); + } + dcfg->auditlog_fd = ap_piped_log_write_fd(pipe_log); + } + 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, + dcfg->auditlog_fileperms, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the audit log file: %s", + file_name); + } + } + + return NULL; +} + +static const char *cmd_audit_log2(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = _dcfg; + + if (dcfg->auditlog_name == NOT_SET_P) { + return apr_psprintf(cmd->pool, "ModSecurity: Cannot configure a secondary audit log without a primary defined: %s", p1); + } + + dcfg->auditlog2_name = (char *)p1; + + if (dcfg->auditlog2_name[0] == '|') { + const char *pipe_name = ap_server_root_relative(cmd->pool, dcfg->auditlog2_name + 1); + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log pipe: %s", + pipe_name); + } + dcfg->auditlog2_fd = ap_piped_log_write_fd(pipe_log); + } + else { + 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, + dcfg->auditlog_fileperms, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the secondary audit log file: %s", + file_name); + } + } + + return NULL; +} + +static const char *cmd_audit_log_parts(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = _dcfg; + + if (is_valid_parts_specification((char *)p1) != 1) { + return apr_psprintf(cmd->pool, "Invalid parts specification for SecAuditLogParts: %s", p1); + } + + dcfg->auditlog_parts = (char *)p1; + return NULL; +} + +static const char *cmd_audit_log_relevant_status(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = _dcfg; + + dcfg->auditlog_relevant_regex = msc_pregcomp(cmd->pool, p1, PCRE_DOTALL, NULL, NULL); + if (dcfg->auditlog_relevant_regex == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + + return NULL; +} + +static const char *cmd_audit_log_type(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = _dcfg; + + if (strcasecmp(p1, "Serial") == 0) dcfg->auditlog_type = AUDITLOG_SERIAL; + else + if (strcasecmp(p1, "Concurrent") == 0) dcfg->auditlog_type = AUDITLOG_CONCURRENT; + else + return (const char *)apr_psprintf(cmd->pool, + "ModSecurity: Unrecognised parameter value for SecAuditLogType: %s", p1); + + 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) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_dirperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogDirMode: %s", p1); + } + + dcfg->auditlog_dirperms = mode2fileperms(mode); + } + + return NULL; +} + +static const char *cmd_audit_log_filemode(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->auditlog_fileperms = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecAuditLogFileMode: %s", p1); + } + + dcfg->auditlog_fileperms = mode2fileperms(mode); + } + + return NULL; +} + +static const char *cmd_audit_log_storage_dir(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = _dcfg; + + dcfg->auditlog_storage_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_cookie_format(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (strcmp(p1, "0") == 0) dcfg->cookie_format = COOKIES_V0; + else + if (strcmp(p1, "1") == 0) dcfg->cookie_format = COOKIES_V1; + else { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid cookie format: %s", p1); + } + + return NULL; +} + +static const char *cmd_chroot_dir(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + char cwd[1025] = ""; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecChrootDir not allowed in VirtualHost"; + } + + chroot_dir = (char *)p1; + + if (getcwd(cwd, 1024) == NULL) { + return "ModSecurity: Failed to get the current working directory"; + } + + if (chdir(chroot_dir) < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)", + chroot_dir, errno, strerror(errno)); + } + + if (chdir(cwd) < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to chdir to %s, errno=%d (%s)", + cwd, errno, strerror(errno)); + } + + return NULL; +} + +/** + * Adds component signature to the list of signatures kept in configuration. + */ +static const char *cmd_component_signature(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + /* ENH Enforce "Name/VersionX.Y.Z (comment)" format. */ + *(char **)apr_array_push(dcfg->component_signatures) = (char *)p1; + + return NULL; +} + +static const char *cmd_content_injection(cmd_parms *cmd, void *_dcfg, int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->content_injection_enabled = flag; + return NULL; +} + +static const char *cmd_data_dir(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecDataDir not allowed in VirtualHost."; + } + + dcfg->data_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_debug_log(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + apr_status_t rc; + + dcfg->debuglog_name = ap_server_root_relative(cmd->pool, p1); + + rc = apr_file_open(&dcfg->debuglog_fd, dcfg->debuglog_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open debug log file: %s", + dcfg->debuglog_name); + } + + return NULL; +} + +/** +* \brief Add SecCollectionTimeout configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_collection_timeout(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + dcfg->col_timeout = atoi(p1); + /* max 30 days */ + if ((dcfg->col_timeout >= 0)&&(dcfg->col_timeout <= 2592000)) return NULL; + + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCollectionTimeout: %s", p1); +} + +static const char *cmd_debug_log_level(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + dcfg->debuglog_level = atoi(p1); + if ((dcfg->debuglog_level >= 0)&&(dcfg->debuglog_level <= 9)) return NULL; + + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecDebugLogLevel: %s", p1); +} + +static const char *cmd_default_action(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + extern msc_engine *modsecurity; + char *my_error_msg = NULL; + + dcfg->tmp_default_actionset = msre_actionset_create(modsecurity->msre, cmd->pool, p1, &my_error_msg); + if (dcfg->tmp_default_actionset == NULL) { + if (my_error_msg != NULL) return my_error_msg; + else return FATAL_ERROR; + } + + /* Must specify a disruptive action. */ + /* ENH: Remove this requirement? */ + if (dcfg->tmp_default_actionset->intercept_action == NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a disruptive action."); + } + + /* Must specify a phase. */ + /* ENH: Remove this requirement? */ + if (dcfg->tmp_default_actionset->phase == NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must specify a phase."); + } + + /* Must not use metadata actions. */ + /* ENH: loop through to check for tags */ + if ((dcfg->tmp_default_actionset->id != NOT_SET_P) + ||(dcfg->tmp_default_actionset->rev != NOT_SET_P) + ||(dcfg->tmp_default_actionset->version != NOT_SET_P) + ||(dcfg->tmp_default_actionset->maturity != NOT_SET) + ||(dcfg->tmp_default_actionset->accuracy != NOT_SET) + ||(dcfg->tmp_default_actionset->msg != NOT_SET_P)) + { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain any metadata actions (id, rev, msg, tag, severity, ver, accuracy, maturity, logdata)."); + } + /* These are just a warning for now. */ + if ((dcfg->tmp_default_actionset->severity != NOT_SET) + ||(dcfg->tmp_default_actionset->logdata != NOT_SET_P)) + { + ap_log_perror(APLOG_MARK, + APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool, + "ModSecurity: WARNING Using \"severity\" or \"logdata\" in " + "SecDefaultAction is deprecated (%s:%d).", + cmd->directive->filename, cmd->directive->line_num); + } + + if (apr_table_get(dcfg->tmp_default_actionset->actions, "t")) { + ap_log_perror(APLOG_MARK, + APLOG_STARTUP|APLOG_WARNING|APLOG_NOERRNO, 0, cmd->pool, + "ModSecurity: WARNING Using transformations in " + "SecDefaultAction is deprecated (%s:%d).", + cmd->directive->filename, cmd->directive->line_num); + } + + /* Must not use chain. */ + if (dcfg->tmp_default_actionset->is_chained != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a chain action."); + } + + /* Must not use skip. */ + if (dcfg->tmp_default_actionset->skip_count != NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a skip action."); + } + + /* Must not use skipAfter. */ + if (dcfg->tmp_default_actionset->skip_after != NOT_SET_P) { + return apr_psprintf(cmd->pool, "ModSecurity: SecDefaultAction must not " + "contain a skipAfter action."); + } + + return NULL; +} + +static const char *cmd_disable_backend_compression(cmd_parms *cmd, void *_dcfg, int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->disable_backend_compression = flag; + return NULL; +} + +static const char *cmd_guardian_log(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + extern char *guardianlog_name; + extern apr_file_t *guardianlog_fd; + extern char *guardianlog_condition; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecGuardianLog not allowed in VirtualHost"; + } + + if (p2 != NULL) { + if (strncmp(p2, "env=", 4) != 0) { + return "ModSecurity: Error in condition clause"; + } + if ( (p2[4] == '\0') || ((p2[4] == '!')&&(p2[5] == '\0')) ) { + return "ModSecurity: Missing variable name"; + } + guardianlog_condition = apr_pstrdup(cmd->pool, p2 + 4); + } + + guardianlog_name = (char *)p1; + + if (guardianlog_name[0] == '|') { + const char *pipe_name = ap_server_root_relative(cmd->pool, guardianlog_name + 1); + piped_log *pipe_log; + + pipe_log = ap_open_piped_log(cmd->pool, pipe_name); + if (pipe_log == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log pipe: %s", + pipe_name); + } + guardianlog_fd = ap_piped_log_write_fd(pipe_log); + } + else { + const char *file_name = ap_server_root_relative(cmd->pool, guardianlog_name); + apr_status_t rc; + + rc = apr_file_open(&guardianlog_fd, file_name, + APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, + CREATEMODE, cmd->pool); + + if (rc != APR_SUCCESS) { + return apr_psprintf(cmd->pool, "ModSecurity: Failed to open the guardian log file: %s", + file_name); + } + } + + return NULL; +} + +/** +* \brief Add SecStreamInBodyInspection configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_stream_inbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->stream_inbody_inspection = flag; + return NULL; +} + + +/** +* \brief Add SecStreamOutBodyInspection configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_stream_outbody_inspection(cmd_parms *cmd, void *_dcfg, int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->stream_outbody_inspection = flag; + return NULL; +} +/** +* \brief Add SecRulePerfTime configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_rule_perf_time(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRulePerfTime: %s", p1); + } + + dcfg->max_rule_time = limit; + + return NULL; +} + +char *parser_conn_limits_operator(apr_pool_t *mp, const char *p2, + TreeRoot **whitelist, TreeRoot **suspicious_list, + const char *filename) +{ + int res = 0; + char *config_orig_path; + char *param = strchr(p2, ' '); + char *file = NULL; + char *error_msg = NULL; + param++; + + config_orig_path = apr_pstrndup(mp, filename, + strlen(filename) - strlen(apr_filepath_name_get(filename))); + + apr_filepath_merge(&file, config_orig_path, param, APR_FILEPATH_TRUENAME, + mp); + + if ((strncasecmp(p2, "!@ipMatchFromFile", strlen("!@ipMatchFromFile")) == 0) || + (strncasecmp(p2, "!@ipMatchF", strlen("!@ipMatchF")) == 0)) { + + res = ip_tree_from_file(whitelist, file, mp, &error_msg); + } + else if (strncasecmp(p2, "!@ipMatch", strlen("!@ipMatch")) == 0) { + res = ip_tree_from_param(mp, param, whitelist, &error_msg); + } + else if ((strncasecmp(p2, "@ipMatchFromFile", strlen("@ipMatchFromFile")) == 0) || + (strncasecmp(p2, "@ipMatchF", strlen("@ipMatchF")) == 0)) { + + res = ip_tree_from_file(suspicious_list, file, mp, &error_msg); + } + else if (strncasecmp(p2, "@ipMatch", strlen("@ipMatch")) == 0) { + res = ip_tree_from_param(mp, param, suspicious_list, &error_msg); + } + else { + return apr_psprintf(mp, "ModSecurity: Invalid operator for " \ + "SecConnReadStateLimit: %s, expected operators: @ipMatch, @ipMatchF " \ + "or @ipMatchFromFile with or without !", p2); + } + + if (res) { + char *error; + error = apr_psprintf(mp, "ModSecurity: failed to load IPs " \ + "from: %s", param); + + if (*error_msg) { + error = apr_psprintf(mp, "%s %s", error, error_msg); + } + + return error; + } + + return NULL; +} + + +/** +* \brief Add SecConnReadStateLimit configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* \param p2 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_conn_read_state_limit(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecConnReadStateLimit: %s", p1); + } + + if (p2 != NULL) { + char *param = parser_conn_limits_operator(cmd->pool, p2, + &conn_read_state_whitelist, &conn_read_state_suspicious_list, + cmd->directive->filename); + + if (param) + return param; + } + + conn_read_state_limit = limit; + + return NULL; +} + +static const char *cmd_read_state_limit(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "SecReadStateLimit is depricated, use SecConnReadStateLimit " \ + "instead."); + + return cmd_conn_read_state_limit(cmd, _dcfg, p1, p2); +} + +/** +* \brief Add SecConnWriteStateLimit configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* \param p2 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_conn_write_state_limit(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX) || (limit == LONG_MIN) || (limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecConnWriteStateLimit: %s", p1); + } + + if (p2 != NULL) { + char *param = parser_conn_limits_operator(cmd->pool, p2, + &conn_write_state_whitelist, &conn_write_state_suspicious_list, + cmd->directive->filename); + + if (param) + return param; + } + + conn_write_state_limit = limit; + + return NULL; +} +static const char *cmd_write_state_limit(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, + "SecWriteStateLimit is depricated, use SecConnWriteStateLimit " \ + "instead."); + + return cmd_conn_write_state_limit(cmd, _dcfg, p1, p2); +} + + + +static const char *cmd_request_body_inmemory_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyInMemoryLimit: %s", p1); + } + + dcfg->reqbody_inmemory_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimit: %s", p1); + } + + dcfg->reqbody_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_no_files_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + if (dcfg == NULL) return NULL; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyNoFilesLimit: %s", p1); + } + + dcfg->reqbody_no_files_limit = limit; + + return NULL; +} + +static const char *cmd_request_body_access(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->reqbody_access = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->reqbody_access = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyAccess: %s", p1); + + return NULL; +} + +/** +* \brief Add SecInterceptOnError configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On success +*/ +static const char *cmd_request_intercept_on_error(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->reqintercept_oe = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->reqintercept_oe = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecInterceptOnError: %s", p1); + + return NULL; +} + + +static const char *cmd_request_encoding(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + /* ENH Validate encoding */ + + dcfg->request_encoding = p1; + + return NULL; +} + +static const char *cmd_response_body_access(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) dcfg->resbody_access = 1; + else + if (strcasecmp(p1, "off") == 0) dcfg->resbody_access = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyAccess: %s", p1); + + return NULL; +} + +static const char *cmd_response_body_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + long int limit; + + limit = strtol(p1, NULL, 10); + if ((limit == LONG_MAX)||(limit == LONG_MIN)||(limit <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimit: %s", p1); + } + + if (limit > RESPONSE_BODY_HARD_LIMIT) { + return apr_psprintf(cmd->pool, "ModSecurity: Response size limit can not exceed the hard limit: %li", RESPONSE_BODY_HARD_LIMIT); + } + + dcfg->of_limit = limit; + + return NULL; +} + +static const char *cmd_response_body_limit_action(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { + dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL; + return NULL; + } + + if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL; + else + if (strcasecmp(p1, "Reject") == 0) dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_REJECT; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecResponseBodyLimitAction: %s", p1); + + return NULL; +} + +/** +* \brief Add SecRequestBodyLimitAction configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On success +*/ +static const char *cmd_resquest_body_limit_action(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (dcfg->is_enabled == MODSEC_DETECTION_ONLY) { + dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL; + return NULL; + } + + if (strcasecmp(p1, "ProcessPartial") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL; + else + if (strcasecmp(p1, "Reject") == 0) dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_REJECT; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecRequestBodyLimitAction: %s", p1); + + return NULL; +} + +static const char *cmd_response_body_mime_type(cmd_parms *cmd, void *_dcfg, + const char *_p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + char *p1 = apr_pstrdup(cmd->pool, _p1); + + /* TODO check whether the parameter is a valid MIME type of "???" */ + + if ((dcfg->of_mime_types == NULL)||(dcfg->of_mime_types == NOT_SET_P)) { + dcfg->of_mime_types = apr_table_make(cmd->pool, 10); + } + + strtolower_inplace((unsigned char *)p1); + apr_table_setn(dcfg->of_mime_types, p1, "1"); + + return NULL; +} + +static const char *cmd_response_body_mime_types_clear(cmd_parms *cmd, + void *_dcfg) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + dcfg->of_mime_types_cleared = 1; + + if ((dcfg->of_mime_types != NULL)&&(dcfg->of_mime_types != NOT_SET_P)) { + apr_table_clear(dcfg->of_mime_types); + } + + return NULL; +} + +/** + * \brief Add SecRuleUpdateTargetById + * + * \param cmd Pointer to configuration data + * \param _dcfg Pointer to directory configuration + * \param p1 Pointer to configuration option + * \param p2 Pointer to configuration option + * \param p3 Pointer to configuration option + * + * \retval NULL On failure|Success + */ +static const char *cmd_rule_update_target_by_id(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2, const char *p3) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + if(p1 == NULL) { + return apr_psprintf(cmd->pool, "Updating target by ID with no ID"); + } + + re->type = RULE_EXCEPTION_REMOVE_ID; + /* TODO: Validate the range here, while we can still tell the user if it's invalid */ + re->param = p1; + + if(dcfg->ruleset == NULL) { + return apr_psprintf(cmd->pool, "Updating target by ID with no ruleset in this context"); + } + + return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3); +} + +/** + * \brief Add SecRuleUpdateTargetByTag configuration option + * + * \param cmd Pointer to configuration data + * \param _dcfg Pointer to directory configuration + * \param p1 Pointer to configuration option RULETAG + * \param p2 Pointer to configuration option TARGET + * \param p3 Pointer to configuration option REPLACED_TARGET + * \todo Finish documenting + * + * \retval NULL On success + * \retval apr_psprintf On failure + * + * \todo Figure out error checking + */ +static const char *cmd_rule_update_target_by_tag(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2, const char *p3) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + if(p1 == NULL) { + return apr_psprintf(cmd->pool, "Updating target by tag with no tag"); + } + + re->type = RULE_EXCEPTION_REMOVE_TAG; + re->param = p1; + re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + + return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3); +} +/** + * \brief Add SecRuleUpdateTargetByMsg configuration option + * + * \param cmd Pointer to configuration data + * \param _dcfg Pointer to directory configuration + * \param p1 Pointer to configuration option RULEMSG + * \param p2 Pointer to configuration option TARGET + * \param p3 Pointer to configuration option REPLACED_TARGET + * \todo Finish documenting + * + * \retval NULL On success + * \retval apr_psprintf On failure + * + * \todo Figure out error checking + */ +static const char *cmd_rule_update_target_by_msg(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2, const char *p3) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + if(p1 == NULL) { + return apr_psprintf(cmd->pool, "Updating target by message with no message"); + } + + re->type = RULE_EXCEPTION_REMOVE_MSG; + re->param = p1; + re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + + return msre_ruleset_rule_update_target_matching_exception(NULL, dcfg->ruleset, re, p2, p3); +} + + +static const char *cmd_rule(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2, const char *p3) +{ + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_NORMAL, p1, p2, p3); +} + +static const char *cmd_sever_conn_filters_engine(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + { + conn_limits_filter_state = MODSEC_ENABLED; + } + else if (strcasecmp(p1, "off") == 0) + { + conn_limits_filter_state = MODSEC_DISABLED; + } + else if (strcasecmp(p1, "detectiononly") == 0) + { + conn_limits_filter_state = MODSEC_DETECTION_ONLY; + } + else + { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecConnEngine: %s", p1); + } + + return NULL; +} + +static const char *cmd_rule_engine(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + { + dcfg->is_enabled = MODSEC_ENABLED; + } + else if (strcasecmp(p1, "off") == 0) + { + dcfg->is_enabled = MODSEC_DISABLED; + } + else if (strcasecmp(p1, "detectiononly") == 0) + { + dcfg->is_enabled = MODSEC_DETECTION_ONLY; + dcfg->of_limit_action = RESPONSE_BODY_LIMIT_ACTION_PARTIAL; + dcfg->if_limit_action = REQUEST_BODY_LIMIT_ACTION_PARTIAL; + } + else + { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecRuleEngine: %s", p1); + } + + return NULL; +} + +static const char *cmd_remote_rules_fail(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + if (strncasecmp(p1, "warn", 4) == 0) + { + remote_rules_fail_action = REMOTE_RULES_WARN_ON_FAIL; + } + else if (strncasecmp(p1, "abort", 5) == 0) + { + remote_rules_fail_action = REMOTE_RULES_ABORT_ON_FAIL; + } + else + { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecRemoteRulesFailAction, expected: Abort or Warn."); + } + + return NULL; +} + +static const char *cmd_remote_rules(cmd_parms *cmd, void *_dcfg, const char *p1, + const char *p2, const char *p3) +{ + char *error_msg = NULL; + directory_config *dcfg = (directory_config *)_dcfg; +#ifdef WITH_REMOTE_RULES + int crypto = 0; + const char *uri = p2; + const char *key = p1; +#endif + + if (dcfg == NULL) return NULL; + +#ifdef WITH_REMOTE_RULES + if (strncasecmp(p1, "crypto", 6) == 0) + { +#ifdef WITH_APU_CRYPTO + uri = p3; + key = p2; + crypto = 1; +#else + return apr_psprintf(cmd->pool, "ModSecurity: SecRemoteRule using " \ + "`crypto' but ModSecurity was not compiled with crypto " \ + "support."); +#endif + } + + if (uri == NULL || key == NULL) + { + return apr_psprintf(cmd->pool, "ModSecurity: Use SecRemoteRule with " \ + "Key and URI"); + } + + if (strncasecmp(uri, "https", 5) != 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid URI:" \ + " '%s'. Expected HTTPS.", uri); + } + + // FIXME: Should we handle more then one server at once? + if (remote_rules_server != NULL) + { + return apr_psprintf(cmd->pool, "ModSecurity: " \ + "SecRemoteRules cannot be used more than once."); + } + + remote_rules_server = apr_pcalloc(cmd->pool, sizeof(msc_remote_rules_server)); + if (remote_rules_server == NULL) + { + return apr_psprintf(cmd->pool, "ModSecurity: " \ + "SecRemoteRules: Internal failure. Not enougth memory."); + } + + remote_rules_server->context = dcfg; + remote_rules_server->context_label = apr_pstrdup(cmd->pool, "Unkwon context"); + remote_rules_server->key = key; + remote_rules_server->uri = uri; + remote_rules_server->amount_of_rules = 0; + remote_rules_server->crypto = crypto; + + msc_remote_add_rules_from_uri(cmd, remote_rules_server, &error_msg); + if (error_msg != NULL) + { + return error_msg; + } +#else + return apr_psprintf(cmd->pool, "ModSecurity: SecRemoteRules: " \ + "ModSecurity was not compiled with SecRemoteRules support."); +#endif + + return NULL; +} + + +static const char *cmd_status_engine(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + if (strcasecmp(p1, "on") == 0) { + status_engine_state = STATUS_ENGINE_ENABLED; + } + else if (strcasecmp(p1, "off") == 0) { + status_engine_state = STATUS_ENGINE_DISABLED; + } + else { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for " \ + "SecStatusEngine: %s", p1); + } + + return NULL; +} + + +static const char *cmd_rule_inheritance(cmd_parms *cmd, void *_dcfg, int flag) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + dcfg->rule_inheritance = flag; + return NULL; +} + +static const char *cmd_rule_script(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + #if defined(WITH_LUA) + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + return add_rule(cmd, (directory_config *)_dcfg, RULE_TYPE_LUA, filename, p2, NULL); + #else + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Ignoring SecRuleScript \"%s\" directive (%s:%d): No Lua scripting support.", p1, cmd->directive->filename, cmd->directive->line_num); + return NULL; + #endif +} + +static const char *cmd_rule_remove_by_id(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_REMOVE_ID; + re->param = p1; + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + /* Remove the corresponding rules from the context straight away. */ + msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re); + + return NULL; +} + +/** +* \brief Add SecRuleRemoveByTag configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On success +*/ +static const char *cmd_rule_remove_by_tag(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_REMOVE_TAG; + re->param = p1; + re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + /* Remove the corresponding rules from the context straight away. */ + msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg); + #endif + + return NULL; +} + +static const char *cmd_rule_remove_by_msg(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(rule_exception)); + if (dcfg == NULL) return NULL; + + re->type = RULE_EXCEPTION_REMOVE_MSG; + re->param = p1; + re->param_data = msc_pregcomp(cmd->pool, p1, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p1); + } + *(rule_exception **)apr_array_push(dcfg->rule_exceptions) = re; + + /* Remove the corresponding rules from the context straight away. */ + msre_ruleset_rule_remove_with_exception(dcfg->ruleset, re); + + #ifdef DEBUG_CONF + ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_NOERRNO, 0, cmd->pool, "Added exception %pp (%d %s) to dcfg %pp.", re, re->type, re->param, dcfg); + #endif + + return NULL; +} + +static const char *cmd_rule_update_action_by_id(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + int offset = 0, rule_id = atoi(p1); + char *opt = strchr(p1,':'); + char *savedptr = NULL; + char *param = apr_pstrdup(cmd->pool, p1); + + if ((rule_id == LONG_MAX)||(rule_id == LONG_MIN)||(rule_id <= 0)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for ID for update action: %s", p1); + } + + if(opt != NULL) { + opt++; + offset = atoi(opt); + opt = apr_strtok(param,":", &savedptr); + return update_rule_action(cmd, (directory_config *)_dcfg, (const char *)opt, p2, offset); + } + + return update_rule_action(cmd, (directory_config *)_dcfg, p1, p2, offset); +} + +static const char *cmd_server_signature(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + if (cmd->server->is_virtual) { + return "ModSecurity: SecServerSignature not allowed in VirtualHost"; + } + new_server_signature = (char *)p1; + return NULL; +} + +static const char *cmd_tmp_dir(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "none") == 0) dcfg->tmp_dir = NULL; + else dcfg->tmp_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_upload_dir(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "none") == 0) dcfg->upload_dir = NULL; + else dcfg->upload_dir = ap_server_root_relative(cmd->pool, p1); + + return NULL; +} + +static const char *cmd_upload_file_limit(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->upload_file_limit = NOT_SET; + } + else { + dcfg->upload_file_limit = atoi(p1); + } + + return NULL; +} + +static const char *cmd_upload_filemode(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "default") == 0) { + dcfg->upload_filemode = NOT_SET; + } + else { + long int mode = strtol(p1, NULL, 8); /* expects octal mode */ + if ((mode == LONG_MAX)||(mode == LONG_MIN)||(mode <= 0)||(mode > 07777)) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecUploadFileMode: %s", p1); + } + + dcfg->upload_filemode = (int)mode; + } + + return NULL; +} + +static const char *cmd_upload_keep_files(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) { + dcfg->upload_keep_files = KEEP_FILES_ON; + } else + if (strcasecmp(p1, "off") == 0) { + dcfg->upload_keep_files = KEEP_FILES_OFF; + } else + if (strcasecmp(p1, "relevantonly") == 0) { + dcfg->upload_keep_files = KEEP_FILES_RELEVANT_ONLY; + } else { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecUploadKeepFiles: %s", + p1); + } + return NULL; +} + +static const char *cmd_upload_save_tmp_files(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + { + dcfg->upload_validates_files = 1; + } + else if (strcasecmp(p1, "off") == 0) + { + dcfg->upload_validates_files = 0; + } + else + { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for SecTmpSaveUploadedFiles: %s", + p1); + } + + return NULL; +} + +static const char *cmd_web_app_id(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + /* ENH enforce format (letters, digits, ., _, -) */ + dcfg->webappid = p1; + + return NULL; +} + +static const char *cmd_sensor_id(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + /* ENH enforce format (letters, digits, ., _, -) */ + dcfg->sensor_id = p1; + + return NULL; +} + +/** +* \brief Add SecXmlExternalEntity configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_xml_external_entity(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) { + dcfg->xml_external_entity = 1; + } + else if (strcasecmp(p1, "off") == 0) { + dcfg->xml_external_entity = 0; + } + else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecXmlExternalEntity: %s", p1); + + return NULL; +} + + +/** +* \brief Add SecHashEngine configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_hash_engine(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) { + dcfg->hash_is_enabled = HASH_ENABLED; + dcfg->hash_enforcement = HASH_ENABLED; + } + else if (strcasecmp(p1, "off") == 0) { + dcfg->hash_is_enabled = HASH_DISABLED; + dcfg->hash_enforcement = HASH_DISABLED; + } + else return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecHashEngine: %s", p1); + + return NULL; +} + +/** +* \brief Add SecHashPram configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_hash_param(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (p1 == NULL) return NULL; + dcfg->crypto_param_name = p1; + + return NULL; +} + +/** +* \brief Add SecHashKey configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param _p1 Pointer to configuration option +* \param _p2 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_hash_key(cmd_parms *cmd, void *_dcfg, const char *_p1, const char *_p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + char *p1 = NULL; + + if (dcfg == NULL) return NULL; + if (_p1 == NULL) return NULL; + + if (strcasecmp(_p1, "Rand") == 0) { + p1 = apr_pstrdup(cmd->pool, getkey(cmd->pool)); + dcfg->crypto_key = p1; + dcfg->crypto_key_len = strlen(dcfg->crypto_key); + } else { + p1 = apr_pstrdup(cmd->pool, _p1); + dcfg->crypto_key = p1; + dcfg->crypto_key_len = strlen(p1); + } + + if(_p2 == NULL) { + return NULL; + } else { + if (strcasecmp(_p2, "KeyOnly") == 0) + dcfg->crypto_key_add = HASH_KEYONLY; + else if (strcasecmp(_p2, "SessionID") == 0) + dcfg->crypto_key_add = HASH_SESSIONID; + else if (strcasecmp(_p2, "RemoteIP") == 0) + dcfg->crypto_key_add = HASH_REMOTEIP; + } + return NULL; +} + +/** +* \brief Add SecHashMethodPm configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* \param p2 Pointer to configuration option +* +* \retval NULL On failure +* \retval apr_psprintf On Success +*/ +static const char *cmd_hash_method_pm(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); + const char *_p2 = apr_pstrdup(cmd->pool, p2); + ACMP *p = NULL; + const char *phrase = NULL; + const char *next = NULL; + + if (dcfg == NULL) return NULL; + + p = acmp_create(0, cmd->pool); + if (p == NULL) return NULL; + + if(phrase == NULL) + phrase = apr_pstrdup(cmd->pool, _p2); + + for (;;) { + while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++; + if (*phrase == '\0') break; + next = phrase; + while((apr_isspace(*next) == 0) && (*next != 0)) next++; + acmp_add_pattern(p, phrase, NULL, NULL, next - phrase); + phrase = next; + } + + acmp_prepare(p); + + if (strcasecmp(p1, "HashHref") == 0) { + re->type = HASH_URL_HREF_HASH_PM; + re->param = _p2; + re->param_data = (void *)p; + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2); + } + dcfg->crypto_hash_href_pm = 1; + } + else if (strcasecmp(p1, "HashFormAction") == 0) { + re->type = HASH_URL_FACTION_HASH_PM; + re->param = _p2; + re->param_data = (void *)p; + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2); + } + dcfg->crypto_hash_faction_pm = 1; + } + else if (strcasecmp(p1, "HashLocation") == 0) { + re->type = HASH_URL_LOCATION_HASH_PM; + re->param = _p2; + re->param_data = (void *)p; + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2); + } + dcfg->crypto_hash_location_pm = 1; + } + else if (strcasecmp(p1, "HashIframeSrc") == 0) { + re->type = HASH_URL_IFRAMESRC_HASH_PM; + re->param = _p2; + re->param_data = (void *)p; + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2); + } + dcfg->crypto_hash_iframesrc_pm = 1; + } + else if (strcasecmp(p1, "HashFrameSrc") == 0) { + re->type = HASH_URL_FRAMESRC_HASH_PM; + re->param = _p2; + re->param_data = (void *)p; + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid pattern: %s", p2); + } + dcfg->crypto_hash_framesrc_pm = 1; + } + + *(hash_method **)apr_array_push(dcfg->hash_method) = re; + + return NULL; +} + +/** + * \brief Add SecHashMethodRx configuration option + * + * \param cmd Pointer to configuration data + * \param _dcfg Pointer to directory configuration + * \param p1 Pointer to configuration option + * \param p2 Pointer to configuration option + * + * \retval NULL On failure + * \retval apr_psprintf On Success + */ +static const char *cmd_hash_method_rx(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + rule_exception *re = apr_pcalloc(cmd->pool, sizeof(hash_method)); + const char *_p2 = apr_pstrdup(cmd->pool, p2); + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "HashHref") == 0) { + re->type = HASH_URL_HREF_HASH_RX; + re->param = _p2; + re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2); + } + dcfg->crypto_hash_href_rx = 1; + } + else if (strcasecmp(p1, "HashFormAction") == 0) { + re->type = HASH_URL_FACTION_HASH_RX; + re->param = _p2; + re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2); + } + dcfg->crypto_hash_faction_rx = 1; + } + else if (strcasecmp(p1, "HashLocation") == 0) { + re->type = HASH_URL_LOCATION_HASH_RX; + re->param = _p2; + re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2); + } + dcfg->crypto_hash_location_rx = 1; + } + else if (strcasecmp(p1, "HashIframeSrc") == 0) { + re->type = HASH_URL_IFRAMESRC_HASH_RX; + re->param = _p2; + re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2); + } + dcfg->crypto_hash_iframesrc_rx = 1; + } + else if (strcasecmp(p1, "HashFrameSrc") == 0) { + re->type = HASH_URL_FRAMESRC_HASH_RX; + re->param = _p2; + re->param_data = msc_pregcomp(cmd->pool, p2, 0, NULL, NULL); + if (re->param_data == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid regular expression: %s", p2); + } + dcfg->crypto_hash_framesrc_rx = 1; + } + + *(hash_method **)apr_array_push(dcfg->hash_method) = re; + + return NULL; +} + +/** +* \brief Add SecHttpBlKey configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_httpBl_key(cmd_parms *cmd, void *_dcfg, const char *p1) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (p1 == NULL) return NULL; + dcfg->httpBlkey = p1; + + return NULL; +} + +/* PCRE Limits */ + +static const char *cmd_pcre_match_limit(cmd_parms *cmd, + void *_dcfg, const char *p1) +{ + long val; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecPcreMatchLimit not allowed in VirtualHost"; + } + + val = atol(p1); + if (val <= 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for " + "SecPcreMatchLimit: %s", p1); + } + msc_pcre_match_limit = (unsigned long int)val; + + return NULL; +} + +static const char *cmd_pcre_match_limit_recursion(cmd_parms *cmd, + void *_dcfg, const char *p1) +{ + long val; + + if (cmd->server->is_virtual) { + return "ModSecurity: SecPcreMatchLimitRecursion not allowed in VirtualHost"; + } + + val = atol(p1); + if (val <= 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for " + "SecPcreMatchLimitRecursion: %s", p1); + } + msc_pcre_match_limit_recursion = (unsigned long int)val; + + return NULL; +} + + +/* -- Geo Lookup configuration -- */ + +static const char *cmd_geo_lookup_db(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + char *error_msg; + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (geo_init(dcfg, filename, &error_msg) <= 0) { + return error_msg; + } + + return NULL; +} + +/** +* \brief Add SecUnicodeCodePage configuration option +* +* Depcrecated +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_unicode_codepage(cmd_parms *cmd, + void *_dcfg, const char *p1) +{ + long val; + + val = atol(p1); + if (val <= 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for " + "SecUnicodeCodePage: %s", p1); + } + + unicode_codepage = (unsigned long int)val; + + return NULL; +} + +/** +* \brief Add SecUnicodeMapFile configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_unicode_map(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + char *error_msg; + long val = 0; + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if(p2 != NULL) { + val = atol(p2); + if (val <= 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Invalid setting for " + "SecUnicodeMapFile: %s", p2); + } + + unicode_codepage = (unsigned long int)val; + } + + if (unicode_map_init(dcfg, filename, &error_msg) <= 0) { + return error_msg; + } + + return NULL; +} + +/** +* \brief Add SecGsbLookupDb configuration option +* +* \param cmd Pointer to configuration data +* \param _dcfg Pointer to directory configuration +* \param p1 Pointer to configuration option +* +* \retval NULL On success +*/ +static const char *cmd_gsb_lookup_db(cmd_parms *cmd, void *_dcfg, + const char *p1) +{ + const char *filename = resolve_relative_path(cmd->pool, cmd->directive->filename, p1); + char *error_msg; + directory_config *dcfg = (directory_config *)_dcfg; + if (dcfg == NULL) return NULL; + + if (gsb_db_init(dcfg, filename, &error_msg) <= 0) { + return error_msg; + } + + return NULL; +} + +/* -- Cache -- */ + +static const char *cmd_cache_transformations(cmd_parms *cmd, void *_dcfg, + const char *p1, const char *p2) +{ + directory_config *dcfg = (directory_config *)_dcfg; + + if (dcfg == NULL) return NULL; + + if (strcasecmp(p1, "on") == 0) + dcfg->cache_trans = MODSEC_CACHE_ENABLED; + else if (strcasecmp(p1, "off") == 0) + dcfg->cache_trans = MODSEC_CACHE_DISABLED; + else + return apr_psprintf(cmd->pool, "ModSecurity: Invalid value for SecCacheTransformations: %s", p1); + + /* Process options */ + if (p2 != NULL) { + apr_table_t *vartable = apr_table_make(cmd->pool, 4); + apr_status_t rc; + char *error_msg = NULL; + const char *charval = NULL; + apr_int64_t intval = 0; + + if (vartable == NULL) { + return apr_psprintf(cmd->pool, "ModSecurity: Unable to process options for SecCacheTransformations"); + } + rc = msre_parse_generic(cmd->pool, p2, vartable, &error_msg); + if (rc < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: Unable to parse options for SecCacheTransformations: %s", error_msg); + } + + /* incremental */ + charval = apr_table_get(vartable, "incremental"); + if (charval != NULL) { + if (strcasecmp(charval, "on") == 0) + dcfg->cache_trans_incremental = 1; + else if (strcasecmp(charval, "off") == 0) + dcfg->cache_trans_incremental = 0; + else + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations invalid incremental value: %s", charval); + } + + /* minlen */ + charval = apr_table_get(vartable, "minlen"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be positive: %s", charval); + } + + /* The NOT_SET indicator is -1, a signed long, and therfore + * we cannot be >= the unsigned value of NOT_SET. + */ + if ((unsigned long)intval >= (unsigned long)NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations minlen must be less than: %lu", (unsigned long)NOT_SET); + } + dcfg->cache_trans_min = (apr_size_t)intval; + } + + /* maxlen */ + charval = apr_table_get(vartable, "maxlen"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be positive: %s", charval); + } + + /* The NOT_SET indicator is -1, a signed long, and therfore + * we cannot be >= the unsigned value of NOT_SET. + */ + if ((unsigned long)intval >= (unsigned long)NOT_SET) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must be less than: %lu", (unsigned long)NOT_SET); + } + if ((intval != 0) && ((apr_size_t)intval < dcfg->cache_trans_min)) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxlen must not be less than minlen: %lu < %" APR_SIZE_T_FMT, (unsigned long)intval, dcfg->cache_trans_min); + } + dcfg->cache_trans_max = (apr_size_t)intval; + + } + + /* maxitems */ + charval = apr_table_get(vartable, "maxitems"); + if (charval != NULL) { + intval = apr_atoi64(charval); + if (errno == ERANGE) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems out of range: %s", charval); + } + if (intval < 0) { + return apr_psprintf(cmd->pool, "ModSecurity: SecCacheTransformations maxitems must be positive: %s", charval); + } + dcfg->cache_trans_maxitems = (apr_size_t)intval; + } + } + + return NULL; +} + + +/* -- Configuration directives definitions -- */ + +#define CMD_SCOPE_MAIN (RSRC_CONF) +#define CMD_SCOPE_ANY (RSRC_CONF | ACCESS_CONF) + +#if defined(HTACCESS_CONFIG) +#define CMD_SCOPE_HTACCESS (OR_OPTIONS) +#endif + +const command_rec module_directives[] = { + +#ifdef HTACCESS_CONFIG + AP_INIT_TAKE1 ( + "SecAction", + cmd_action, + NULL, + CMD_SCOPE_HTACCESS, + "an action list" + ), +#else + AP_INIT_TAKE1 ( + "SecAction", + cmd_action, + NULL, + CMD_SCOPE_ANY, + "an action list" + ), +#endif + + AP_INIT_TAKE1 ( + "SecArgumentSeparator", + cmd_argument_separator, + NULL, + CMD_SCOPE_ANY, + "character that will be used as separator when parsing application/x-www-form-urlencoded content." + ), + + AP_INIT_TAKE1 ( + "SecCookiev0Separator", + cmd_cookiev0_separator, + NULL, + CMD_SCOPE_ANY, + "character that will be used as separator when parsing cookie v0 content." + ), + + AP_INIT_TAKE1 ( + "SecAuditEngine", + cmd_audit_engine, + NULL, + CMD_SCOPE_ANY, + "On, Off or RelevantOnly to determine the level of audit logging" + ), + + AP_INIT_TAKE1 ( + "SecAuditLog", + cmd_audit_log, + NULL, + CMD_SCOPE_ANY, + "filename of the primary audit log file" + ), + + AP_INIT_TAKE1 ( + "SecAuditLog2", + cmd_audit_log2, + NULL, + CMD_SCOPE_ANY, + "filename of the secondary audit log file" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogParts", + cmd_audit_log_parts, + NULL, + CMD_SCOPE_ANY, + "list of audit log parts that go into the log." + ), + + AP_INIT_TAKE1 ( + "SecAuditLogRelevantStatus", + cmd_audit_log_relevant_status, + NULL, + CMD_SCOPE_ANY, + "regular expression that will be used to determine if the response status is relevant for audit logging" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogType", + cmd_audit_log_type, + NULL, + CMD_SCOPE_ANY, + "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, + NULL, + CMD_SCOPE_ANY, + "path to the audit log storage area; absolute, or relative to the root of the server" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogDirMode", + cmd_audit_log_dirmode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log directories" + ), + + AP_INIT_TAKE1 ( + "SecAuditLogFileMode", + cmd_audit_log_filemode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for concurrent audit log files" + ), + + AP_INIT_TAKE12 ( + "SecCacheTransformations", + cmd_cache_transformations, + NULL, + CMD_SCOPE_ANY, + "whether or not to cache transformations. Defaults to true." + ), + + AP_INIT_TAKE1 ( + "SecChrootDir", + cmd_chroot_dir, + NULL, + CMD_SCOPE_MAIN, + "path of the directory to which server will be chrooted" + ), + + AP_INIT_TAKE1 ( + "SecComponentSignature", + cmd_component_signature, + NULL, + CMD_SCOPE_MAIN, + "component signature to add to ModSecurity signature." + ), + + AP_INIT_FLAG ( + "SecContentInjection", + cmd_content_injection, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_FLAG ( + "SecStreamOutBodyInspection", + cmd_stream_outbody_inspection, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_FLAG ( + "SecStreamInBodyInspection", + cmd_stream_inbody_inspection, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecCookieFormat", + cmd_cookie_format, + NULL, + CMD_SCOPE_ANY, + "version of the Cookie specification to use for parsing. Possible values are 0 and 1." + ), + + AP_INIT_TAKE1 ( + "SecDataDir", + cmd_data_dir, + NULL, + CMD_SCOPE_MAIN, + "path to the persistent data storage area" // TODO + ), + + AP_INIT_TAKE1 ( + "SecDebugLog", + cmd_debug_log, + NULL, + CMD_SCOPE_ANY, + "path to the debug log file" + ), + + AP_INIT_TAKE1 ( + "SecDebugLogLevel", + cmd_debug_log_level, + NULL, + CMD_SCOPE_ANY, + "debug log level, which controls the verbosity of logging." + " Use values from 0 (no logging) to 9 (a *lot* of logging)." + ), + + AP_INIT_TAKE1 ( + "SecCollectionTimeout", + cmd_collection_timeout, + NULL, + CMD_SCOPE_ANY, + "set default collections timeout. default it 3600" + ), + + AP_INIT_TAKE1 ( + "SecDefaultAction", + cmd_default_action, + NULL, + CMD_SCOPE_ANY, + "default action list" + ), + + AP_INIT_FLAG ( + "SecDisableBackendCompression", + cmd_disable_backend_compression, + NULL, + CMD_SCOPE_ANY, + "When set to On, removes the compression headers from the backend requests." + ), + + AP_INIT_TAKE1 ( + "SecGsbLookupDB", + cmd_gsb_lookup_db, + NULL, + RSRC_CONF, + "database google safe browsing" + ), + + AP_INIT_TAKE1 ( + "SecUnicodeCodePage", + cmd_unicode_codepage, + NULL, + CMD_SCOPE_MAIN, + "Unicode CodePage" + ), + + AP_INIT_TAKE12 ( + "SecUnicodeMapFile", + cmd_unicode_map, + NULL, + CMD_SCOPE_MAIN, + "Unicode Map file" + ), + + AP_INIT_TAKE1 ( + "SecGeoLookupDB", + cmd_geo_lookup_db, + NULL, + RSRC_CONF, + "database for geographical lookups module." + ), + + AP_INIT_TAKE12 ( + "SecGuardianLog", + cmd_guardian_log, + NULL, + CMD_SCOPE_MAIN, + "The filename of the filter debugging log file" + ), + + AP_INIT_TAKE1 ( + "SecMarker", + cmd_marker, + NULL, + CMD_SCOPE_ANY, + "marker for a skipAfter target" + ), + + AP_INIT_TAKE1 ( + "SecPcreMatchLimit", + cmd_pcre_match_limit, + NULL, + CMD_SCOPE_MAIN, + "PCRE match limit" + ), + + AP_INIT_TAKE1 ( + "SecPcreMatchLimitRecursion", + cmd_pcre_match_limit_recursion, + NULL, + CMD_SCOPE_MAIN, + "PCRE match limit recursion" + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyAccess", + cmd_request_body_access, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecInterceptOnError", + cmd_request_intercept_on_error, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecRulePerfTime", + cmd_rule_perf_time, + NULL, + CMD_SCOPE_ANY, + "Threshold to log slow rules in usecs." + ), + + AP_INIT_TAKE12 ( + "SecConnReadStateLimit", + cmd_conn_read_state_limit, + NULL, + CMD_SCOPE_ANY, + "maximum number of threads in READ_BUSY state per ip address" + ), + + AP_INIT_TAKE12 ( + "SecReadStateLimit", + cmd_read_state_limit, + NULL, + CMD_SCOPE_ANY, + "maximum number of threads in READ_BUSY state per ip address" + ), + + AP_INIT_TAKE12 ( + "SecConnWriteStateLimit", + cmd_conn_write_state_limit, + NULL, + CMD_SCOPE_ANY, + "maximum number of threads in WRITE_BUSY state per ip address" + ), + + AP_INIT_TAKE12 ( + "SecWriteStateLimit", + cmd_write_state_limit, + NULL, + CMD_SCOPE_ANY, + "maximum number of threads in WRITE_BUSY state per ip address" + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyInMemoryLimit", + cmd_request_body_inmemory_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size that will be placed in memory (except for POST urlencoded requests)." + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyLimit", + cmd_request_body_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size ModSecurity will accept." + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyNoFilesLimit", + cmd_request_body_no_files_limit, + NULL, + CMD_SCOPE_ANY, + "maximum request body size ModSecurity will accept, but excluding the size of uploaded files." + ), + + AP_INIT_TAKE1 ( + "SecRequestEncoding", + cmd_request_encoding, + NULL, + CMD_SCOPE_ANY, + "character encoding used in request." + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyAccess", + cmd_response_body_access, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyLimit", + cmd_response_body_limit, + NULL, + CMD_SCOPE_ANY, + "byte limit for response body" + ), + + AP_INIT_TAKE1 ( + "SecResponseBodyLimitAction", + cmd_response_body_limit_action, + NULL, + CMD_SCOPE_ANY, + "what happens when the response body limit is reached" + ), + + AP_INIT_TAKE1 ( + "SecRequestBodyLimitAction", + cmd_resquest_body_limit_action, + NULL, + CMD_SCOPE_ANY, + "what happens when the request body limit is reached" + ), + + AP_INIT_ITERATE ( + "SecResponseBodyMimeType", + cmd_response_body_mime_type, + NULL, + CMD_SCOPE_ANY, + "adds given MIME types to the list of types that will be buffered on output" + ), + + AP_INIT_NO_ARGS ( + "SecResponseBodyMimeTypesClear", + cmd_response_body_mime_types_clear, + NULL, + CMD_SCOPE_ANY, + "clears the list of MIME types that will be buffered on output" + ), + +#ifdef HTACCESS_CONFIG + AP_INIT_TAKE23 ( + "SecRule", + cmd_rule, + NULL, + CMD_SCOPE_HTACCESS, + "rule target, operator and optional action list" + ), +#else + AP_INIT_TAKE23 ( + "SecRule", + cmd_rule, + NULL, + CMD_SCOPE_ANY, + "rule target, operator and optional action list" + ), +#endif + + AP_INIT_TAKE1 ( + "SecRuleEngine", + cmd_rule_engine, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecStatusEngine", + cmd_status_engine, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecConnEngine", + cmd_sever_conn_filters_engine, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE23 ( + "SecRemoteRules", + cmd_remote_rules, + NULL, + CMD_SCOPE_ANY, + "key and URI to the remote rules" + ), + + AP_INIT_TAKE1 ( + "SecRemoteRulesFailAction", + cmd_remote_rules_fail, + NULL, + CMD_SCOPE_ANY, + "Abort or Warn" + ), + + + AP_INIT_TAKE1 ( + "SecXmlExternalEntity", + cmd_xml_external_entity, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_FLAG ( + "SecRuleInheritance", + cmd_rule_inheritance, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE12 ( + "SecRuleScript", + cmd_rule_script, + NULL, + CMD_SCOPE_ANY, + "rule script and optional actionlist" + ), + +#ifdef HTACCESS_CONFIG + AP_INIT_ITERATE ( + "SecRuleRemoveById", + cmd_rule_remove_by_id, + NULL, + CMD_SCOPE_HTACCESS, + "rule ID for removal" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveByTag", + cmd_rule_remove_by_tag, + NULL, + CMD_SCOPE_HTACCESS, + "rule tag for removal" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveByMsg", + cmd_rule_remove_by_msg, + NULL, + CMD_SCOPE_HTACCESS, + "rule message for removal" + ), +#else + AP_INIT_ITERATE ( + "SecRuleRemoveById", + cmd_rule_remove_by_id, + NULL, + CMD_SCOPE_ANY, + "rule ID for removal" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveByTag", + cmd_rule_remove_by_tag, + NULL, + CMD_SCOPE_ANY, + "rule tag for removal" + ), + + AP_INIT_ITERATE ( + "SecRuleRemoveByMsg", + cmd_rule_remove_by_msg, + NULL, + CMD_SCOPE_ANY, + "rule message for removal" + ), +#endif + + AP_INIT_TAKE2 ( + "SecHashMethodPm", + cmd_hash_method_pm, + NULL, + CMD_SCOPE_ANY, + "Hash method and pattern" + ), + + AP_INIT_TAKE2 ( + "SecHashMethodRx", + cmd_hash_method_rx, + NULL, + CMD_SCOPE_ANY, + "Hash method and regex" + ), + +#ifdef HTACCESS_CONFIG + AP_INIT_TAKE2 ( + "SecRuleUpdateActionById", + cmd_rule_update_action_by_id, + NULL, + CMD_SCOPE_HTACCESS, + "updated action list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetById", + cmd_rule_update_target_by_id, + NULL, + CMD_SCOPE_HTACCESS, + "updated target list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetByTag", + cmd_rule_update_target_by_tag, + NULL, + CMD_SCOPE_HTACCESS, + "rule tag pattern and updated target list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetByMsg", + cmd_rule_update_target_by_msg, + NULL, + CMD_SCOPE_HTACCESS, + "rule message pattern and updated target list" + ), +#else + AP_INIT_TAKE2 ( + "SecRuleUpdateActionById", + cmd_rule_update_action_by_id, + NULL, + CMD_SCOPE_ANY, + "updated action list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetById", + cmd_rule_update_target_by_id, + NULL, + CMD_SCOPE_ANY, + "updated target list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetByTag", + cmd_rule_update_target_by_tag, + NULL, + CMD_SCOPE_ANY, + "rule tag pattern and updated target list" + ), + + AP_INIT_TAKE23 ( + "SecRuleUpdateTargetByMsg", + cmd_rule_update_target_by_msg, + NULL, + CMD_SCOPE_ANY, + "rule message pattern and updated target list" + ), +#endif + + AP_INIT_TAKE1 ( + "SecServerSignature", + cmd_server_signature, + NULL, + CMD_SCOPE_MAIN, + "the new signature of the server" + ), + + AP_INIT_TAKE1 ( + "SecTmpDir", + cmd_tmp_dir, + NULL, + CMD_SCOPE_ANY, + "path to the temporary storage area" + ), + + AP_INIT_TAKE1 ( + "SecUploadDir", + cmd_upload_dir, + NULL, + CMD_SCOPE_ANY, + "path to the file upload area" + ), + + AP_INIT_TAKE1 ( + "SecUploadFileLimit", + cmd_upload_file_limit, + NULL, + CMD_SCOPE_ANY, + "limit the number of uploaded files processed" + ), + + AP_INIT_TAKE1 ( + "SecUploadFileMode", + cmd_upload_filemode, + NULL, + CMD_SCOPE_ANY, + "octal permissions mode for uploaded files" + ), + + AP_INIT_TAKE1 ( + "SecUploadKeepFiles", + cmd_upload_keep_files, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecTmpSaveUploadedFiles", + cmd_upload_save_tmp_files, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE1 ( + "SecWebAppId", + cmd_web_app_id, + NULL, + CMD_SCOPE_ANY, + "id" + ), + + AP_INIT_TAKE1 ( + "SecSensorId", + cmd_sensor_id, + NULL, + CMD_SCOPE_MAIN, + "sensor id" + ), + + AP_INIT_TAKE1 ( + "SecHttpBlKey", + cmd_httpBl_key, + NULL, + CMD_SCOPE_ANY, + "httpBl access key" + ), + + AP_INIT_TAKE1 ( + "SecHashEngine", + cmd_hash_engine, + NULL, + CMD_SCOPE_ANY, + "On or Off" + ), + + AP_INIT_TAKE2 ( + "SecHashKey", + cmd_hash_key, + NULL, + CMD_SCOPE_ANY, + "Set Hash key" + ), + + AP_INIT_TAKE1 ( + "SecHashParam", + cmd_hash_param, + NULL, + CMD_SCOPE_ANY, + "Set Hash parameter" + ), + + { NULL } +}; diff --git a/apache2/apache2_io.c b/apache2/apache2_io.c new file mode 100644 index 0000000..c14dd41 --- /dev/null +++ b/apache2/apache2_io.c @@ -0,0 +1,1042 @@ +/* + * ModSecurity for Apache 2.x, http://www.modsecurity.org/ + * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License.  You may obtain a copy of the License at + * + *     http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + */ + +#include + +#include "modsecurity.h" +#include "apache2.h" +#include "msc_crypt.h" + +/* -- Input filter -- */ + +#if 0 +static void dummy_free_func(void *data) {} +#endif + +/** + * This request filter will forward the previously stored + * request body further down the chain (most likely to the + * processing module). + */ +apr_status_t input_filter(ap_filter_t *f, apr_bucket_brigade *bb_out, + ap_input_mode_t mode, apr_read_type_e block, apr_off_t nbytes) +{ + modsec_rec *msr = (modsec_rec *)f->ctx; + msc_data_chunk *chunk = NULL; + apr_bucket *bucket; + apr_status_t rc; + char *my_error_msg = NULL; + + if (msr == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal error in input filter: msr is null."); + ap_remove_input_filter(f); + return APR_EGENERAL; + } + + /* Make sure we are using the current request */ + msr->r = f->r; + + if (msr->phase < PHASE_REQUEST_BODY) { + msr_log(msr, 1, "Internal error: REQUEST_BODY phase incomplete for input filter in phase %d", msr->phase); + return APR_EGENERAL; + } + + if ((msr->if_status == IF_STATUS_COMPLETE)||(msr->if_status == IF_STATUS_NONE)) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Input forwarding already complete, skipping (f %pp, r %pp).", f, f->r); + } + ap_remove_input_filter(f); + return ap_get_brigade(f->next, bb_out, mode, block, nbytes); + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Forwarding input: mode=%d, block=%d, nbytes=%" APR_OFF_T_FMT + " (f %pp, r %pp).", mode, block, nbytes, f, f->r); + } + + if (msr->if_started_forwarding == 0) { + msr->if_started_forwarding = 1; + rc = modsecurity_request_body_retrieve_start(msr, &my_error_msg); + if (rc == -1) { + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + return APR_EGENERAL; + } + } + + rc = modsecurity_request_body_retrieve(msr, &chunk, (unsigned int)nbytes, &my_error_msg); + if (rc == -1) { + if (my_error_msg != NULL) { + msr_log(msr, 1, "%s", my_error_msg); + } + 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 0 + + It would seem that we cannot prevent other filters in the chain + from modifying data in-place. Hence we copy. + + if (chunk->is_permanent) { + /* Do not make a copy of the data we received in the chunk. */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, dummy_free_func, + f->r->connection->bucket_alloc); + } else { + /* Copy the data we received in the chunk. */ + bucket = apr_bucket_heap_create(chunk->data, chunk->length, NULL, + f->r->connection->bucket_alloc); + } + +#endif + + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Forwarded %" APR_SIZE_T_FMT " bytes.", chunk->length); + } + } else if (msr->stream_input_data != NULL) { + + msr->if_stream_changed = 0; + + 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 (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input stream filter: Forwarded %" APR_SIZE_T_FMT " bytes.", msr->stream_input_length); + } + + } + + if (rc == 0) { + modsecurity_request_body_retrieve_end(msr); + + if (msr->if_seen_eos) { + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + APR_BRIGADE_INSERT_TAIL(bb_out, bucket); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Sent EOS."); + } + } + + /* We're done */ + msr->if_status = IF_STATUS_COMPLETE; + ap_remove_input_filter(f); + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Input forwarding complete."); + } + } + + return APR_SUCCESS; +} + +/** + * Reads request body from a client. + */ +apr_status_t read_request_body(modsec_rec *msr, char **error_msg) { + request_rec *r = msr->r; + unsigned int finished_reading; + apr_bucket_brigade *bb_in; + apr_bucket *bucket; + + if (error_msg == NULL) return -1; + *error_msg = NULL; + + if (msr->reqbody_should_exist != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: This request does not have a body."); + } + return 0; + } + + if (msr->txcfg->reqbody_access != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Input filter: Request body access not enabled."); + } + return 0; + } + + 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; + } + + 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 { + apr_status_t rc; + + rc = ap_get_brigade(r->input_filters, bb_in, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); + if (rc != APR_SUCCESS) { + /* NOTE Apache returns AP_FILTER_ERROR here when the request is + * too large and APR_EGENERAL when the client disconnects. + */ + switch(rc) { + case APR_INCOMPLETE : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -7; + case APR_EOF : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -6; + case APR_TIMEUP : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -4; + case AP_FILTER_ERROR : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: HTTP Error 413 - Request entity too large. (Most likely.)"); + return -3; + case APR_EGENERAL : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: Client went away."); + return -2; + default : + *error_msg = apr_psprintf(msr->mp, "Error reading request body: %s", get_apr_error(msr->mp, rc)); + return -1; + } + } + + /* Loop through the buckets in the brigade in order + * to extract the size of the data available. + */ + for(bucket = APR_BRIGADE_FIRST(bb_in); + bucket != APR_BRIGADE_SENTINEL(bb_in); + bucket = APR_BUCKET_NEXT(bucket)) + { + const char *buf; + apr_size_t buflen; + + rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ); + if (rc != APR_SUCCESS) { + *error_msg = apr_psprintf(msr->mp, "Failed reading input / bucket (%d): %s", rc, get_apr_error(msr->mp, rc)); + return -1; + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Input filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.", + bucket->type->name, buflen); + } + + /* Check request body limit (should only trigger on chunked requests). */ + if (msr->reqbody_length + buflen > (apr_size_t)msr->txcfg->reqbody_limit) { + if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + return -5; + } else if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) { + + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + + } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)){ + + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + + } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)){ + + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + + } else { + + *error_msg = apr_psprintf(msr->mp, "Request body is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_limit); + + return -5; + } + } + + if (msr->txcfg->stream_inbody_inspection == 1) { + msr->stream_input_length+=buflen; + modsecurity_request_body_to_stream(msr, buf, buflen, error_msg); + } + + msr->reqbody_length += buflen; + + if (buflen != 0) { + int rcbs = modsecurity_request_body_store(msr, buf, buflen, error_msg); + + if (msr->reqbody_length > (apr_size_t)msr->txcfg->reqbody_limit && msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) { + finished_reading = 1; + } + + if (rcbs < 0) { + if (rcbs == -5) { + if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + return -5; + } else if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + } else if ((msr->txcfg->is_enabled == MODSEC_DETECTION_ONLY) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL)) { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + } else { + *error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the " + "configured limit (%ld).", msr->txcfg->reqbody_no_files_limit); + return -5; + } + } + + if((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) + return -1; + } + + } + + if (APR_BUCKET_IS_EOS(bucket)) { + finished_reading = 1; + msr->if_seen_eos = 1; + } + } + + apr_brigade_cleanup(bb_in); + } while(!finished_reading); + + // TODO: Why ignore the return code here? + 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 ").", + msr->reqbody_length); + } + + msr->if_status = IF_STATUS_WANTS_TO_RUN; + + return 1; +} + + +/* -- Output filter -- */ + +/** + * Examines the configuration and the response MIME type + * in order to determine whether output buffering should + * run or not. + */ +static int output_filter_should_run(modsec_rec *msr, request_rec *r) { + char *content_type = NULL; + + /* Check configuration. */ + if (msr->txcfg->resbody_access != 1) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Response body buffering is not enabled."); + } + + return 0; + } + + /* Check MIME type. */ + + if ((msr->txcfg->of_mime_types == NULL)||(msr->txcfg->of_mime_types == NOT_SET_P)) { + msr_log(msr, 1, "Output filter: MIME type structures corrupted (internal error)."); + return -1; + } + + if (r->content_type != NULL) { + char *p = NULL; + + content_type = apr_pstrdup(msr->mp, r->content_type); + if (content_type == NULL) { + msr_log(msr, 1, "Output filter: Failed to allocate memory for content type."); + return -1; + } + + /* Hide the character encoding information + * if present. Sometimes the content type header + * looks like this "text/html; charset=xyz" ... + */ + p = strstr(content_type, ";"); + if (p != NULL) { + *p = '\0'; + } + + strtolower_inplace((unsigned char *)content_type); + + if (strcmp(content_type, "text/html") == 0) { + /* Useful information to have should we later + * decide to do something with the HTML output. + */ + msr->resbody_contains_html = 1; + } + } else { + content_type = "null"; + } + + if (apr_table_get(msr->txcfg->of_mime_types, content_type) != NULL) return 1; + + msr_log(msr, 4, "Output filter: Not buffering response body for unconfigured MIME type \"%s\".", content_type); + + return 0; +} + +/** + * Initialises the output filter. + */ +static apr_status_t output_filter_init(modsec_rec *msr, ap_filter_t *f, + apr_bucket_brigade *bb_in) +{ + request_rec *r = f->r; + const char *s_content_length = NULL; + apr_status_t rc; + + msr->of_brigade = apr_brigade_create(msr->mp, f->c->bucket_alloc); + if (msr->of_brigade == NULL) { + msr_log(msr, 1, "Output filter: Failed to create brigade."); + return -1; + } + msr->of_status = OF_STATUS_IN_PROGRESS; + + rc = output_filter_should_run(msr, r); + if (rc < 0) return -1; /* output_filter_should_run() generates error msg */ + if (rc == 0) return 0; + + /* Do not check the output limit if we are willing to + * process partial response bodies. + */ + + if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_PARTIAL) { + return 1; + } + + /* Look up the Content-Length header to see if we know + * the amount of data coming our way. If we do and if + * it's too much we might want to stop processing right here. + */ + s_content_length = apr_table_get(r->headers_out, "Content-Length"); + if (s_content_length == NULL) { + /* Try this too, mod_cgi seems to put headers there. */ + s_content_length = apr_table_get(r->err_headers_out, "Content-Length"); + } + + if (s_content_length != NULL) { + long int len; + + len = strtol(s_content_length, NULL, 10); + if ((len == LONG_MIN)||(len == LONG_MAX)||(len < 0)||(len >= 1073741824)) { + msr_log(msr, 1, "Output filter: Invalid Content-Length: %s", log_escape_nq(r->pool, + (char *)s_content_length)); + return -1; /* Invalid. */ + } + + if (len == 0) { + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Skipping response since Content-Length is zero."); + } + + return 0; + } + + if (len > msr->txcfg->of_limit) { + msr_log(msr, 1, "Output filter: Content-Length (%s) over the limit (%ld).", + log_escape_nq(r->pool, (char *)s_content_length), msr->txcfg->of_limit); + msr->outbound_error = 1; + return -2; /* Over the limit. */ + } + } + + return 1; +} + +/** + * Send the accumulated content down the filter stream + * and to the client. + */ +static apr_status_t send_of_brigade(modsec_rec *msr, ap_filter_t *f) { + apr_status_t rc; + + rc = ap_pass_brigade(f->next, msr->of_brigade); + if (rc != APR_SUCCESS) { + /* TODO: These need to move to flags in 2.6. For now log them + * at level 4 so that they are not confusing users. + */ + int log_level = 4; + + if (msr->txcfg->debuglog_level >= log_level) { + switch(rc) { + case AP_NOBODY_WROTE : + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): No data", rc); + break; + case AP_FILTER_ERROR : + /* Look like this is caused by the error + * already being handled, so we should ignore it + * + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): Filter error", rc); + */ + break; + default : + msr_log(msr, log_level, "Output filter: Error while forwarding response data (%d): %s", + rc, get_apr_error(msr->mp, rc)); + break; + } + } + + return rc; + } + + return APR_SUCCESS; +} + +/** \brief Inject data into brigade + * + * \param msr ModSecurity transation resource + * \param ap_filter_t Apache filter + * + */ +static void inject_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + apr_bucket *b; + + if (msr->txcfg->content_injection_enabled && msr->stream_output_data != NULL) { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->stream_output_data, + msr->stream_output_length, NULL, f->r->connection->bucket_alloc); + + for (b = APR_BRIGADE_FIRST(msr->of_brigade); b != APR_BRIGADE_SENTINEL(msr->of_brigade); b = APR_BUCKET_NEXT(b)) { + if(!APR_BUCKET_IS_METADATA(b)) + apr_bucket_delete(b); + } + + APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Data reinjected bytes [%"APR_SIZE_T_FMT"]",msr->stream_output_length); + } + + } +} + +/** + * + */ +static void prepend_content_to_of_brigade(modsec_rec *msr, ap_filter_t *f) { + if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (!msr->of_skipping)) { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_prepend, + msr->content_prepend_len, NULL, f->r->connection->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(msr->of_brigade, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection (b): Added content to top: %s", + log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len)); + } + } +} + +/** + * + */ +static int flatten_response_body(modsec_rec *msr) { + apr_status_t rc; + + msr->resbody_status = RESBODY_STATUS_READ_BRIGADE; + + if (msr->resbody_length + 1 <= 0) { + msr_log(msr, 1, "Output filter: Invalid response length: %" APR_SIZE_T_FMT, msr->resbody_length); + return -1; + } + + msr->resbody_data = apr_palloc(msr->mp, msr->resbody_length + 1); + if (msr->resbody_data == NULL) { + msr_log(msr, 1, "Output filter: Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT, + msr->resbody_length + 1); + return -1; + } + + rc = apr_brigade_flatten(msr->of_brigade, msr->resbody_data, &msr->resbody_length); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Output filter: Failed to flatten brigade (%d): %s", rc, + get_apr_error(msr->mp, rc)); + return -1; + } + + msr->resbody_data[msr->resbody_length] = '\0'; + msr->resbody_status = RESBODY_STATUS_READ; + + if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_DISABLED) { + + msr->stream_output_length = msr->resbody_length; + + if (msr->stream_output_data == NULL) { + msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT, + msr->stream_output_length + 1); + return -1; + } + + memset(msr->stream_output_data, 0, msr->stream_output_length+1); + memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; + } else if (msr->txcfg->stream_outbody_inspection && msr->txcfg->hash_is_enabled == HASH_ENABLED) { + int retval = 0; + apr_time_t time1 = apr_time_now(); + + retval = init_response_body_html_parser(msr); + + if(retval == 1) { + retval = hash_response_body_links(msr); + if(retval > 0) { + retval = inject_hashed_response_body(msr, retval); + 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)); + } + } + + } + } + + if(msr->of_stream_changed == 0) { + msr->stream_output_length = msr->resbody_length; + + if (msr->stream_output_data == NULL) { + msr_log(msr, 1, "Output filter: Stream Response body data memory allocation failed. Asked for: %" APR_SIZE_T_FMT, + msr->stream_output_length + 1); + return -1; + } + + memset(msr->stream_output_data, 0, msr->stream_output_length+1); + memcpy(msr->stream_output_data, msr->resbody_data, msr->stream_output_length); + msr->stream_output_data[msr->stream_output_length] = '\0'; + } + } + + return 1; +} + +/** + * Output filter. + */ +apr_status_t output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) { + request_rec *r = f->r; + modsec_rec *msr = (modsec_rec *)f->ctx; + apr_bucket *bucket = NULL, *eos_bucket = NULL; + apr_status_t rc; + int start_skipping = 0; + + /* Do we have the context? */ + if (msr == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server, + "ModSecurity: Internal Error: msr is null in output filter."); + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + msr->r = r; + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Receiving output (f %pp, r %pp).", f, f->r); + } + + /* Put back the Accept-Encoding and TE request headers + * if they were removed from the request. + */ + if (msr->txcfg->disable_backend_compression) { + char *ae = (char *)apr_table_get(msr->request_headers, "Accept-Encoding"); + char *te = (char *)apr_table_get(msr->request_headers, "TE"); + + if ((ae != NULL)&&(apr_table_get(f->r->headers_in, "Accept-Encoding") == NULL)) { + apr_table_add(f->r->headers_in, "Accept-Encoding", ae); + } + + if ((te != NULL)&&(apr_table_get(f->r->headers_in, "TE") == NULL)) { + apr_table_add(f->r->headers_in, "TE", te); + } + } + + /* Initialise on first invocation */ + if (msr->of_status == OF_STATUS_NOT_STARTED) { + /* Update our context from the request structure. */ + msr->r = r; + msr->response_status = r->status; + msr->status_line = ((r->status_line != NULL) + ? r->status_line : ap_get_status_line(r->status)); + msr->response_protocol = get_response_protocol(r); + + if(msr->txcfg->crypto_hash_location_rx == 1 || msr->txcfg->crypto_hash_location_pm == 1) + rc = modify_response_header(msr); + + msr->response_headers = apr_table_overlay(msr->mp, r->err_headers_out, r->headers_out); + + /* Process phase RESPONSE_HEADERS */ + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_HEADERS); + if (rc < 0) { /* error */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + if (rc > 0) { /* transaction needs to be interrupted */ + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + return send_error_bucket(msr, f, status); + } + } + + msr->outbound_error = 0; + /* Decide whether to observe the response body. */ + rc = output_filter_init(msr, f, bb_in); + switch(rc) { + case -2 : /* response too large */ + case -1 : /* error */ + /* there's something wrong with this response */ + ap_remove_output_filter(f); + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + case 0 : + /* We do not want to observe this response body + * but we need to remain attached to observe + * when it is completed so that we can run + * the RESPONSE_BODY phase. + */ + msr->of_skipping = 1; + msr->resbody_status = RESBODY_STATUS_NOT_READ; + break; + default : + /* Continue (observe the response body). */ + break; + } + + /* If injecting content unset headers now. */ + if (msr->txcfg->content_injection_enabled == 0) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Not enabled."); + } + } else { + if ((msr->content_prepend) || (msr->content_append)) { + apr_table_unset(msr->r->headers_out, "Content-Length"); + apr_table_unset(msr->r->headers_out, "Last-Modified"); + apr_table_unset(msr->r->headers_out, "ETag"); + apr_table_unset(msr->r->headers_out, "Expires"); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Removing headers (C-L, L-M, Etag, Expires)."); + } + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection: Nothing to inject."); + } + } + } + + /* Content injection (prepend & non-buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_prepend) && (msr->of_skipping)) { + apr_bucket *bucket_ci = apr_bucket_heap_create(msr->content_prepend, + msr->content_prepend_len, NULL, f->r->connection->bucket_alloc); + APR_BRIGADE_INSERT_HEAD(bb_in, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content Injection (nb): Added content to top: %s", + log_escape_nq_ex(msr->mp, msr->content_prepend, msr->content_prepend_len)); + } + } + } else + if (msr->of_status == OF_STATUS_COMPLETE) { + msr_log(msr, 1, "Output filter: Internal error: output filtering complete yet filter was invoked."); + ap_remove_output_filter(f); + return APR_EGENERAL; + } + + + /* Loop through the buckets in the brigade in order + * to extract the size of the data available. + */ + for(bucket = APR_BRIGADE_FIRST(bb_in); + bucket != APR_BRIGADE_SENTINEL(bb_in); + bucket = APR_BUCKET_NEXT(bucket)) { + const char *buf; + apr_size_t buflen; + + /* Look into response data if configured to do so, + * unless we've already processed a partial response. + */ + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { /* Observe the response data. */ + /* Retrieve data from the bucket. */ + rc = apr_bucket_read(bucket, &buf, &buflen, APR_BLOCK_READ); + if (rc != APR_SUCCESS) { + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_ERROR; + + msr_log(msr, 1, "Output filter: Failed to read bucket (rc %d): %s", + rc, get_apr_error(r->pool, rc)); + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Bucket type %s contains %" APR_SIZE_T_FMT " bytes.", + bucket->type->name, buflen); + } + + /* Check the response size. */ + if (msr->resbody_length > (apr_size_t)msr->txcfg->of_limit) { + /* The size of the response is larger than what we're + * ready to accept. We need to decide what we want to do + * about it. + */ + msr->outbound_error = 1; + if (msr->txcfg->of_limit_action == RESPONSE_BODY_LIMIT_ACTION_REJECT) { + /* Reject response. */ + msr_log(msr, 1, "Output filter: Response body too large (over limit of %ld, " + "total not specified).", msr->txcfg->of_limit); + + msr->of_status = OF_STATUS_COMPLETE; + msr->resbody_status = RESBODY_STATUS_PARTIAL; + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } else { + /* Process partial response. */ + start_skipping = 1; + msr->resbody_length = msr->txcfg->of_limit; + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Processing partial response body (limit %ld)", + msr->txcfg->of_limit); + } + } + } else { + msr->resbody_length += buflen; + } + } + + /* Have we reached the end of the response? */ + if (APR_BUCKET_IS_EOS(bucket)) { + eos_bucket = bucket; + + /* Inject content (append & non-buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_append) + && (msr->of_skipping || msr->of_partial || start_skipping)) + { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_append, + msr->content_append_len, NULL, f->r->connection->bucket_alloc); + APR_BUCKET_INSERT_BEFORE(bucket, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content-Injection (nb): Added content to bottom: %s", + log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len)); + } + } + + msr->of_done_reading = 1; + } + } + + /* Add buckets in this brigade to the brigade + * we have in the context, but only if we actually + * want to keep the response body. + */ + if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) { + ap_save_brigade(f, &msr->of_brigade, &bb_in, msr->mp); + + /* Do we need to process a partial response? */ + if (start_skipping) { + + if (msr->txcfg->stream_outbody_inspection) { + if(msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + } + + msr->stream_output_data = (char *)malloc(msr->resbody_length+1); + } + + if (flatten_response_body(msr) < 0) { + if (msr->txcfg->stream_outbody_inspection) { + if(msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + } + } + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + /* Process phase RESPONSE_BODY */ + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY); + if (rc < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + if (rc > 0) { + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, status); + } + } + + /* Prepend content as necessary. */ + prepend_content_to_of_brigade(msr, f); + + if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) { + return rc; + } + + msr->of_partial = 1; + } + + if (msr->of_done_reading == 0) { + /* We are done for now. We will be called again with more data. */ + return APR_SUCCESS; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Completed receiving response body (buffered %s - %" APR_SIZE_T_FMT " bytes).", + (msr->of_partial ? "partial" : "full"), msr->resbody_length); + } + } else { /* Not looking at response data. */ + if (msr->of_done_reading == 0) { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Sending input brigade directly."); + } + + return ap_pass_brigade(f->next, bb_in); + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Completed receiving response body (non-buffering)."); + } + } + + /* We've done our thing; remove us from the filter list. */ + msr->of_status = OF_STATUS_COMPLETE; + ap_remove_output_filter(f); + + /* Process phase RESPONSE_BODY, but + * only if it hasn't been processed already. + */ + if (msr->phase < PHASE_RESPONSE_BODY) { + + if (msr->txcfg->stream_outbody_inspection) { + if(msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + } + + msr->stream_output_data = (char *)malloc(msr->resbody_length+1); + } + + if (flatten_response_body(msr) < 0) { + if (msr->txcfg->stream_outbody_inspection) { + if(msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + } + } + + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + + rc = modsecurity_process_phase(msr, PHASE_RESPONSE_BODY); + if (rc < 0) { + ap_remove_output_filter(f); + return send_error_bucket(msr, f, HTTP_INTERNAL_SERVER_ERROR); + } + if (rc > 0) { + int status = perform_interception(msr); + if (status != DECLINED) { /* DECLINED means we allow-ed the request. */ + ap_remove_output_filter(f); + return send_error_bucket(msr, f, status); + } + } + } + + /* Now send data down the filter stream + * (full-buffering only). + */ + if ((msr->of_skipping == 0)&&(!msr->of_partial)) { + if(msr->of_stream_changed == 1) { + inject_content_to_of_brigade(msr,f); + msr->of_stream_changed = 0; + } + + if (msr->txcfg->stream_outbody_inspection) { + if(msr->stream_output_data != NULL) { + free(msr->stream_output_data); + msr->stream_output_data = NULL; + } + } + + prepend_content_to_of_brigade(msr, f); + + /* Inject content into response (append & buffering). */ + if ((msr->txcfg->content_injection_enabled) && (msr->content_append)) { + apr_bucket *bucket_ci = NULL; + + bucket_ci = apr_bucket_heap_create(msr->content_append, + msr->content_append_len, NULL, f->r->connection->bucket_alloc); + APR_BUCKET_INSERT_BEFORE(eos_bucket, bucket_ci); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Content-Injection (b): Added content to bottom: %s", + log_escape_nq_ex(msr->mp, msr->content_append, msr->content_append_len)); + } + } + + /* Send data down the filter stream. */ + if ((rc = send_of_brigade(msr, f)) != APR_SUCCESS) { + return rc; + } + } + + /* Another job well done! */ + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Output filter: Output forwarding complete."); + } + + if ((msr->of_skipping == 0)&&(msr->of_partial == 0)) { + return APR_SUCCESS; + } else { + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Output filter: Sending input brigade directly."); + } + + return ap_pass_brigade(f->next, bb_in); + } +} diff --git a/apache2/apache2_util.c b/apache2/apache2_util.c new file mode 100644 index 0000000..24bba0c --- /dev/null +++ b/apache2/apache2_util.c @@ -0,0 +1,398 @@ +/* +* ModSecurity for Apache 2.x, http://www.modsecurity.org/ +* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) +* +* You may not use this file except in compliance with +* the License.  You may obtain a copy of the License at +* +*     http://www.apache.org/licenses/LICENSE-2.0 +* +* If any of the files related to licensing are missing or if you have any +* other questions related to licensing please contact Trustwave Holdings, Inc. +* directly using the email address security@modsecurity.org. +*/ + +#include "modsecurity.h" +#include "apache2.h" +#include "http_core.h" +#include "util_script.h" + +/** + * Sends a brigade with an error bucket down the filter chain. + */ +apr_status_t send_error_bucket(modsec_rec *msr, ap_filter_t *f, int status) { + apr_bucket_brigade *brigade = NULL; + apr_bucket *bucket = NULL; + + /* Set the status line explicitly for the error document */ + f->r->status_line = ap_get_status_line(status); + + brigade = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc); + if (brigade == NULL) return APR_EGENERAL; + + bucket = ap_bucket_error_create(status, NULL, f->r->pool, f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + + APR_BRIGADE_INSERT_TAIL(brigade, bucket); + + bucket = apr_bucket_eos_create(f->r->connection->bucket_alloc); + if (bucket == NULL) return APR_EGENERAL; + + APR_BRIGADE_INSERT_TAIL(brigade, bucket); + + ap_pass_brigade(f->next, brigade); + + /* NOTE: + * It may not matter what we do from the filter as it may be too + * late to even generate an error (already sent to client). Nick Kew + * recommends to return APR_EGENERAL in hopes that the handler in control + * will notice and do The Right Thing. So, that is what we do now. + */ + + return APR_EGENERAL; +} + +/** + * Execute system command. First line of the output will be returned in + * the "output" parameter. + */ +int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { + apr_procattr_t *procattr = NULL; + apr_proc_t *procnew = NULL; + apr_status_t rc = APR_SUCCESS; + const char *const *env = NULL; + apr_file_t *script_out = NULL; + request_rec *r = msr->r; + + if (argv == NULL) { + argv = apr_pcalloc(r->pool, 3 * sizeof(char *)); + argv[0] = command; + argv[1] = NULL; + } + + ap_add_cgi_vars(r); + ap_add_common_vars(r); + + /* PHP hack, getting around its silly security checks. */ + apr_table_add(r->subprocess_env, "PATH_TRANSLATED", command); + apr_table_add(r->subprocess_env, "REDIRECT_STATUS", "302"); + + env = (const char * const *)ap_create_environment(r->pool, r->subprocess_env); + if (env == NULL) { + msr_log(msr, 1, "Exec: Unable to create environment."); + return -1; + } + + procnew = apr_pcalloc(r->pool, sizeof(*procnew)); + if (procnew == NULL) { + msr_log(msr, 1, "Exec: Unable to allocate %lu bytes.", (unsigned long)sizeof(*procnew)); + return -1; + } + + apr_procattr_create(&procattr, r->pool); + if (procattr == NULL) { + msr_log(msr, 1, "Exec: Unable to create procattr."); + return -1; + } + + apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); + apr_procattr_cmdtype_set(procattr, APR_SHELLCMD); + + if (msr->txcfg->debuglog_level >= 9) { + msr_log(msr, 9, "Exec: %s", log_escape_nq(r->pool, command)); + } + + rc = apr_proc_create(procnew, command, argv, env, procattr, r->pool); + if (rc != APR_SUCCESS) { + msr_log(msr, 1, "Exec: Execution failed: %s (%s)", log_escape_nq(r->pool, command), + get_apr_error(r->pool, rc)); + return -1; + } + + apr_pool_note_subprocess(r->pool, procnew, APR_KILL_AFTER_TIMEOUT); + + script_out = procnew->out; + if (!script_out) { + msr_log(msr, 1, "Exec: Failed to get script output pipe."); + return -1; + } + + apr_file_pipe_timeout_set(script_out, r->server->timeout); + + /* Now read from the pipe. */ + { + char buf[260] = ""; + char *p = buf; + apr_size_t nbytes = 255; + apr_status_t rc2; + + rc2 = apr_file_read(script_out, buf, &nbytes); + if (rc2 == APR_SUCCESS) { + buf[nbytes] = 0; + + /* if there is more than one line ignore them */ + while(*p != 0) { + if (*p == 0x0a) *p = 0; + p++; + } + + if (msr->txcfg->debuglog_level >= 4) { + msr_log(msr, 4, "Exec: First line from script output: \"%s\"", + log_escape(r->pool, buf)); + } + + if (output != NULL) *output = apr_pstrdup(r->pool, buf); + + /* Soak up the remaining data. */ + nbytes = 255; + while(apr_file_read(script_out, buf, &nbytes) == APR_SUCCESS) nbytes = 255; + } else { + msr_log(msr, 1, "Exec: Execution failed while reading output: %s (%s)", + log_escape_nq(r->pool, command), + get_apr_error(r->pool, rc2)); + return -1; + } + } + + apr_proc_wait(procnew, NULL, NULL, APR_WAIT); + + return 1; +} + +/** + * Returns a new string that contains the error + * message for the given return code. + */ +char *get_apr_error(apr_pool_t *p, apr_status_t rc) { + char *text = apr_pcalloc(p, 201); + if (text == NULL) return NULL; + apr_strerror(rc, text, 200); + return text; +} + +/** + * Retrieve named environment variable. + */ +char *get_env_var(request_rec *r, char *name) { + char *result = (char *)apr_table_get(r->notes, name); + + if (result == NULL) { + result = (char *)apr_table_get(r->subprocess_env, name); + } + + if (result == NULL) { + result = getenv(name); + } + + return result; +} + +/** + * Extended internal log helper function. Use msr_log instead. If fixup is + * true, the message will be stripped of any trailing newline and any + * required bytes will be escaped. + */ +static void internal_log_ex(request_rec *r, directory_config *dcfg, modsec_rec *msr, + int level, int fixup, const char *text, va_list ap) +{ + apr_size_t nbytes, nbytes_written; + apr_file_t *debuglog_fd = NULL; + int filter_debug_level = 0; + char *remote = NULL; + char *parse_remote = NULL; + char *saved = NULL; + char *str = NULL; + char str1[1024] = ""; + char str2[1256] = ""; + + /* Find the logging FD and determine the logging level from configuration. */ + if (dcfg != NULL) { + if ((dcfg->debuglog_fd != NULL)&&(dcfg->debuglog_fd != NOT_SET_P)) { + debuglog_fd = dcfg->debuglog_fd; + } + + if (dcfg->debuglog_level != NOT_SET) { + filter_debug_level = dcfg->debuglog_level; + } + } + + /* Return immediately if we don't have where to write + * or if the log level of the message is higher than + * wanted in the log. + */ + if ((level > 3)&&( (debuglog_fd == NULL) || (level > filter_debug_level) )) return; + + /* Construct the message. */ + apr_vsnprintf(str1, sizeof(str1), text, ap); + if (fixup) { + int len = strlen(str1); + + /* Strip line ending. */ + if (len && str1[len - 1] == '\n') { + str1[len - 1] = '\0'; + } + if (len > 1 && str1[len - 2] == '\r') { + str1[len - 2] = '\0'; + } + } + + /* Construct the log entry. */ + apr_snprintf(str2, sizeof(str2), + "[%s] [%s/sid#%pp][rid#%pp][%s][%d] %s\n", + current_logtime(msr->mp), ap_get_server_name(r), (r->server), + r, ((r->uri == NULL) ? "" : log_escape_nq(msr->mp, r->uri)), + level, (fixup ? log_escape_nq(msr->mp, str1) : str1)); + + /* Write to the debug log. */ + if ((debuglog_fd != NULL)&&(level <= filter_debug_level)) { + nbytes = strlen(str2); + apr_file_write_full(debuglog_fd, str2, nbytes, &nbytes_written); + } + + /* Send message levels 1-3 to the Apache error log and + * add it to the message list in the audit log. */ + if (level <= 3) { + char *unique_id = (char *)get_env_var(r, "UNIQUE_ID"); + char *hostname = (char *)msr->hostname; + + if (unique_id != NULL) { + unique_id = apr_psprintf(msr->mp, " [unique_id \"%s\"]", + log_escape(msr->mp, unique_id)); + } + else unique_id = ""; + + if (hostname != NULL) { + hostname = apr_psprintf(msr->mp, " [hostname \"%s\"]", + log_escape(msr->mp, hostname)); + } + else hostname = ""; + +#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 + ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r, + "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", r->useragent_ip ? r->useragent_ip : r->connection->client_ip, str1, + hostname, log_escape(msr->mp, r->uri), unique_id); +#else + ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server, + "[client %s] ModSecurity: %s%s [uri \"%s\"]%s", msr->remote_addr ? msr->remote_addr : r->connection->remote_ip, str1, + hostname, log_escape(msr->mp, r->uri), unique_id); +#endif + + /* Add this message to the list. */ + if (msr != NULL) { + /* Force relevency if this is an alert */ + msr->is_relevant++; + + *(const char **)apr_array_push(msr->alerts) = apr_pstrdup(msr->mp, str1); + } + } + + return; +} + +/** + * Logs one message at the given level to the debug log (and to the + * Apache error log if the message is important enough. + */ +void msr_log(modsec_rec *msr, int level, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, level, 0, text, ap); + va_end(ap); +} + + +/** + * Logs one message at level 3 to the debug log and to the + * Apache error log. This is intended for error callbacks. + */ +void msr_log_error(modsec_rec *msr, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, 3, 1, text, ap); + va_end(ap); +} + +/** + * Logs one message at level 4 to the debug log and to the + * Apache error log. This is intended for warning callbacks. + * + * The 'text' will first be escaped. + */ +void msr_log_warn(modsec_rec *msr, const char *text, ...) { + va_list ap; + + va_start(ap, text); + internal_log_ex(msr->r, msr->txcfg, msr, 4, 1, text, ap); + va_end(ap); +} + + +/** + * Converts an Apache error log message into one line of text. + */ +char *format_error_log_message(apr_pool_t *mp, error_message_t *em) { + char *s_file = "", *s_line = "", *s_level = ""; + char *s_status = "", *s_message = ""; + char *msg = NULL; + + 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)); + if (s_file == NULL) return NULL; + } + + if (em->line > 0) { + 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; + + if (em->status != 0) { + s_status = apr_psprintf(mp, "[status %d] ", em->status); + if (s_status == NULL) return NULL; + } + + if (em->message != NULL) { + s_message = log_escape_nq(mp, em->message); + if (s_message == NULL) return NULL; + } + + msg = apr_psprintf(mp, "%s%s%s%s%s", s_file, s_line, s_level, s_status, s_message); + if (msg == NULL) return NULL; + + return msg; +} + +/** + * Determines the reponse protocol Apache will use (or has used) + * to respond to the given request. + */ +const char *get_response_protocol(request_rec *r) { + int proto_num = r->proto_num; + + if (r->assbackwards) { + return NULL; + } + + if (proto_num > HTTP_VERSION(1,0) + && apr_table_get(r->subprocess_env, "downgrade-1.0")) + { + proto_num = HTTP_VERSION(1,0); + } + + if (proto_num == HTTP_VERSION(1,0) + && apr_table_get(r->subprocess_env, "force-response-1.0")) + { + return "HTTP/1.0"; + } + + return AP_SERVER_PROTOCOL; +} diff --git a/apache2/libinjection/COPYING.txt b/apache2/libinjection/COPYING.txt new file mode 100644 index 0000000..ef2f78d --- /dev/null +++ b/apache2/libinjection/COPYING.txt @@ -0,0 +1,37 @@ +/* + * Copyright 2012, 2013 + * Nick Galbreath -- nickg [at] client9 [dot] com + * http://www.client9.com/projects/libinjection/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of libinjection nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This is the standard "new" BSD license: + * http://www.opensource.org/licenses/bsd-license.php + */ diff --git a/apache2/libinjection/libinjection.h b/apache2/libinjection/libinjection.h new file mode 100644 index 0000000..6b40b1d --- /dev/null +++ b/apache2/libinjection/libinjection.h @@ -0,0 +1,65 @@ +/** + * Copyright 2012-2016 Nick Galbreath + * nickg@client9.com + * BSD License -- see COPYING.txt for details + * + * https://libinjection.client9.com/ + * + */ + +#ifndef LIBINJECTION_H +#define LIBINJECTION_H + +#ifdef __cplusplus +# define LIBINJECTION_BEGIN_DECLS extern "C" { +# define LIBINJECTION_END_DECLS } +#else +# define LIBINJECTION_BEGIN_DECLS +# define LIBINJECTION_END_DECLS +#endif + +LIBINJECTION_BEGIN_DECLS + +/* + * Pull in size_t + */ +#include + +/* + * Version info. + * + * This is moved into a function to allow SWIG and other auto-generated + * binding to not be modified during minor release changes. We change + * change the version number in the c source file, and not regenerated + * the binding + * + * See python's normalized version + * http://www.python.org/dev/peps/pep-0386/#normalizedversion + */ +const char* libinjection_version(void); + +/** + * Simple API for SQLi detection - returns a SQLi fingerprint or NULL + * is benign input + * + * \param[in] s input string, may contain nulls, does not need to be null-terminated + * \param[in] slen input string length + * \param[out] fingerprint buffer of 8+ characters. c-string, + * \return 1 if SQLi, 0 if benign. fingerprint will be set or set to empty string. + */ +int libinjection_sqli(const char* s, size_t slen, char fingerprint[]); + +/** ALPHA version of xss detector. + * + * NOT DONE. + * + * \param[in] s input string, may contain nulls, does not need to be null-terminated + * \param[in] slen input string length + * \return 1 if XSS found, 0 if benign + * + */ +int libinjection_xss(const char* s, size_t slen); + +LIBINJECTION_END_DECLS + +#endif /* LIBINJECTION_H */ diff --git a/apache2/libinjection/libinjection_html5.c b/apache2/libinjection/libinjection_html5.c new file mode 100644 index 0000000..a380ca0 --- /dev/null +++ b/apache2/libinjection/libinjection_html5.c @@ -0,0 +1,850 @@ +#include "libinjection_html5.h" + +#include +#include + +#ifdef DEBUG +#include +#define TRACE() printf("%s:%d\n", __FUNCTION__, __LINE__) +#else +#define TRACE() +#endif + + +#define CHAR_EOF -1 +#define CHAR_NULL 0 +#define CHAR_BANG 33 +#define CHAR_DOUBLE 34 +#define CHAR_PERCENT 37 +#define CHAR_SINGLE 39 +#define CHAR_DASH 45 +#define CHAR_SLASH 47 +#define CHAR_LT 60 +#define CHAR_EQUALS 61 +#define CHAR_GT 62 +#define CHAR_QUESTION 63 +#define CHAR_RIGHTB 93 +#define CHAR_TICK 96 + +/* prototypes */ + +static int h5_skip_white(h5_state_t* hs); +static int h5_is_white(char c); +static int h5_state_eof(h5_state_t* hs); +static int h5_state_data(h5_state_t* hs); +static int h5_state_tag_open(h5_state_t* hs); +static int h5_state_tag_name(h5_state_t* hs); +static int h5_state_tag_name_close(h5_state_t* hs); +static int h5_state_end_tag_open(h5_state_t* hs); +static int h5_state_self_closing_start_tag(h5_state_t* hs); +static int h5_state_attribute_name(h5_state_t* hs); +static int h5_state_after_attribute_name(h5_state_t* hs); +static int h5_state_before_attribute_name(h5_state_t* hs); +static int h5_state_before_attribute_value(h5_state_t* hs); +static int h5_state_attribute_value_double_quote(h5_state_t* hs); +static int h5_state_attribute_value_single_quote(h5_state_t* hs); +static int h5_state_attribute_value_back_quote(h5_state_t* hs); +static int h5_state_attribute_value_no_quote(h5_state_t* hs); +static int h5_state_after_attribute_value_quoted_state(h5_state_t* hs); +static int h5_state_comment(h5_state_t* hs); +static int h5_state_cdata(h5_state_t* hs); + + +/* 12.2.4.44 */ +static int h5_state_bogus_comment(h5_state_t* hs); +static int h5_state_bogus_comment2(h5_state_t* hs); + +/* 12.2.4.45 */ +static int h5_state_markup_declaration_open(h5_state_t* hs); + +/* 8.2.4.52 */ +static int h5_state_doctype(h5_state_t* hs); + +/** + * public function + */ +void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_flags flags) +{ + memset(hs, 0, sizeof(h5_state_t)); + hs->s = s; + hs->len = len; + + switch (flags) { + case DATA_STATE: + hs->state = h5_state_data; + break; + case VALUE_NO_QUOTE: + hs->state = h5_state_before_attribute_name; + break; + case VALUE_SINGLE_QUOTE: + hs->state = h5_state_attribute_value_single_quote; + break; + case VALUE_DOUBLE_QUOTE: + hs->state = h5_state_attribute_value_double_quote; + break; + case VALUE_BACK_QUOTE: + hs->state = h5_state_attribute_value_back_quote; + break; + } +} + +/** + * public function + */ +int libinjection_h5_next(h5_state_t* hs) +{ + assert(hs->state != NULL); + return (*hs->state)(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; +} + +static int h5_skip_white(h5_state_t* hs) +{ + char ch; + while (hs->pos < hs->len) { + ch = hs->s[hs->pos]; + switch (ch) { + case 0x00: /* IE only */ + case 0x20: + case 0x09: + case 0x0A: + case 0x0B: /* IE only */ + case 0x0C: + case 0x0D: /* IE only */ + hs->pos += 1; + break; + default: + return ch; + } + } + return CHAR_EOF; +} + +static int h5_state_eof(h5_state_t* hs) +{ + /* eliminate unused function argument warning */ + (void)hs; + return 0; +} + +static int h5_state_data(h5_state_t* hs) +{ + const char* idx; + + TRACE(); + assert(hs->len >= hs->pos); + idx = (const char*) memchr(hs->s + hs->pos, CHAR_LT, hs->len - hs->pos); + if (idx == NULL) { + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = DATA_TEXT; + hs->state = h5_state_eof; + if (hs->token_len == 0) { + return 0; + } + } else { + hs->token_start = hs->s + hs->pos; + hs->token_type = DATA_TEXT; + hs->token_len = (size_t)(idx - hs->s) - hs->pos; + hs->pos = (size_t)(idx - hs->s) + 1; + hs->state = h5_state_tag_open; + if (hs->token_len == 0) { + return h5_state_tag_open(hs); + } + } + return 1; +} + +/** + * 12 2.4.8 + */ +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; + return h5_state_markup_declaration_open(hs); + } else if (ch == CHAR_SLASH) { + hs->pos += 1; + hs->is_close = 1; + return h5_state_end_tag_open(hs); + } else if (ch == CHAR_QUESTION) { + hs->pos += 1; + return h5_state_bogus_comment(hs); + } else if (ch == CHAR_PERCENT) { + /* this is not in spec.. alternative comment format used + by IE <= 9 and Safari < 4.0.3 */ + hs->pos += 1; + return h5_state_bogus_comment2(hs); + } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { + return h5_state_tag_name(hs); + } else if (ch == CHAR_NULL) { + /* IE-ism NULL characters are ignored */ + return h5_state_tag_name(hs); + } else { + /* user input mistake in configuring state */ + if (hs->pos == 0) { + return h5_state_data(hs); + } + hs->token_start = hs->s + hs->pos - 1; + hs->token_len = 1; + hs->token_type = DATA_TEXT; + hs->state = h5_state_data; + return 1; + } +} +/** + * 12.2.4.9 + */ +static int h5_state_end_tag_open(h5_state_t* hs) +{ + char ch; + + TRACE(); + + if (hs->pos >= hs->len) { + return 0; + } + ch = hs->s[hs->pos]; + if (ch == CHAR_GT) { + return h5_state_data(hs); + } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { + return h5_state_tag_name(hs); + } + + hs->is_close = 0; + return h5_state_bogus_comment(hs); +} +/* + * + */ +static int h5_state_tag_name_close(h5_state_t* hs) +{ + TRACE(); + hs->is_close = 0; + hs->token_start = hs->s + hs->pos; + hs->token_len = 1; + hs->token_type = TAG_NAME_CLOSE; + hs->pos += 1; + if (hs->pos < hs->len) { + hs->state = h5_state_data; + } else { + hs->state = h5_state_eof; + } + + return 1; +} + +/** + * 12.2.4.10 + */ +static int h5_state_tag_name(h5_state_t* hs) +{ + char ch; + size_t pos; + + TRACE(); + 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)) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = TAG_NAME_OPEN; + hs->pos = pos + 1; + hs->state = h5_state_before_attribute_name; + return 1; + } else if (ch == CHAR_SLASH) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = TAG_NAME_OPEN; + hs->pos = pos + 1; + hs->state = h5_state_self_closing_start_tag; + return 1; + } else if (ch == CHAR_GT) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + if (hs->is_close) { + hs->pos = pos + 1; + hs->is_close = 0; + hs->token_type = TAG_CLOSE; + hs->state = h5_state_data; + } else { + hs->pos = pos; + hs->token_type = TAG_NAME_OPEN; + hs->state = h5_state_tag_name_close; + } + return 1; + } else { + pos += 1; + } + } + + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = TAG_NAME_OPEN; + hs->state = h5_state_eof; + return 1; +} + +/** + * 12.2.4.34 + */ +static int h5_state_before_attribute_name(h5_state_t* hs) +{ + int ch; + + TRACE(); + ch = h5_skip_white(hs); + switch (ch) { + case CHAR_EOF: { + return 0; + } + case CHAR_SLASH: { + hs->pos += 1; + return h5_state_self_closing_start_tag(hs); + } + case CHAR_GT: { + hs->state = h5_state_data; + hs->token_start = hs->s + hs->pos; + hs->token_len = 1; + hs->token_type = TAG_NAME_CLOSE; + hs->pos += 1; + return 1; + } + default: { + return h5_state_attribute_name(hs); + } + } +} + +static int h5_state_attribute_name(h5_state_t* hs) +{ + char ch; + size_t pos; + + TRACE(); + pos = hs->pos + 1; + while (pos < hs->len) { + ch = hs->s[pos]; + if (h5_is_white(ch)) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = ATTR_NAME; + hs->state = h5_state_after_attribute_name; + hs->pos = pos + 1; + return 1; + } else if (ch == CHAR_SLASH) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = ATTR_NAME; + hs->state = h5_state_self_closing_start_tag; + hs->pos = pos + 1; + return 1; + } else if (ch == CHAR_EQUALS) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = ATTR_NAME; + hs->state = h5_state_before_attribute_value; + hs->pos = pos + 1; + return 1; + } else if (ch == CHAR_GT) { + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->token_type = ATTR_NAME; + hs->state = h5_state_tag_name_close; + hs->pos = pos; + return 1; + } else { + pos += 1; + } + } + /* EOF */ + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = ATTR_NAME; + hs->state = h5_state_eof; + hs->pos = hs->len; + return 1; +} + +/** + * 12.2.4.36 + */ +static int h5_state_after_attribute_name(h5_state_t* hs) +{ + int c; + + TRACE(); + c = h5_skip_white(hs); + switch (c) { + case CHAR_EOF: { + return 0; + } + case CHAR_SLASH: { + hs->pos += 1; + return h5_state_self_closing_start_tag(hs); + } + case CHAR_EQUALS: { + hs->pos += 1; + return h5_state_before_attribute_value(hs); + } + case CHAR_GT: { + return h5_state_tag_name_close(hs); + } + default: { + return h5_state_attribute_name(hs); + } + } +} + +/** + * 12.2.4.37 + */ +static int h5_state_before_attribute_value(h5_state_t* hs) +{ + int c; + TRACE(); + + c = h5_skip_white(hs); + + if (c == CHAR_EOF) { + hs->state = h5_state_eof; + return 0; + } + + if (c == CHAR_DOUBLE) { + return h5_state_attribute_value_double_quote(hs); + } else if (c == CHAR_SINGLE) { + return h5_state_attribute_value_single_quote(hs); + } else if (c == CHAR_TICK) { + /* NON STANDARD IE */ + return h5_state_attribute_value_back_quote(hs); + } else { + return h5_state_attribute_value_no_quote(hs); + } +} + + +static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar) +{ + const char* idx; + + TRACE(); + + /* skip initial quote in normal case. + * don't do this "if (pos == 0)" since it means we have started + * in a non-data state. given an input of '>pos > 0) { + hs->pos += 1; + } + + + idx = (const char*) memchr(hs->s + hs->pos, qchar, hs->len - hs->pos); + if (idx == NULL) { + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = ATTR_VALUE; + hs->state = h5_state_eof; + } else { + hs->token_start = hs->s + hs->pos; + hs->token_len = (size_t)(idx - hs->s) - hs->pos; + hs->token_type = ATTR_VALUE; + hs->state = h5_state_after_attribute_value_quoted_state; + hs->pos += hs->token_len + 1; + } + return 1; +} + +static +int h5_state_attribute_value_double_quote(h5_state_t* hs) +{ + TRACE(); + return h5_state_attribute_value_quote(hs, CHAR_DOUBLE); +} + +static +int h5_state_attribute_value_single_quote(h5_state_t* hs) +{ + TRACE(); + return h5_state_attribute_value_quote(hs, CHAR_SINGLE); +} + +static +int h5_state_attribute_value_back_quote(h5_state_t* hs) +{ + TRACE(); + return h5_state_attribute_value_quote(hs, CHAR_TICK); +} + +static int h5_state_attribute_value_no_quote(h5_state_t* hs) +{ + char ch; + size_t pos; + + TRACE(); + pos = hs->pos; + while (pos < hs->len) { + ch = hs->s[pos]; + if (h5_is_white(ch)) { + hs->token_type = ATTR_VALUE; + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->pos = pos + 1; + hs->state = h5_state_before_attribute_name; + return 1; + } else if (ch == CHAR_GT) { + hs->token_type = ATTR_VALUE; + hs->token_start = hs->s + hs->pos; + hs->token_len = pos - hs->pos; + hs->pos = pos; + hs->state = h5_state_tag_name_close; + return 1; + } + pos += 1; + } + TRACE(); + /* EOF */ + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = ATTR_VALUE; + return 1; +} + +/** + * 12.2.4.41 + */ +static int h5_state_after_attribute_value_quoted_state(h5_state_t* hs) +{ + char ch; + + TRACE(); + if (hs->pos >= hs->len) { + return 0; + } + ch = hs->s[hs->pos]; + if (h5_is_white(ch)) { + hs->pos += 1; + return h5_state_before_attribute_name(hs); + } else if (ch == CHAR_SLASH) { + hs->pos += 1; + return h5_state_self_closing_start_tag(hs); + } else if (ch == CHAR_GT) { + hs->token_start = hs->s + hs->pos; + hs->token_len = 1; + hs->token_type = TAG_NAME_CLOSE; + hs->pos += 1; + hs->state = h5_state_data; + return 1; + } else { + return h5_state_before_attribute_name(hs); + } +} + +/** + * 12.2.4.43 + */ +static int h5_state_self_closing_start_tag(h5_state_t* hs) +{ + char ch; + + TRACE(); + if (hs->pos >= hs->len) { + return 0; + } + ch = hs->s[hs->pos]; + if (ch == CHAR_GT) { + assert(hs->pos > 0); + hs->token_start = hs->s + hs->pos -1; + hs->token_len = 2; + hs->token_type = TAG_NAME_SELFCLOSE; + hs->state = h5_state_data; + hs->pos += 1; + return 1; + } else { + return h5_state_before_attribute_name(hs); + } +} + +/** + * 12.2.4.44 + */ +static int h5_state_bogus_comment(h5_state_t* hs) +{ + const char* idx; + + TRACE(); + idx = (const char*) memchr(hs->s + hs->pos, CHAR_GT, hs->len - hs->pos); + if (idx == NULL) { + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->pos = hs->len; + hs->state = h5_state_eof; + } else { + hs->token_start = hs->s + hs->pos; + hs->token_len = (size_t)(idx - hs->s) - hs->pos; + hs->pos = (size_t)(idx - hs->s) + 1; + hs->state = h5_state_data; + } + + hs->token_type = TAG_COMMENT; + return 1; +} + +/** + * 12.2.4.44 ALT + */ +static int h5_state_bogus_comment2(h5_state_t* hs) +{ + const char* idx; + size_t pos; + + TRACE(); + pos = hs->pos; + while (1) { + idx = (const char*) memchr(hs->s + pos, CHAR_PERCENT, hs->len - pos); + if (idx == NULL || (idx + 1 >= hs->s + hs->len)) { + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->pos = hs->len; + hs->token_type = TAG_COMMENT; + hs->state = h5_state_eof; + return 1; + } + + if (*(idx +1) != CHAR_GT) { + pos = (size_t)(idx - hs->s) + 1; + continue; + } + + /* ends in %> */ + hs->token_start = hs->s + hs->pos; + hs->token_len = (size_t)(idx - hs->s) - hs->pos; + hs->pos = (size_t)(idx - hs->s) + 2; + hs->state = h5_state_data; + hs->token_type = TAG_COMMENT; + return 1; + } +} + +/** + * 8.2.4.45 + */ +static int h5_state_markup_declaration_open(h5_state_t* hs) +{ + size_t remaining; + + TRACE(); + remaining = hs->len - hs->pos; + if (remaining >= 7 && + /* case insensitive */ + (hs->s[hs->pos + 0] == 'D' || hs->s[hs->pos + 0] == 'd') && + (hs->s[hs->pos + 1] == 'O' || hs->s[hs->pos + 1] == 'o') && + (hs->s[hs->pos + 2] == 'C' || hs->s[hs->pos + 2] == 'c') && + (hs->s[hs->pos + 3] == 'T' || hs->s[hs->pos + 3] == 't') && + (hs->s[hs->pos + 4] == 'Y' || hs->s[hs->pos + 4] == 'y') && + (hs->s[hs->pos + 5] == 'P' || hs->s[hs->pos + 5] == 'p') && + (hs->s[hs->pos + 6] == 'E' || hs->s[hs->pos + 6] == 'e') + ) { + return h5_state_doctype(hs); + } else if (remaining >= 7 && + /* upper case required */ + hs->s[hs->pos + 0] == '[' && + hs->s[hs->pos + 1] == 'C' && + hs->s[hs->pos + 2] == 'D' && + hs->s[hs->pos + 3] == 'A' && + hs->s[hs->pos + 4] == 'T' && + hs->s[hs->pos + 5] == 'A' && + hs->s[hs->pos + 6] == '[' + ) { + hs->pos += 7; + return h5_state_cdata(hs); + } else if (remaining >= 2 && + hs->s[hs->pos + 0] == '-' && + hs->s[hs->pos + 1] == '-') { + hs->pos += 2; + return h5_state_comment(hs); + } + + return h5_state_bogus_comment(hs); +} + +/** + * 12.2.4.48 + * 12.2.4.49 + * 12.2.4.50 + * 12.2.4.51 + * state machine spec is confusing since it can only look + * at one character at a time but simply it's comments end by: + * 1) EOF + * 2) ending in --> + * 3) ending in -!> + */ +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 */ + if (idx == NULL || idx > hs->s + hs->len - 3) { + 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; + } + 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; + } + + /* 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 + offset - hs->s); + hs->state = h5_state_data; + hs->token_type = TAG_COMMENT; + return 1; + } +} + +static int h5_state_cdata(h5_state_t* hs) +{ + const char* idx; + size_t pos; + + TRACE(); + pos = hs->pos; + while (1) { + idx = (const char*) memchr(hs->s + pos, CHAR_RIGHTB, hs->len - pos); + + /* did not find anything or has less than 3 chars left */ + if (idx == NULL || idx > hs->s + hs->len - 3) { + hs->state = h5_state_eof; + hs->token_start = hs->s + hs->pos; + hs->token_len = hs->len - hs->pos; + hs->token_type = DATA_TEXT; + return 1; + } else if ( *(idx+1) == CHAR_RIGHTB && *(idx+2) == CHAR_GT) { + hs->state = h5_state_data; + 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->token_type = DATA_TEXT; + return 1; + } else { + pos = (size_t)(idx - hs->s) + 1; + } + } +} + +/** + * 8.2.4.52 + * http://www.w3.org/html/wg/drafts/html/master/syntax.html#doctype-state + */ +static int h5_state_doctype(h5_state_t* hs) +{ + const char* idx; + + TRACE(); + hs->token_start = hs->s + hs->pos; + hs->token_type = DOCTYPE; + + idx = (const char*) memchr(hs->s + hs->pos, CHAR_GT, hs->len - hs->pos); + if (idx == NULL) { + hs->state = h5_state_eof; + hs->token_len = hs->len - hs->pos; + } else { + hs->state = h5_state_data; + hs->token_len = (size_t)(idx - hs->s) - hs->pos; + hs->pos = (size_t)(idx - hs->s) + 1; + } + return 1; +} diff --git a/apache2/libinjection/libinjection_html5.h b/apache2/libinjection/libinjection_html5.h new file mode 100644 index 0000000..29a1459 --- /dev/null +++ b/apache2/libinjection/libinjection_html5.h @@ -0,0 +1,54 @@ +#ifndef LIBINJECTION_HTML5 +#define LIBINJECTION_HTML5 + +#ifdef __cplusplus +extern "C" { +#endif + +/* pull in size_t */ + +#include + +enum html5_type { + DATA_TEXT + , TAG_NAME_OPEN + , TAG_NAME_CLOSE + , TAG_NAME_SELFCLOSE + , TAG_DATA + , TAG_CLOSE + , ATTR_NAME + , ATTR_VALUE + , TAG_COMMENT + , DOCTYPE +}; + +enum html5_flags { + DATA_STATE + , VALUE_NO_QUOTE + , VALUE_SINGLE_QUOTE + , VALUE_DOUBLE_QUOTE + , VALUE_BACK_QUOTE +}; + +struct h5_state; +typedef int (*ptr_html5_state)(struct h5_state*); + +typedef struct h5_state { + const char* s; + size_t len; + size_t pos; + int is_close; + ptr_html5_state state; + const char* token_start; + size_t token_len; + enum html5_type token_type; +} h5_state_t; + + +void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_flags); +int libinjection_h5_next(h5_state_t* hs); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/apache2/libinjection/libinjection_sqli.c b/apache2/libinjection/libinjection_sqli.c new file mode 100644 index 0000000..cecbbea --- /dev/null +++ b/apache2/libinjection/libinjection_sqli.c @@ -0,0 +1,2325 @@ +/** + * Copyright 2012,2016 Nick Galbreath + * nickg@client9.com + * BSD License -- see COPYING.txt for details + * + * https://libinjection.client9.com/ + * + */ + +#include +#include +#include +#include +#include +#include + +#include "libinjection.h" +#include "libinjection_sqli.h" +#include "libinjection_sqli_data.h" + +#define LIBINJECTION_VERSION "3.9.2" + +#define LIBINJECTION_SQLI_TOKEN_SIZE sizeof(((stoken_t*)(0))->val) +#define LIBINJECTION_SQLI_MAX_TOKENS 5 + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define CHAR_NULL '\0' +#define CHAR_SINGLE '\'' +#define CHAR_DOUBLE '"' +#define CHAR_TICK '`' + +/* faster than calling out to libc isdigit */ +#define ISDIGIT(a) ((unsigned)((a) - '0') <= 9) + +#if 0 +#define FOLD_DEBUG printf("%d \t more=%d pos=%d left=%d\n", __LINE__, more, (int)pos, (int)left); +#else +#define FOLD_DEBUG +#endif + +/* + * not making public just yet + */ +typedef enum { + TYPE_NONE = 0 + , TYPE_KEYWORD = (int)'k' + , TYPE_UNION = (int)'U' + , TYPE_GROUP = (int)'B' + , TYPE_EXPRESSION = (int)'E' + , TYPE_SQLTYPE = (int)'t' + , TYPE_FUNCTION = (int)'f' + , TYPE_BAREWORD = (int)'n' + , TYPE_NUMBER = (int)'1' + , TYPE_VARIABLE = (int)'v' + , TYPE_STRING = (int)'s' + , TYPE_OPERATOR = (int)'o' + , TYPE_LOGIC_OPERATOR = (int)'&' + , TYPE_COMMENT = (int)'c' + , TYPE_COLLATE = (int)'A' + , TYPE_LEFTPARENS = (int)'(' + , TYPE_RIGHTPARENS = (int)')' /* not used? */ + , TYPE_LEFTBRACE = (int)'{' + , TYPE_RIGHTBRACE = (int)'}' + , TYPE_DOT = (int)'.' + , TYPE_COMMA = (int)',' + , TYPE_COLON = (int)':' + , TYPE_SEMICOLON = (int)';' + , TYPE_TSQL = (int)'T' /* TSQL start */ + , TYPE_UNKNOWN = (int)'?' + , TYPE_EVIL = (int)'X' /* unparsable, abort */ + , TYPE_FINGERPRINT = (int)'F' /* not really a token */ + , TYPE_BACKSLASH = (int)'\\' +} sqli_token_types; + +/** + * Initializes parsing state + * + */ +static char flag2delim(int flag) +{ + if (flag & FLAG_QUOTE_SINGLE) { + return CHAR_SINGLE; + } else if (flag & FLAG_QUOTE_DOUBLE) { + return CHAR_DOUBLE; + } else { + return CHAR_NULL; + } +} + +/* memchr2 finds a string of 2 characters inside another string + * This a specialized version of "memmem" or "memchr". + * 'memmem' doesn't exist on all platforms + * + * Porting notes: this is just a special version of + * astring.find("AB") + * + */ +static const char * +memchr2(const char *haystack, size_t haystack_len, char c0, char c1) +{ + const char *cur = haystack; + const char *last = haystack + haystack_len - 1; + + if (haystack_len < 2) { + return NULL; + } + + while (cur < last) { + /* safe since cur < len - 1 always */ + if (cur[0] == c0 && cur[1] == c1) { + return cur; + } + cur += 1; + } + + return NULL; +} + +/** + * memmem might not exist on some systems + */ +static const char * +my_memmem(const char* haystack, size_t hlen, const char* needle, size_t nlen) +{ + const char* cur; + const char* last; + assert(haystack); + assert(needle); + assert(nlen > 1); + last = haystack + hlen - nlen; + for (cur = haystack; cur <= last; ++cur) { + if (cur[0] == needle[0] && memcmp(cur, needle, nlen) == 0) { + return cur; + } + } + return NULL; +} + +/** Find largest string containing certain characters. + * + * C Standard library 'strspn' only works for 'c-strings' (null terminated) + * This works on arbitrary length. + * + * Performance notes: + * not critical + * + * Porting notes: + * if accept is 'ABC', then this function would be similar to + * a_regexp.match(a_str, '[ABC]*'), + */ +static size_t +strlenspn(const char *s, size_t len, const char *accept) +{ + size_t i; + for (i = 0; i < len; ++i) { + /* likely we can do better by inlining this function + * but this works for now + */ + if (strchr(accept, s[i]) == NULL) { + return i; + } + } + return len; +} + +static size_t +strlencspn(const char *s, size_t len, const char *accept) +{ + size_t i; + for (i = 0; i < len; ++i) { + /* likely we can do better by inlining this function + * but this works for now + */ + if (strchr(accept, s[i]) != NULL) { + return i; + } + } + return len; +} +static int char_is_white(char ch) { + /* ' ' space is 0x32 + '\t 0x09 \011 horizontal tab + '\n' 0x0a \012 new line + '\v' 0x0b \013 vertical tab + '\f' 0x0c \014 new page + '\r' 0x0d \015 carriage return + 0x00 \000 null (oracle) + 0xa0 \240 is Latin-1 + */ + return strchr(" \t\n\v\f\r\240\000", ch) != NULL; +} + +/* DANGER DANGER + * This is -very specialized function- + * + * this compares a ALL_UPPER CASE C STRING + * with a *arbitrary memory* + length + * + * Sane people would just make a copy, up-case + * and use a hash table. + * + * Required since libc version uses the current locale + * and is much slower. + */ +static int cstrcasecmp(const char *a, const char *b, size_t n) +{ + char cb; + + for (; n > 0; a++, b++, n--) { + cb = *b; + if (cb >= 'a' && cb <= 'z') { + cb -= 0x20; + } + if (*a != cb) { + return *a - cb; + } else if (*a == '\0') { + return -1; + } + } + + return (*a == 0) ? 0 : 1; +} + +/** + * Case sensitive string compare. + * Here only to make code more readable + */ +static int streq(const char *a, const char *b) +{ + return strcmp(a, b) == 0; +} + +/** + * + * + * + * Porting Notes: + * given a mapping/hash of string to char + * this is just + * typecode = mapping[key.upper()] + */ + +static char bsearch_keyword_type(const char *key, size_t len, + const keyword_t * keywords, size_t numb) +{ + size_t pos; + size_t left = 0; + size_t right = numb - 1; + + while (left < right) { + pos = (left + right) >> 1; + + /* arg0 = upper case only, arg1 = mixed case */ + if (cstrcasecmp(keywords[pos].word, key, len) < 0) { + left = pos + 1; + } else { + right = pos; + } + } + if ((left == right) && cstrcasecmp(keywords[left].word, key, len) == 0) { + return keywords[left].type; + } else { + return CHAR_NULL; + } +} + +static char is_keyword(const char* key, size_t len) +{ + return bsearch_keyword_type(key, len, sql_keywords, sql_keywords_sz); +} + +/* st_token methods + * + * The following functions manipulates the stoken_t type + * + * + */ + +static void st_clear(stoken_t * st) +{ + memset(st, 0, sizeof(stoken_t)); +} + +static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len, + const char value) +{ + /* done to eliminate unused warning */ + (void)len; + st->type = (char) stype; + st->pos = pos; + st->len = 1; + st->val[0] = value; + st->val[1] = CHAR_NULL; +} + +static void st_assign(stoken_t * st, const char stype, + size_t pos, size_t len, const char* value) +{ + const size_t MSIZE = LIBINJECTION_SQLI_TOKEN_SIZE; + size_t last = len < MSIZE ? len : (MSIZE - 1); + st->type = (char) stype; + st->pos = pos; + st->len = last; + memcpy(st->val, value, last); + st->val[last] = CHAR_NULL; +} + +static void st_copy(stoken_t * dest, const stoken_t * src) +{ + memcpy(dest, src, sizeof(stoken_t)); +} + +static int st_is_arithmetic_op(const stoken_t* st) +{ + const char ch = st->val[0]; + return (st->type == TYPE_OPERATOR && st->len == 1 && + (ch == '*' || ch == '/' || ch == '-' || ch == '+' || ch == '%')); +} + +static int st_is_unary_op(const stoken_t * st) +{ + const char* str = st->val; + const size_t len = st->len; + + if (st->type != TYPE_OPERATOR) { + return FALSE; + } + + switch (len) { + case 1: + return *str == '+' || *str == '-' || *str == '!' || *str == '~'; + case 2: + return str[0] == '!' && str[1] == '!'; + case 3: + return cstrcasecmp("NOT", str, 3) == 0; + default: + return FALSE; + } +} + +/* Parsers + * + * + */ + +static size_t parse_white(struct libinjection_sqli_state * sf) +{ + return sf->pos + 1; +} + +static size_t parse_operator1(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + size_t pos = sf->pos; + + st_assign_char(sf->current, TYPE_OPERATOR, pos, 1, cs[pos]); + return pos + 1; +} + +static size_t parse_other(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + size_t pos = sf->pos; + + st_assign_char(sf->current, TYPE_UNKNOWN, pos, 1, cs[pos]); + return pos + 1; +} + +static size_t parse_char(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + size_t pos = sf->pos; + + st_assign_char(sf->current, cs[pos], pos, 1, cs[pos]); + return pos + 1; +} + +static size_t parse_eol_comment(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + const char *endpos = + (const char *) memchr((const void *) (cs + pos), '\n', slen - pos); + if (endpos == NULL) { + st_assign(sf->current, TYPE_COMMENT, pos, slen - pos, cs + pos); + return slen; + } else { + st_assign(sf->current, TYPE_COMMENT, pos, (size_t)(endpos - cs) - pos, cs + pos); + return (size_t)((endpos - cs) + 1); + } +} + +/** 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) +{ + sf->stats_comment_hash += 1; + if (sf->flags & FLAG_SQL_MYSQL) { + sf->stats_comment_hash += 1; + return parse_eol_comment(sf); + } else { + st_assign_char(sf->current, TYPE_OPERATOR, sf->pos, 1, '#'); + return sf->pos + 1; + } +} + +static size_t parse_dash(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + /* + * five cases + * 1) --[white] this is always a SQL comment + * 2) --[EOF] this is a comment + * 3) --[notwhite] in MySQL this is NOT a comment but two unary operators + * 4) --[notwhite] everyone else thinks this is a comment + * 5) -[not dash] '-' is a unary operator + */ + + if (pos + 2 < slen && cs[pos + 1] == '-' && char_is_white(cs[pos+2]) ) { + return parse_eol_comment(sf); + } else if (pos +2 == slen && cs[pos + 1] == '-') { + return parse_eol_comment(sf); + } else if (pos + 1 < slen && cs[pos + 1] == '-' && (sf->flags & FLAG_SQL_ANSI)) { + /* --[not-white] not-white case: + * + */ + sf->stats_comment_ddx += 1; + return parse_eol_comment(sf); + } else { + st_assign_char(sf->current, TYPE_OPERATOR, pos, 1, '-'); + return pos + 1; + } +} + + +/** This detects MySQL comments, comments that + * start with /x! We just ban these now but + * previously we attempted to parse the inside + * + * For reference: + * the form of /x![anything]x/ or /x!12345[anything] x/ + * + * Mysql 3 (maybe 4), allowed this: + * /x!0selectx/ 1; + * where 0 could be any number. + * + * The last version of MySQL 3 was in 2003. + + * It is unclear if the MySQL 3 syntax was allowed + * in MySQL 4. The last version of MySQL 4 was in 2008 + * + */ +static size_t is_mysql_comment(const char *cs, const size_t len, size_t pos) +{ + /* so far... + * cs[pos] == '/' && cs[pos+1] == '*' + */ + + if (pos + 2 >= len) { + /* not a mysql comment */ + return 0; + } + + if (cs[pos + 2] != '!') { + /* not a mysql comment */ + return 0; + } + + /* + * this is a mysql comment + * got "/x!" + */ + return 1; +} + +static size_t parse_slash(struct libinjection_sqli_state * sf) +{ + const char* ptr; + size_t clen; + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + const char* cur = cs + pos; + char ctype = TYPE_COMMENT; + size_t pos1 = pos + 1; + if (pos1 == slen || cs[pos1] != '*') { + return parse_operator1(sf); + } + + /* + * skip over initial '/x' + */ + ptr = memchr2(cur + 2, slen - (pos + 2), '*', '/'); + + /* + * (ptr == NULL) causes false positive in cppcheck 1.61 + * casting to type seems to fix it + */ + if (ptr == (const char*) NULL) { + /* till end of line */ + clen = slen - pos; + } else { + clen = (size_t)(ptr + 2 - cur); + } + + /* + * postgresql allows nested comments which makes + * this is incompatible with parsing so + * if we find a '/x' inside the coment, then + * make a new token. + * + * Also, Mysql's "conditional" comments for version + * are an automatic black ban! + */ + + if (memchr2(cur + 2, (size_t)(ptr - (cur + 1)), '/', '*') != NULL) { + ctype = TYPE_EVIL; + } else if (is_mysql_comment(cs, slen, pos)) { + ctype = TYPE_EVIL; + } + + st_assign(sf->current, ctype, pos, clen, cs + pos); + return pos + clen; +} + + +static size_t parse_backslash(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + /* + * Weird MySQL alias for NULL, "\N" (capital N only) + */ + if (pos + 1 < slen && cs[pos +1] == 'N') { + st_assign(sf->current, TYPE_NUMBER, pos, 2, cs + pos); + return pos + 2; + } else { + st_assign_char(sf->current, TYPE_BACKSLASH, pos, 1, cs[pos]); + return pos + 1; + } +} + +static size_t parse_operator2(struct libinjection_sqli_state * sf) +{ + char ch; + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + if (pos + 1 >= slen) { + return parse_operator1(sf); + } + + if (pos + 2 < slen && + cs[pos] == '<' && + cs[pos + 1] == '=' && + cs[pos + 2] == '>') { + /* + * special 3-char operator + */ + st_assign(sf->current, TYPE_OPERATOR, pos, 3, cs + pos); + return pos + 3; + } + + ch = sf->lookup(sf, LOOKUP_OPERATOR, cs + pos, 2); + if (ch != CHAR_NULL) { + st_assign(sf->current, ch, pos, 2, cs+pos); + return pos + 2; + } + + /* + * not an operator.. what to do with the two + * characters we got? + */ + + if (cs[pos] == ':') { + /* ':' is not an operator */ + st_assign(sf->current, TYPE_COLON, pos, 1, cs+pos); + return pos + 1; + } else { + /* + * must be a single char operator + */ + return parse_operator1(sf); + } +} + +/* + * Ok! " \" " one backslash = escaped! + * " \\" " two backslash = not escaped! + * "\\\" " three backslash = escaped! + */ +static int is_backslash_escaped(const char* end, const char* start) +{ + const char* ptr; + for (ptr = end; ptr >= start; ptr--) { + if (*ptr != '\\') { + break; + } + } + /* if number of backslashes is odd, it is escaped */ + + return (end - ptr) & 1; +} + +static size_t is_double_delim_escaped(const char* cur, const char* end) +{ + return ((cur + 1) < end) && *(cur+1) == *cur; +} + +/* Look forward for doubling of delimiter + * + * case 'foo''bar' --> foo''bar + * + * ending quote isn't duplicated (i.e. escaped) + * since it's the wrong char or EOL + * + */ +static size_t parse_string_core(const char *cs, const size_t len, size_t pos, + stoken_t * st, char delim, size_t offset) +{ + /* + * offset is to skip the perhaps first quote char + */ + const char *qpos = + (const char *) memchr((const void *) (cs + pos + offset), delim, + len - pos - offset); + + /* + * then keep string open/close info + */ + if (offset > 0) { + /* + * this is real quote + */ + st->str_open = delim; + } else { + /* + * this was a simulated quote + */ + st->str_open = CHAR_NULL; + } + + while (TRUE) { + if (qpos == NULL) { + /* + * string ended with no trailing quote + * assign what we have + */ + st_assign(st, TYPE_STRING, pos + offset, len - pos - offset, cs + pos + offset); + st->str_close = CHAR_NULL; + return len; + } else if ( is_backslash_escaped(qpos - 1, cs + pos + offset)) { + /* keep going, move ahead one character */ + qpos = + (const char *) memchr((const void *) (qpos + 1), delim, + (size_t)((cs + len) - (qpos + 1))); + continue; + } else if (is_double_delim_escaped(qpos, cs + len)) { + /* keep going, move ahead two characters */ + qpos = + (const char *) memchr((const void *) (qpos + 2), delim, + (size_t)((cs + len) - (qpos + 2))); + continue; + } else { + /* hey it's a normal string */ + st_assign(st, TYPE_STRING, pos + offset, + (size_t)(qpos - (cs + pos + offset)), cs + pos + offset); + st->str_close = delim; + return (size_t)(qpos - cs + 1); + } + } +} + +/** + * Used when first char is a ' or " + */ +static size_t parse_string(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + /* + * assert cs[pos] == single or double quote + */ + return parse_string_core(cs, slen, pos, sf->current, cs[pos], 1); +} + +/** + * Used when first char is: + * N or n: mysql "National Character set" + * E : psql "Escaped String" + */ +static size_t parse_estring(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + if (pos + 2 >= slen || cs[pos+1] != CHAR_SINGLE) { + return parse_word(sf); + } + return parse_string_core(cs, slen, pos, sf->current, CHAR_SINGLE, 2); +} + +static size_t parse_ustring(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + size_t slen = sf->slen; + size_t pos = sf->pos; + + if (pos + 2 < slen && cs[pos+1] == '&' && cs[pos+2] == '\'') { + sf->pos += 2; + pos = parse_string(sf); + sf->current->str_open = 'u'; + if (sf->current->str_close == '\'') { + sf->current->str_close = 'u'; + } + return pos; + } else { + return parse_word(sf); + } +} + +static size_t parse_qstring_core(struct libinjection_sqli_state * sf, size_t offset) +{ + char ch; + const char *strend; + const char *cs = sf->s; + size_t slen = sf->slen; + size_t pos = sf->pos + offset; + + /* if we are already at end of string.. + if current char is not q or Q + if we don't have 2 more chars + if char2 != a single quote + then, just treat as word + */ + if (pos >= slen || + (cs[pos] != 'q' && cs[pos] != 'Q') || + pos + 2 >= slen || + cs[pos + 1] != '\'') { + return parse_word(sf); + } + + ch = cs[pos + 2]; + + /* the ch > 127 is un-needed since + * we assume char is signed + */ + if (ch < 33 /* || ch > 127 */) { + return parse_word(sf); + } + switch (ch) { + case '(' : ch = ')'; break; + case '[' : ch = ']'; break; + case '{' : ch = '}'; break; + case '<' : ch = '>'; break; + } + + strend = memchr2(cs + pos + 3, slen - pos - 3, ch, '\''); + if (strend == NULL) { + st_assign(sf->current, TYPE_STRING, pos + 3, slen - pos - 3, cs + pos + 3); + sf->current->str_open = 'q'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + st_assign(sf->current, TYPE_STRING, pos + 3, (size_t)(strend - cs) - pos - 3, cs + pos + 3); + sf->current->str_open = 'q'; + sf->current->str_close = 'q'; + return (size_t)(strend - cs + 2); + } +} + +/* + * Oracle's q string + */ +static size_t parse_qstring(struct libinjection_sqli_state * sf) +{ + return parse_qstring_core(sf, 0); +} + +/* + * mysql's N'STRING' or + * ... Oracle's nq string + */ +static size_t parse_nqstring(struct libinjection_sqli_state * sf) +{ + size_t slen = sf->slen; + size_t pos = sf->pos; + if (pos + 2 < slen && sf->s[pos+1] == CHAR_SINGLE) { + return parse_estring(sf); + } + return parse_qstring_core(sf, 1); +} + +/* + * binary literal string + * re: [bB]'[01]*' + */ +static size_t parse_bstring(struct libinjection_sqli_state *sf) +{ + size_t wlen; + const char *cs = sf->s; + size_t pos = sf->pos; + size_t slen = sf->slen; + + /* need at least 2 more characters + * if next char isn't a single quote, then + * continue as normal word + */ + if (pos + 2 >= slen || cs[pos+1] != '\'') { + return parse_word(sf); + } + + wlen = strlenspn(cs + pos + 2, sf->slen - pos - 2, "01"); + if (pos + 2 + wlen >= slen || cs[pos + 2 + wlen] != '\'') { + return parse_word(sf); + } + st_assign(sf->current, TYPE_NUMBER, pos, wlen + 3, cs + pos); + return pos + 2 + wlen + 1; +} + +/* + * hex literal string + * re: [xX]'[0123456789abcdefABCDEF]*' + * mysql has requirement of having EVEN number of chars, + * but pgsql does not + */ +static size_t parse_xstring(struct libinjection_sqli_state *sf) +{ + size_t wlen; + const char *cs = sf->s; + size_t pos = sf->pos; + size_t slen = sf->slen; + + /* need at least 2 more characters + * if next char isn't a single quote, then + * continue as normal word + */ + if (pos + 2 >= slen || cs[pos+1] != '\'') { + return parse_word(sf); + } + + wlen = strlenspn(cs + pos + 2, sf->slen - pos - 2, "0123456789ABCDEFabcdef"); + if (pos + 2 + wlen >= slen || cs[pos + 2 + wlen] != '\'') { + return parse_word(sf); + } + st_assign(sf->current, TYPE_NUMBER, pos, wlen + 3, cs + pos); + return pos + 2 + wlen + 1; +} + +/** + * This handles MS SQLSERVER bracket words + * http://stackoverflow.com/questions/3551284/sql-serverwhat-do-brackets-mean-around-column-name + * + */ +static size_t parse_bword(struct libinjection_sqli_state * sf) +{ + const char *cs = sf->s; + size_t pos = sf->pos; + const char* endptr = (const char*) memchr(cs + pos, ']', sf->slen - pos); + if (endptr == NULL) { + st_assign(sf->current, TYPE_BAREWORD, pos, sf->slen - pos, cs + pos); + return sf->slen; + } else { + st_assign(sf->current, TYPE_BAREWORD, pos, (size_t)(endptr - cs) - pos + 1, cs + pos); + return (size_t)((endptr - cs) + 1); + } +} + +static size_t parse_word(struct libinjection_sqli_state * sf) +{ + char ch; + char delim; + size_t i; + const char *cs = sf->s; + size_t pos = sf->pos; + size_t wlen = strlencspn(cs + pos, sf->slen - pos, + " []{}<>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r\"\240\000"); + + st_assign(sf->current, TYPE_BAREWORD, pos, wlen, cs + pos); + + /* now we need to look inside what we good for "." and "`" + * and see if what is before is a keyword or not + */ + for (i =0; i < sf->current->len; ++i) { + delim = sf->current->val[i]; + if (delim == '.' || delim == '`') { + ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, i); + if (ch != TYPE_NONE && ch != TYPE_BAREWORD) { + /* needed for swig */ + st_clear(sf->current); + /* + * we got something like "SELECT.1" + * or SELECT`column` + */ + st_assign(sf->current, ch, pos, i, cs + pos); + return pos + i; + } + } + } + + /* + * do normal lookup with word including '.' + */ + if (wlen < LIBINJECTION_SQLI_TOKEN_SIZE) { + + ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, wlen); + if (ch == CHAR_NULL) { + ch = TYPE_BAREWORD; + } + sf->current->type = ch; + } + return pos + wlen; +} + +/* MySQL backticks are a cross between string and + * and a bare word. + * + */ +static size_t parse_tick(struct libinjection_sqli_state* sf) +{ + size_t pos = parse_string_core(sf->s, sf->slen, sf->pos, sf->current, CHAR_TICK, 1); + + /* we could check to see if start and end of + * of string are both "`", i.e. make sure we have + * matching set. `foo` vs. `foo + * but I don't think it matters much + */ + + /* check value of string to see if it's a keyword, + * function, operator, etc + */ + char ch = sf->lookup(sf, LOOKUP_WORD, sf->current->val, sf->current->len); + if (ch == TYPE_FUNCTION) { + /* if it's a function, then convert token */ + sf->current->type = TYPE_FUNCTION; + } else { + /* otherwise it's a 'n' type -- mysql treats + * everything as a bare word + */ + sf->current->type = TYPE_BAREWORD; + } + return pos; +} + +static size_t parse_var(struct libinjection_sqli_state * sf) +{ + size_t xlen; + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos + 1; + + /* + * var_count is only used to reconstruct + * the input. It counts the number of '@' + * seen 0 in the case of NULL, 1 or 2 + */ + + /* + * move past optional other '@' + */ + if (pos < slen && cs[pos] == '@') { + pos += 1; + sf->current->count = 2; + } else { + sf->current->count = 1; + } + + /* + * MySQL allows @@`version` + */ + if (pos < slen) { + if (cs[pos] == '`') { + sf->pos = pos; + pos = parse_tick(sf); + sf->current->type = TYPE_VARIABLE; + return pos; + } else if (cs[pos] == CHAR_SINGLE || cs[pos] == CHAR_DOUBLE) { + sf->pos = pos; + pos = parse_string(sf); + sf->current->type = TYPE_VARIABLE; + return pos; + } + } + + + xlen = strlencspn(cs + pos, slen - pos, + " <>:\\?=@!#~+-*/&|^%(),';\t\n\v\f\r'`\""); + if (xlen == 0) { + st_assign(sf->current, TYPE_VARIABLE, pos, 0, cs + pos); + return pos; + } else { + st_assign(sf->current, TYPE_VARIABLE, pos, xlen, cs + pos); + return pos + xlen; + } +} + +static size_t parse_money(struct libinjection_sqli_state *sf) +{ + size_t xlen; + const char* strend; + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + + if (pos + 1 == slen) { + /* end of line */ + st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$'); + return slen; + } + + /* + * $1,000.00 or $1.000,00 ok! + * This also parses $....,,,111 but that's ok + */ + + xlen = strlenspn(cs + pos + 1, slen - pos - 1, "0123456789.,"); + if (xlen == 0) { + if (cs[pos + 1] == '$') { + /* we have $$ .. find ending $$ and make string */ + strend = memchr2(cs + pos + 2, slen - pos -2, '$', '$'); + if (strend == NULL) { + /* fell off edge */ + st_assign(sf->current, TYPE_STRING, pos + 2, slen - (pos + 2), cs + pos + 2); + sf->current->str_open = '$'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + st_assign(sf->current, TYPE_STRING, pos + 2, + (size_t)(strend - (cs + pos + 2)), cs + pos + 2); + sf->current->str_open = '$'; + sf->current->str_close = '$'; + return (size_t)(strend - cs + 2); + } + } else { + /* ok it's not a number or '$$', but maybe it's pgsql "$ quoted strings" */ + xlen = strlenspn(cs + pos + 1, slen - pos - 1, "abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + if (xlen == 0) { + /* hmm it's "$" _something_ .. just add $ and keep going*/ + st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$'); + return pos + 1; + } + /* we have $foobar????? */ + /* is it $foobar$ */ + if (pos + xlen + 1 == slen || cs[pos+xlen+1] != '$') { + /* not $foobar$, or fell off edge */ + st_assign_char(sf->current, TYPE_BAREWORD, pos, 1, '$'); + return pos + 1; + } + + /* we have $foobar$ ... find it again */ + strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2); + + if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) { + /* fell off edge */ + st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2); + sf->current->str_open = '$'; + sf->current->str_close = CHAR_NULL; + return slen; + } else { + /* got one */ + st_assign(sf->current, TYPE_STRING, pos+xlen+2, + (size_t)(strend - (cs + pos + xlen + 2)), cs+pos+xlen+2); + sf->current->str_open = '$'; + sf->current->str_close = '$'; + return (size_t)((strend + xlen + 2) - cs); + } + } + } else if (xlen == 1 && cs[pos + 1] == '.') { + /* $. should parsed as a word */ + return parse_word(sf); + } else { + st_assign(sf->current, TYPE_NUMBER, pos, 1 + xlen, cs + pos); + return pos + 1 + xlen; + } +} + +static size_t parse_number(struct libinjection_sqli_state * sf) +{ + size_t xlen; + size_t start; + const char* digits = NULL; + const char *cs = sf->s; + const size_t slen = sf->slen; + size_t pos = sf->pos; + int have_e = 0; + int have_exp = 0; + + /* cs[pos] == '0' has 1/10 chance of being true, + * while pos+1< slen is almost always true + */ + if (cs[pos] == '0' && pos + 1 < slen) { + if (cs[pos + 1] == 'X' || cs[pos + 1] == 'x') { + digits = "0123456789ABCDEFabcdef"; + } else if (cs[pos + 1] == 'B' || cs[pos + 1] == 'b') { + digits = "01"; + } + + if (digits) { + xlen = strlenspn(cs + pos + 2, slen - pos - 2, digits); + if (xlen == 0) { + st_assign(sf->current, TYPE_BAREWORD, pos, 2, cs + pos); + return pos + 2; + } else { + st_assign(sf->current, TYPE_NUMBER, pos, 2 + xlen, cs + pos); + return pos + 2 + xlen; + } + } + } + + start = pos; + while (pos < slen && ISDIGIT(cs[pos])) { + pos += 1; + } + + if (pos < slen && cs[pos] == '.') { + pos += 1; + while (pos < slen && ISDIGIT(cs[pos])) { + pos += 1; + } + if (pos - start == 1) { + /* only one character read so far */ + st_assign_char(sf->current, TYPE_DOT, start, 1, '.'); + return pos; + } + } + + if (pos < slen) { + if (cs[pos] == 'E' || cs[pos] == 'e') { + have_e = 1; + pos += 1; + if (pos < slen && (cs[pos] == '+' || cs[pos] == '-')) { + pos += 1; + } + while (pos < slen && ISDIGIT(cs[pos])) { + have_exp = 1; + pos += 1; + } + } + } + + /* oracle's ending float or double suffix + * http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements003.htm#i139891 + */ + if (pos < slen && (cs[pos] == 'd' || cs[pos] == 'D' || cs[pos] == 'f' || cs[pos] == 'F')) { + if (pos + 1 == slen) { + /* line ends evaluate "... 1.2f$" as '1.2f' */ + pos += 1; + } else if ((char_is_white(cs[pos+1]) || cs[pos+1] == ';')) { + /* + * easy case, evaluate "... 1.2f ... as '1.2f' + */ + pos += 1; + } else if (cs[pos+1] == 'u' || cs[pos+1] == 'U') { + /* + * a bit of a hack but makes '1fUNION' parse as '1f UNION' + */ + pos += 1; + } else { + /* it's like "123FROM" */ + /* parse as "123" only */ + } + } + + if (have_e == 1 && have_exp == 0) { + /* very special form of + * "1234.e" + * "10.10E" + * ".E" + * this is a WORD not a number!! */ + st_assign(sf->current, TYPE_BAREWORD, start, pos - start, cs + start); + } else { + st_assign(sf->current, TYPE_NUMBER, start, pos - start, cs + start); + } + return pos; +} + +/* + * API to return version. This allows us to increment the version + * without having to regenerated the SWIG (or other binding) in minor + * releases. + */ +const char* libinjection_version() +{ + return LIBINJECTION_VERSION; +} + +int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf) +{ + pt2Function fnptr; + size_t *pos = &sf->pos; + stoken_t *current = sf->current; + const char *s = sf->s; + const size_t slen = sf->slen; + + if (slen == 0) { + return FALSE; + } + + st_clear(current); + sf->current = current; + + /* + * if we are at beginning of string + * and in single-quote or double quote mode + * then pretend the input starts with a quote + */ + if (*pos == 0 && (sf->flags & (FLAG_QUOTE_SINGLE | FLAG_QUOTE_DOUBLE))) { + *pos = parse_string_core(s, slen, 0, current, flag2delim(sf->flags), 0); + sf->stats_tokens += 1; + return TRUE; + } + + while (*pos < slen) { + + /* + * get current character + */ + const unsigned char ch = (unsigned char) (s[*pos]); + + /* + * look up the parser, and call it + * + * Porting Note: this is mapping of char to function + * charparsers[ch]() + */ + fnptr = char_parse_map[ch]; + + *pos = (*fnptr) (sf); + + /* + * + */ + if (current->type != CHAR_NULL) { + sf->stats_tokens += 1; + return TRUE; + } + } + return FALSE; +} + +void libinjection_sqli_init(struct libinjection_sqli_state * sf, const char *s, size_t len, int flags) +{ + if (flags == 0) { + flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI; + } + + memset(sf, 0, sizeof(struct libinjection_sqli_state)); + sf->s = s; + sf->slen = len; + sf->lookup = libinjection_sqli_lookup_word; + sf->userdata = 0; + sf->flags = flags; + sf->current = &(sf->tokenvec[0]); +} + +void libinjection_sqli_reset(struct libinjection_sqli_state * sf, int flags) +{ + void *userdata = sf->userdata; + ptr_lookup_fn lookup = sf->lookup;; + + if (flags == 0) { + flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI; + } + libinjection_sqli_init(sf, sf->s, sf->slen, flags); + sf->lookup = lookup; + sf->userdata = userdata; +} + +void libinjection_sqli_callback(struct libinjection_sqli_state * sf, ptr_lookup_fn fn, void* userdata) +{ + if (fn == NULL) { + sf->lookup = libinjection_sqli_lookup_word; + sf->userdata = (void*)(NULL); + } else { + sf->lookup = fn; + sf->userdata = userdata; + } +} + +/** See if two tokens can be merged since they are compound SQL phrases. + * + * This takes two tokens, and, if they are the right type, + * merges their values together. Then checks to see if the + * new value is special using the PHRASES mapping. + * + * Example: "UNION" + "ALL" ==> "UNION ALL" + * + * C Security Notes: this is safe to use C-strings (null-terminated) + * since the types involved by definition do not have embedded nulls + * (e.g. there is no keyword with embedded null) + * + * Porting Notes: since this is C, it's oddly complicated. + * This is just: multikeywords[token.value + ' ' + token2.value] + * + */ +static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a, stoken_t * b) +{ + size_t sz1; + size_t sz2; + size_t sz3; + char tmp[LIBINJECTION_SQLI_TOKEN_SIZE]; + char ch; + + /* first token is of right type? */ + if (! + (a->type == TYPE_KEYWORD || + a->type == TYPE_BAREWORD || + a->type == TYPE_OPERATOR || + a->type == TYPE_UNION || + a->type == TYPE_FUNCTION || + a->type == TYPE_EXPRESSION || + a->type == TYPE_TSQL || + a->type == TYPE_SQLTYPE)) { + return FALSE; + } + + 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; + sz2 = b->len; + sz3 = sz1 + sz2 + 1; /* +1 for space in the middle */ + if (sz3 >= LIBINJECTION_SQLI_TOKEN_SIZE) { /* make sure there is room for ending null */ + return FALSE; + } + /* + * oddly annoying last.val + ' ' + current.val + */ + memcpy(tmp, a->val, sz1); + 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) { + st_assign(a, ch, a->pos, sz3, tmp); + return TRUE; + } else { + return FALSE; + } +} + +int libinjection_sqli_fold(struct libinjection_sqli_state * sf) +{ + stoken_t last_comment; + + /* POS is the position of where the NEXT token goes */ + size_t pos = 0; + + /* LEFT is a count of how many tokens that are already + folded or processed (i.e. part of the fingerprint) */ + size_t left = 0; + + int more = 1; + + st_clear(&last_comment); + + /* Skip all initial comments, right-parens ( and unary operators + * + */ + sf->current = &(sf->tokenvec[0]); + while (more) { + more = libinjection_sqli_tokenize(sf); + if ( ! (sf->current->type == TYPE_COMMENT || + sf->current->type == TYPE_LEFTPARENS || + sf->current->type == TYPE_SQLTYPE || + st_is_unary_op(sf->current))) { + break; + } + } + + if (! more) { + /* If input was only comments, unary or (, then exit */ + return 0; + } else { + /* it's some other token */ + pos += 1; + } + + while (1) { + FOLD_DEBUG; + + /* do we have all the max number of tokens? if so do + * some special cases for 5 tokens + */ + if (pos >= LIBINJECTION_SQLI_MAX_TOKENS) { + if ( + ( + sf->tokenvec[0].type == TYPE_NUMBER && + (sf->tokenvec[1].type == TYPE_OPERATOR || sf->tokenvec[1].type == TYPE_COMMA) && + sf->tokenvec[2].type == TYPE_LEFTPARENS && + sf->tokenvec[3].type == TYPE_NUMBER && + sf->tokenvec[4].type == TYPE_RIGHTPARENS + ) || + ( + sf->tokenvec[0].type == TYPE_BAREWORD && + sf->tokenvec[1].type == TYPE_OPERATOR && + sf->tokenvec[2].type == TYPE_LEFTPARENS && + (sf->tokenvec[3].type == TYPE_BAREWORD || sf->tokenvec[3].type == TYPE_NUMBER) && + sf->tokenvec[4].type == TYPE_RIGHTPARENS + ) || + ( + sf->tokenvec[0].type == TYPE_NUMBER && + sf->tokenvec[1].type == TYPE_RIGHTPARENS && + 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 + ) + ) + { + if (pos > LIBINJECTION_SQLI_MAX_TOKENS) { + st_copy(&(sf->tokenvec[1]), &(sf->tokenvec[LIBINJECTION_SQLI_MAX_TOKENS])); + pos = 2; + left = 0; + } else { + pos = 1; + left = 0; + } + } + } + + if (! more || left >= LIBINJECTION_SQLI_MAX_TOKENS) { + left = pos; + break; + } + + /* get up to two tokens */ + while (more && pos <= LIBINJECTION_SQLI_MAX_TOKENS && (pos - left) < 2) { + sf->current = &(sf->tokenvec[pos]); + more = libinjection_sqli_tokenize(sf); + if (more) { + if (sf->current->type == TYPE_COMMENT) { + st_copy(&last_comment, sf->current); + } else { + last_comment.type = CHAR_NULL; + pos += 1; + } + } + } + FOLD_DEBUG; + /* did we get 2 tokens? if not then we are done */ + if (pos - left < 2) { + left = pos; + continue; + } + + /* FOLD: "ss" -> "s" + * "foo" "bar" is valid SQL + * just ignore second string + */ + if (sf->tokenvec[left].type == TYPE_STRING && sf->tokenvec[left+1].type == TYPE_STRING) { + pos -= 1; + sf->stats_folds += 1; + continue; + } else if (sf->tokenvec[left].type == TYPE_SEMICOLON && sf->tokenvec[left+1].type == TYPE_SEMICOLON) { + /* not sure how various engines handle + * 'select 1;;drop table foo' or + * 'select 1; /x foo x/; drop table foo' + * to prevent surprises, just fold away repeated semicolons + */ + pos -= 1; + sf->stats_folds += 1; + continue; + } else if ((sf->tokenvec[left].type == TYPE_OPERATOR || + sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR) && + (st_is_unary_op(&sf->tokenvec[left+1]) || + sf->tokenvec[left+1].type == TYPE_SQLTYPE)) { + pos -= 1; + sf->stats_folds += 1; + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_LEFTPARENS && + st_is_unary_op(&sf->tokenvec[left+1])) { + pos -= 1; + sf->stats_folds += 1; + if (left > 0) { + left -= 1; + } + continue; + } else if (syntax_merge_words(sf, &sf->tokenvec[left], &sf->tokenvec[left+1])) { + pos -= 1; + sf->stats_folds += 1; + if (left > 0) { + 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 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 || + + /* Function in MYSQL */ + cstrcasecmp("DATABASE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("PASSWORD", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + + /* Mysql words that act as a variable and are a function */ + + /* TSQL current_users is fake-variable */ + /* http://msdn.microsoft.com/en-us/library/ms176050.aspx */ + cstrcasecmp("CURRENT_USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("CURRENT_DATE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("CURRENT_TIME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("CURRENT_TIMESTAMP", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("LOCALTIME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("LOCALTIMESTAMP", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 + )) { + + /* pos is the same + * other conversions need to go here... for instance + * password CAN be a function, coalesce CAN be a function + */ + sf->tokenvec[left].type = TYPE_FUNCTION; + continue; + } else if (sf->tokenvec[left].type == TYPE_KEYWORD && ( + cstrcasecmp("IN", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("NOT IN", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 + )) { + + if (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) { + /* got .... IN ( ... (or 'NOT IN') + * it's an operator + */ + sf->tokenvec[left].type = TYPE_OPERATOR; + } else { + /* + * it's a nothing + */ + sf->tokenvec[left].type = TYPE_BAREWORD; + } + + /* "IN" can be used as "IN BOOLEAN MODE" for mysql + * in which case merging of words can be done later + * other wise it acts as an equality operator __ IN (values..) + * + * here we got "IN" "(" so it's an operator. + * also back track to handle "NOT IN" + * might need to do the same with like + * two use cases "foo" LIKE "BAR" (normal operator) + * "foo" = LIKE(1,2) + */ + continue; + } else if ((sf->tokenvec[left].type == TYPE_OPERATOR) && ( + cstrcasecmp("LIKE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 || + cstrcasecmp("NOT LIKE", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0)) { + if (sf->tokenvec[left+1].type == TYPE_LEFTPARENS) { + /* SELECT LIKE(... + * it's a function + */ + sf->tokenvec[left].type = TYPE_FUNCTION; + } + } else if (sf->tokenvec[left].type == TYPE_SQLTYPE && + (sf->tokenvec[left+1].type == TYPE_BAREWORD || + sf->tokenvec[left+1].type == TYPE_NUMBER || + sf->tokenvec[left+1].type == TYPE_SQLTYPE || + sf->tokenvec[left+1].type == TYPE_LEFTPARENS || + sf->tokenvec[left+1].type == TYPE_FUNCTION || + sf->tokenvec[left+1].type == TYPE_VARIABLE || + sf->tokenvec[left+1].type == TYPE_STRING)) { + st_copy(&sf->tokenvec[left], &sf->tokenvec[left+1]); + pos -= 1; + sf->stats_folds += 1; + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_COLLATE && + sf->tokenvec[left+1].type == TYPE_BAREWORD) { + /* + * there are too many collation types.. so if the bareword has a "_" + * then it's TYPE_SQLTYPE + */ + if (strchr(sf->tokenvec[left+1].val, '_') != NULL) { + sf->tokenvec[left+1].type = TYPE_SQLTYPE; + left = 0; + } + } else if (sf->tokenvec[left].type == TYPE_BACKSLASH) { + if (st_is_arithmetic_op(&(sf->tokenvec[left+1]))) { + /* very weird case in TSQL where '\%1' is parsed as '0 % 1', etc */ + sf->tokenvec[left].type = TYPE_NUMBER; + } else { + /* just ignore it.. Again T-SQL seems to parse \1 as "1" */ + st_copy(&sf->tokenvec[left], &sf->tokenvec[left+1]); + pos -= 1; + sf->stats_folds += 1; + } + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_LEFTPARENS && + sf->tokenvec[left+1].type == TYPE_LEFTPARENS) { + pos -= 1; + left = 0; + sf->stats_folds += 1; + continue; + } else if (sf->tokenvec[left].type == TYPE_RIGHTPARENS && + sf->tokenvec[left+1].type == TYPE_RIGHTPARENS) { + pos -= 1; + left = 0; + sf->stats_folds += 1; + continue; + } else if (sf->tokenvec[left].type == TYPE_LEFTBRACE && + sf->tokenvec[left+1].type == TYPE_BAREWORD) { + + /* + * MySQL Degenerate case -- + * + * select { ``.``.id }; -- valid !!! + * select { ``.``.``.id }; -- invalid + * select ``.``.id; -- invalid + * select { ``.id }; -- invalid + * + * so it appears {``.``.id} is a magic case + * I suspect this is "current database, current table, field id" + * + * The folding code can't look at more than 3 tokens, and + * I don't want to make two passes. + * + * Since "{ ``" so rare, we are just going to blacklist it. + * + * Highly likely this will need revisiting! + * + * CREDIT @rsalgado 2013-11-25 + */ + if (sf->tokenvec[left+1].len == 0) { + sf->tokenvec[left+1].type = TYPE_EVIL; + return (int)(left+2); + } + /* weird ODBC / MYSQL {foo expr} --> expr + * but for this rule we just strip away the "{ foo" part + */ + left = 0; + pos -= 2; + sf->stats_folds += 2; + continue; + } else if (sf->tokenvec[left+1].type == TYPE_RIGHTBRACE) { + pos -= 1; + left = 0; + sf->stats_folds += 1; + continue; + } + + /* all cases of handing 2 tokens is done + and nothing matched. Get one more token + */ + FOLD_DEBUG; + while (more && pos <= LIBINJECTION_SQLI_MAX_TOKENS && pos - left < 3) { + sf->current = &(sf->tokenvec[pos]); + more = libinjection_sqli_tokenize(sf); + if (more) { + if (sf->current->type == TYPE_COMMENT) { + st_copy(&last_comment, sf->current); + } else { + last_comment.type = CHAR_NULL; + pos += 1; + } + } + } + + /* do we have three tokens? If not then we are done */ + if (pos -left < 3) { + left = pos; + continue; + } + + /* + * now look for three token folding + */ + if (sf->tokenvec[left].type == TYPE_NUMBER && + sf->tokenvec[left+1].type == TYPE_OPERATOR && + sf->tokenvec[left+2].type == TYPE_NUMBER) { + pos -= 2; + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_OPERATOR && + sf->tokenvec[left+1].type != TYPE_LEFTPARENS && + sf->tokenvec[left+2].type == TYPE_OPERATOR) { + left = 0; + pos -= 2; + continue; + } else if (sf->tokenvec[left].type == TYPE_LOGIC_OPERATOR && + sf->tokenvec[left+2].type == TYPE_LOGIC_OPERATOR) { + pos -= 2; + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_VARIABLE && + sf->tokenvec[left+1].type == TYPE_OPERATOR && + (sf->tokenvec[left+2].type == TYPE_VARIABLE || + sf->tokenvec[left+2].type == TYPE_NUMBER || + sf->tokenvec[left+2].type == TYPE_BAREWORD)) { + pos -= 2; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || + sf->tokenvec[left].type == TYPE_NUMBER ) && + sf->tokenvec[left+1].type == TYPE_OPERATOR && + (sf->tokenvec[left+2].type == TYPE_NUMBER || + sf->tokenvec[left+2].type == TYPE_BAREWORD)) { + pos -= 2; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || + sf->tokenvec[left].type == TYPE_NUMBER || + sf->tokenvec[left].type == TYPE_VARIABLE || + sf->tokenvec[left].type == TYPE_STRING) && + sf->tokenvec[left+1].type == TYPE_OPERATOR && + streq(sf->tokenvec[left+1].val, "::") && + sf->tokenvec[left+2].type == TYPE_SQLTYPE) { + pos -= 2; + left = 0; + sf->stats_folds += 2; + continue; + } else if ((sf->tokenvec[left].type == TYPE_BAREWORD || + sf->tokenvec[left].type == TYPE_NUMBER || + sf->tokenvec[left].type == TYPE_STRING || + sf->tokenvec[left].type == TYPE_VARIABLE) && + sf->tokenvec[left+1].type == TYPE_COMMA && + (sf->tokenvec[left+2].type == TYPE_NUMBER || + sf->tokenvec[left+2].type == TYPE_BAREWORD || + sf->tokenvec[left+2].type == TYPE_STRING || + sf->tokenvec[left+2].type == TYPE_VARIABLE)) { + pos -= 2; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_EXPRESSION || + sf->tokenvec[left].type == TYPE_GROUP || + sf->tokenvec[left].type == TYPE_COMMA) && + st_is_unary_op(&sf->tokenvec[left+1]) && + sf->tokenvec[left+2].type == TYPE_LEFTPARENS) { + /* got something like SELECT + (, LIMIT + ( + * remove unary operator + */ + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + pos -= 1; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_KEYWORD || + sf->tokenvec[left].type == TYPE_EXPRESSION || + sf->tokenvec[left].type == TYPE_GROUP ) && + st_is_unary_op(&sf->tokenvec[left+1]) && + (sf->tokenvec[left+2].type == TYPE_NUMBER || + sf->tokenvec[left+2].type == TYPE_BAREWORD || + sf->tokenvec[left+2].type == TYPE_VARIABLE || + sf->tokenvec[left+2].type == TYPE_STRING || + sf->tokenvec[left+2].type == TYPE_FUNCTION )) { + /* remove unary operators + * select - 1 + */ + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + pos -= 1; + left = 0; + continue; + } else if (sf->tokenvec[left].type == TYPE_COMMA && + st_is_unary_op(&sf->tokenvec[left+1]) && + (sf->tokenvec[left+2].type == TYPE_NUMBER || + sf->tokenvec[left+2].type == TYPE_BAREWORD || + sf->tokenvec[left+2].type == TYPE_VARIABLE || + sf->tokenvec[left+2].type == TYPE_STRING)) { + /* + * interesting case turn ", -1" ->> ",1" PLUS we need to back up + * one token if possible to see if more folding can be done + * "1,-1" --> "1" + */ + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + left = 0; + /* pos is >= 3 so this is safe */ + assert(pos >= 3); + pos -= 3; + continue; + } else if (sf->tokenvec[left].type == TYPE_COMMA && + st_is_unary_op(&sf->tokenvec[left+1]) && + sf->tokenvec[left+2].type == TYPE_FUNCTION) { + + /* Separate case from above since you end up with + * 1,-sin(1) --> 1 (1) + * Here, just do + * 1,-sin(1) --> 1,sin(1) + * just remove unary operator + */ + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + pos -= 1; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_BAREWORD) && + (sf->tokenvec[left+1].type == TYPE_DOT) && + (sf->tokenvec[left+2].type == TYPE_BAREWORD)) { + /* ignore the '.n' + * typically is this databasename.table + */ + assert(pos >= 3); + pos -= 2; + left = 0; + continue; + } else if ((sf->tokenvec[left].type == TYPE_EXPRESSION) && + (sf->tokenvec[left+1].type == TYPE_DOT) && + (sf->tokenvec[left+2].type == TYPE_BAREWORD)) { + /* select . `foo` --> select `foo` */ + st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]); + 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 + */ + + left += 1; + + } /* while(1) */ + + /* if we have 4 or less tokens, and we had a comment token + * at the end, add it back + */ + + if (left < LIBINJECTION_SQLI_MAX_TOKENS && last_comment.type == TYPE_COMMENT) { + st_copy(&sf->tokenvec[left], &last_comment); + left += 1; + } + + /* sometimes we grab a 6th token to help + determine the type of token 5. + */ + if (left > LIBINJECTION_SQLI_MAX_TOKENS) { + left = LIBINJECTION_SQLI_MAX_TOKENS; + } + + return (int)left; +} + +/* secondary api: detects SQLi in a string, GIVEN a context. + * + * A context can be: + * * CHAR_NULL (\0), process as is + * * CHAR_SINGLE ('), process pretending input started with a + * single quote. + * * CHAR_DOUBLE ("), process pretending input started with a + * double quote. + * + */ +const char* libinjection_sqli_fingerprint(struct libinjection_sqli_state * sql_state, int flags) +{ + int i; + int tlen = 0; + + libinjection_sqli_reset(sql_state, flags); + + tlen = libinjection_sqli_fold(sql_state); + + /* Check for magic PHP backquote comment + * If: + * * last token is of type "bareword" + * * And is quoted in a backtick + * * And isn't closed + * * And it's empty? + * Then convert it to comment + */ + if (tlen > 2 && + sql_state->tokenvec[tlen-1].type == TYPE_BAREWORD && + sql_state->tokenvec[tlen-1].str_open == CHAR_TICK && + sql_state->tokenvec[tlen-1].len == 0 && + sql_state->tokenvec[tlen-1].str_close == CHAR_NULL) { + sql_state->tokenvec[tlen-1].type = TYPE_COMMENT; + } + + for (i = 0; i < tlen; ++i) { + sql_state->fingerprint[i] = sql_state->tokenvec[i].type; + } + + /* + * make the fingerprint pattern a c-string (null delimited) + */ + sql_state->fingerprint[tlen] = CHAR_NULL; + + /* + * check for 'X' in pattern, and then + * clear out all tokens + * + * this means parsing could not be done + * accurately due to pgsql's double comments + * or other syntax that isn't consistent. + * Should be very rare false positive + */ + if (strchr(sql_state->fingerprint, TYPE_EVIL)) { + /* needed for SWIG */ + memset((void*)sql_state->fingerprint, 0, LIBINJECTION_SQLI_MAX_TOKENS + 1); + memset((void*)sql_state->tokenvec[0].val, 0, LIBINJECTION_SQLI_TOKEN_SIZE); + + sql_state->fingerprint[0] = TYPE_EVIL; + + sql_state->tokenvec[0].type = TYPE_EVIL; + sql_state->tokenvec[0].val[0] = TYPE_EVIL; + sql_state->tokenvec[1].type = CHAR_NULL; + } + + + return sql_state->fingerprint; +} + +int libinjection_sqli_check_fingerprint(struct libinjection_sqli_state* sql_state) +{ + return libinjection_sqli_blacklist(sql_state) && + libinjection_sqli_not_whitelist(sql_state); +} + +char libinjection_sqli_lookup_word(struct libinjection_sqli_state *sql_state, int lookup_type, + const char* str, size_t len) +{ + if (lookup_type == LOOKUP_FINGERPRINT) { + return libinjection_sqli_check_fingerprint(sql_state) ? 'X' : '\0'; + } else { + return bsearch_keyword_type(str, len, sql_keywords, sql_keywords_sz); + } +} + +int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state) +{ + /* + * use minimum of 8 bytes to make sure gcc -fstack-protector + * works correctly + */ + char fp2[8]; + char ch; + size_t i; + size_t len = strlen(sql_state->fingerprint); + int patmatch; + + if (len < 1) { + sql_state->reason = __LINE__; + return FALSE; + } + + /* + to keep everything compatible, convert the + v0 fingerprint pattern to v1 + v0: up to 5 chars, mixed case + v1: 1 char is '0', up to 5 more chars, upper case + */ + + fp2[0] = '0'; + for (i = 0; i < len; ++i) { + ch = sql_state->fingerprint[i]; + if (ch >= 'a' && ch <= 'z') { + ch -= 0x20; + } + fp2[i+1] = ch; + } + fp2[i+1] = '\0'; + + patmatch = is_keyword(fp2, len + 1) == TYPE_FINGERPRINT; + + /* + * No match. + * + * Set sql_state->reason to current line number + * only for debugging purposes. + */ + if (!patmatch) { + sql_state->reason = __LINE__; + return FALSE; + } + + return TRUE; +} + +/* + * return TRUE if SQLi, false is benign + */ +int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state) +{ + /* + * We assume we got a SQLi match + * This next part just helps reduce false positives. + * + */ + char ch; + size_t tlen = strlen(sql_state->fingerprint); + + if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) { + /* + * if ending comment is contains 'sp_password' then it's SQLi! + * MS Audit log apparently ignores anything with + * 'sp_password' in it. Unable to find primary reference to + * this "feature" of SQL Server but seems to be known SQLi + * technique + */ + if (my_memmem(sql_state->s, sql_state->slen, + "sp_password", strlen("sp_password"))) { + sql_state->reason = __LINE__; + return TRUE; + } + } + + switch (tlen) { + case 2:{ + /* + * case 2 are "very small SQLi" which make them + * hard to tell from normal input... + */ + + if (sql_state->fingerprint[1] == TYPE_UNION) { + if (sql_state->stats_tokens == 2) { + /* 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 + */ + /* it really is a number and 'union' + * other wise it has folding or comments + */ + sql_state->reason = __LINE__; + return FALSE; + } else { + sql_state->reason = __LINE__; + return TRUE; + } + } + /* + * if 'comment' is '#' ignore.. too many FP + */ + if (sql_state->tokenvec[1].val[0] == '#') { + sql_state->reason = __LINE__; + return FALSE; + } + + /* + * for fingerprint like 'nc', only comments of /x are treated + * as SQL... ending comments of "--" and "#" are not SQLi + */ + if (sql_state->tokenvec[0].type == TYPE_BAREWORD && + sql_state->tokenvec[1].type == TYPE_COMMENT && + sql_state->tokenvec[1].val[0] != '/') { + sql_state->reason = __LINE__; + return FALSE; + } + + /* + * if '1c' ends with '/x' then it's SQLi + */ + if (sql_state->tokenvec[0].type == TYPE_NUMBER && + sql_state->tokenvec[1].type == TYPE_COMMENT && + sql_state->tokenvec[1].val[0] == '/') { + return TRUE; + } + + /** + * there are some odd base64-looking query string values + * 1234-ABCDEFEhfhihwuefi-- + * which evaluate to "1c"... these are not SQLi + * but 1234-- probably is. + * Make sure the "1" in "1c" is actually a true decimal number + * + * Need to check -original- string since the folding step + * may have merged tokens, e.g. "1+FOO" is folded into "1" + * + * Note: evasion: 1*1-- + */ + 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 */ + sql_state->reason = __LINE__; + return TRUE; + } + /* + * we check that next character after the number is either whitespace, + * or '/' or a '-' ==> SQLi. + */ + ch = sql_state->s[sql_state->tokenvec[0].len]; + if ( ch <= 32 ) { + /* next char was whitespace,e.g. "1234 --" + * this isn't exactly correct.. ideally we should skip over all whitespace + * but this seems to be ok for now + */ + return TRUE; + } + if (ch == '/' && sql_state->s[sql_state->tokenvec[0].len + 1] == '*') { + return TRUE; + } + if (ch == '-' && sql_state->s[sql_state->tokenvec[0].len + 1] == '-') { + return TRUE; + } + + sql_state->reason = __LINE__; + return FALSE; + } + + /* + * 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) + && sql_state->tokenvec[1].val[0] == '-') { + sql_state->reason = __LINE__; + return FALSE; + } + + break; + } /* case 2 */ + case 3:{ + /* + * ...foo' + 'bar... + * no opening quote, no closing quote + * and each string has data + */ + + if (streq(sql_state->fingerprint, "sos") + || streq(sql_state->fingerprint, "s&s")) { + + if ((sql_state->tokenvec[0].str_open == CHAR_NULL) + && (sql_state->tokenvec[2].str_close == CHAR_NULL) + && (sql_state->tokenvec[0].str_close == sql_state->tokenvec[2].str_open)) { + /* + * if ....foo" + "bar.... + */ + sql_state->reason = __LINE__; + return TRUE; + } + if (sql_state->stats_tokens == 3) { + sql_state->reason = __LINE__; + return FALSE; + } + + /* + * not SQLi + */ + sql_state->reason = __LINE__; + return FALSE; + } else if (streq(sql_state->fingerprint, "s&n") || + streq(sql_state->fingerprint, "n&1") || + 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 + */ + if (sql_state->stats_tokens == 3) { + sql_state->reason = __LINE__; + return FALSE; + } + } else if (sql_state->tokenvec[1].type == TYPE_KEYWORD) { + if ((sql_state->tokenvec[1].len < 5) || + cstrcasecmp("INTO", sql_state->tokenvec[1].val, 4)) { + /* if it's not "INTO OUTFILE", or "INTO DUMPFILE" (MySQL) + * then treat as safe + */ + sql_state->reason = __LINE__; + return FALSE; + } + } + break; + } /* case 3 */ + case 4: + case 5: { + /* nothing right now */ + break; + } /* case 5 */ + } /* end switch */ + + return TRUE; +} + +/** Main API, detects SQLi in an input. + * + * + */ +static int reparse_as_mysql(struct libinjection_sqli_state * sql_state) +{ + return sql_state->stats_comment_ddx || + sql_state->stats_comment_hash; +} + +/* + * This function is mostly use with SWIG + */ +struct libinjection_sqli_token* +libinjection_sqli_get_token(struct libinjection_sqli_state * sql_state, int i) +{ + if (i < 0 || i > (int)LIBINJECTION_SQLI_MAX_TOKENS) { + return NULL; + } + return &(sql_state->tokenvec[i]); +} + +int libinjection_is_sqli(struct libinjection_sqli_state * sql_state) +{ + const char *s = sql_state->s; + size_t slen = sql_state->slen; + + /* + * no input? not SQLi + */ + if (slen == 0) { + return FALSE; + } + + /* + * test input "as-is" + */ + libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_ANSI); + if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, + sql_state->fingerprint, strlen(sql_state->fingerprint))) { + return TRUE; + } else if (reparse_as_mysql(sql_state)) { + libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_NONE | FLAG_SQL_MYSQL); + if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, + sql_state->fingerprint, strlen(sql_state->fingerprint))) { + return TRUE; + } + } + + /* + * if input has a single_quote, then + * test as if input was actually ' + * example: if input if "1' = 1", then pretend it's + * "'1' = 1" + * Porting Notes: example the same as doing + * is_string_sqli(sql_state, "'" + s, slen+1, NULL, fn, arg) + * + */ + if (memchr(s, CHAR_SINGLE, slen)) { + libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_ANSI); + if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, + sql_state->fingerprint, strlen(sql_state->fingerprint))) { + return TRUE; + } else if (reparse_as_mysql(sql_state)) { + libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_SINGLE | FLAG_SQL_MYSQL); + if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, + sql_state->fingerprint, strlen(sql_state->fingerprint))) { + return TRUE; + } + } + } + + /* + * same as above but with a double-quote " + */ + if (memchr(s, CHAR_DOUBLE, slen)) { + libinjection_sqli_fingerprint(sql_state, FLAG_QUOTE_DOUBLE | FLAG_SQL_MYSQL); + if (sql_state->lookup(sql_state, LOOKUP_FINGERPRINT, + sql_state->fingerprint, strlen(sql_state->fingerprint))) { + return TRUE; + } + } + + /* + * Hurray, input is not SQLi + */ + return FALSE; +} + +int libinjection_sqli(const char* input, size_t slen, char fingerprint[]) +{ + int issqli; + struct libinjection_sqli_state state; + + libinjection_sqli_init(&state, input, slen, 0); + issqli = libinjection_is_sqli(&state); + if (issqli) { + strcpy(fingerprint, state.fingerprint); + } else { + fingerprint[0] = '\0'; + } + return issqli; +} diff --git a/apache2/libinjection/libinjection_sqli.h b/apache2/libinjection/libinjection_sqli.h new file mode 100644 index 0000000..b974655 --- /dev/null +++ b/apache2/libinjection/libinjection_sqli.h @@ -0,0 +1,294 @@ +/** + * Copyright 2012-2016 Nick Galbreath + * nickg@client9.com + * BSD License -- see `COPYING.txt` for details + * + * https://libinjection.client9.com/ + * + */ + +#ifndef LIBINJECTION_SQLI_H +#define LIBINJECTION_SQLI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pull in size_t + */ +#include + +enum sqli_flags { + FLAG_NONE = 0 + , FLAG_QUOTE_NONE = 1 /* 1 << 0 */ + , FLAG_QUOTE_SINGLE = 2 /* 1 << 1 */ + , FLAG_QUOTE_DOUBLE = 4 /* 1 << 2 */ + + , FLAG_SQL_ANSI = 8 /* 1 << 3 */ + , FLAG_SQL_MYSQL = 16 /* 1 << 4 */ +}; + +enum lookup_type { + LOOKUP_WORD = 1 + , LOOKUP_TYPE = 2 + , LOOKUP_OPERATOR = 3 + , LOOKUP_FINGERPRINT = 4 +}; + +struct libinjection_sqli_token { +#ifdef SWIG +%immutable; +#endif + /* + * position and length of token + * in original string + */ + size_t pos; + size_t len; + + /* count: + * in type 'v', used for number of opening '@' + * 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 c-string input, + * returns '\0' for no match, else a char + */ +struct libinjection_sqli_state; +typedef char (*ptr_lookup_fn)(struct libinjection_sqli_state*, int lookuptype, const char* word, size_t len); + +struct libinjection_sqli_state { +#ifdef SWIG +%immutable; +#endif + + /* + * input, does not need to be null terminated. + * it is also not modified. + */ + const char *s; + + /* + * input length + */ + size_t slen; + + /* + * How to lookup a word or fingerprint + */ + ptr_lookup_fn lookup; + void* userdata; + + /* + * + */ + int flags; + + /* + * pos is the index in the string during tokenization + */ + size_t pos; + +#ifndef SWIG + /* for SWIG.. don't use this.. use functional API instead */ + + /* MAX TOKENS + 1 since we use one extra token + * to determine the type of the previous token + */ + struct libinjection_sqli_token tokenvec[8]; +#endif + + /* + * Pointer to token position in tokenvec, above + */ + struct libinjection_sqli_token *current; + + /* + * fingerprint pattern c-string + * +1 for ending null + * Minimum of 8 bytes to add gcc's -fstack-protector to work + */ + char fingerprint[8]; + + /* + * Line number of code that said decided if the input was SQLi or + * not. Most of the time it's line that said "it's not a matching + * fingerprint" but there is other logic that sometimes approves + * an input. This is only useful for debugging. + * + */ + int reason; + + /* Number of ddw (dash-dash-white) comments + * These comments are in the form of + * '--[whitespace]' or '--[EOF]' + * + * All databases treat this as a comment. + */ + int stats_comment_ddw; + + /* Number of ddx (dash-dash-[notwhite]) comments + * + * ANSI SQL treats these are comments, MySQL treats this as + * two unary operators '-' '-' + * + * If you are parsing result returns FALSE and + * stats_comment_dd > 0, you should reparse with + * COMMENT_MYSQL + * + */ + int stats_comment_ddx; + + /* + * c-style comments found /x .. x/ + */ + int stats_comment_c; + + /* '#' operators or MySQL EOL comments found + * + */ + int stats_comment_hash; + + /* + * number of tokens folded away + */ + int stats_folds; + + /* + * total tokens processed + */ + int stats_tokens; + +}; + +typedef struct libinjection_sqli_state sfilter; + +struct libinjection_sqli_token* libinjection_sqli_get_token( + struct libinjection_sqli_state* sqlistate, int i); + +/* + * Version info. + * + * This is moved into a function to allow SWIG and other auto-generated + * binding to not be modified during minor release changes. We change + * change the version number in the c source file, and not regenerated + * the binding + * + * See python's normalized version + * http://www.python.org/dev/peps/pep-0386/#normalizedversion + */ +const char* libinjection_version(void); + +/** + * + */ +void libinjection_sqli_init(struct libinjection_sqli_state* sql_state, + const char* s, size_t slen, + int flags); + +/** + * Main API: tests for SQLi in three possible contexts, no quotes, + * single quote and double quote + * + * \param sql_state core data structure + * + * \return 1 (true) if SQLi, 0 (false) if benign + */ +int libinjection_is_sqli(struct libinjection_sqli_state* sql_state); + +/* 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, + void* userdata); + + +/* + * Resets state, but keeps initial string and callbacks + */ +void libinjection_sqli_reset(struct libinjection_sqli_state* sql_state, + int flags); + +/** + * + */ + +/** + * This detects SQLi in a single context, mostly useful for custom + * logic and debugging. + * + * \param sql_state Main data structure + * \param flags flags to adjust parsing + * + * \returns a pointer to sfilter.fingerprint as convenience + * do not free! + * + */ +const char* libinjection_sqli_fingerprint(struct libinjection_sqli_state* sql_state, + int flags); + +/** + * The default "word" to token-type or fingerprint function. This + * uses a ASCII case-insensitive binary tree. + */ +char libinjection_sqli_lookup_word(struct libinjection_sqli_state* sql_state, + int lookup_type, + const char* s, + size_t slen); + +/* Streaming tokenization interface. + * + * sql_state->current is updated with the current token. + * + * \returns 1, has a token, keep going, or 0 no tokens + * + */ +int libinjection_sqli_tokenize(struct libinjection_sqli_state * sql_state); + +/** + * parses and folds input, up to 5 tokens + * + */ +int libinjection_sqli_fold(struct libinjection_sqli_state * sql_state); + +/** The built-in default function to match fingerprints + * and do false negative/positive analysis. This calls the following + * two functions. With this, you over-ride one part or the other. + * + * return libinjection_sqli_blacklist(sql_state) && + * libinjection_sqli_not_whitelist(sql_state); + * + * \param sql_state should be filled out after libinjection_sqli_fingerprint is called + */ +int libinjection_sqli_check_fingerprint(struct libinjection_sqli_state * sql_state); + +/* Given a pattern determine if it's a SQLi pattern. + * + * \return TRUE if sqli, false otherwise + */ +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 + */ +int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBINJECTION_SQLI_H */ diff --git a/apache2/libinjection/libinjection_sqli_data.h b/apache2/libinjection/libinjection_sqli_data.h new file mode 100644 index 0000000..f5e1454 --- /dev/null +++ b/apache2/libinjection/libinjection_sqli_data.h @@ -0,0 +1,9652 @@ + +#ifndef LIBINJECTION_SQLI_DATA_H +#define LIBINJECTION_SQLI_DATA_H + +#include "libinjection.h" +#include "libinjection_sqli.h" + +typedef struct { + const char *word; + char type; +} keyword_t; + +static size_t parse_money(sfilter * sf); +static size_t parse_other(sfilter * sf); +static size_t parse_white(sfilter * sf); +static size_t parse_operator1(sfilter *sf); +static size_t parse_char(sfilter *sf); +static size_t parse_hash(sfilter *sf); +static size_t parse_dash(sfilter *sf); +static size_t parse_slash(sfilter *sf); +static size_t parse_backslash(sfilter * sf); +static size_t parse_operator2(sfilter *sf); +static size_t parse_string(sfilter *sf); +static size_t parse_word(sfilter * sf); +static size_t parse_var(sfilter * sf); +static size_t parse_number(sfilter * sf); +static size_t parse_tick(sfilter * sf); +static size_t parse_ustring(sfilter * sf); +static size_t parse_qstring(sfilter * sf); +static size_t parse_nqstring(sfilter * sf); +static size_t parse_xstring(sfilter * sf); +static size_t parse_bstring(sfilter * sf); +static size_t parse_estring(sfilter * sf); +static size_t parse_bword(sfilter * sf); + + +typedef size_t (*pt2Function)(sfilter *sf); +static const pt2Function char_parse_map[] = { + &parse_white, /* 0 */ + &parse_white, /* 1 */ + &parse_white, /* 2 */ + &parse_white, /* 3 */ + &parse_white, /* 4 */ + &parse_white, /* 5 */ + &parse_white, /* 6 */ + &parse_white, /* 7 */ + &parse_white, /* 8 */ + &parse_white, /* 9 */ + &parse_white, /* 10 */ + &parse_white, /* 11 */ + &parse_white, /* 12 */ + &parse_white, /* 13 */ + &parse_white, /* 14 */ + &parse_white, /* 15 */ + &parse_white, /* 16 */ + &parse_white, /* 17 */ + &parse_white, /* 18 */ + &parse_white, /* 19 */ + &parse_white, /* 20 */ + &parse_white, /* 21 */ + &parse_white, /* 22 */ + &parse_white, /* 23 */ + &parse_white, /* 24 */ + &parse_white, /* 25 */ + &parse_white, /* 26 */ + &parse_white, /* 27 */ + &parse_white, /* 28 */ + &parse_white, /* 29 */ + &parse_white, /* 30 */ + &parse_white, /* 31 */ + &parse_white, /* 32 */ + &parse_operator2, /* 33 */ + &parse_string, /* 34 */ + &parse_hash, /* 35 */ + &parse_money, /* 36 */ + &parse_operator1, /* 37 */ + &parse_operator2, /* 38 */ + &parse_string, /* 39 */ + &parse_char, /* 40 */ + &parse_char, /* 41 */ + &parse_operator2, /* 42 */ + &parse_operator1, /* 43 */ + &parse_char, /* 44 */ + &parse_dash, /* 45 */ + &parse_number, /* 46 */ + &parse_slash, /* 47 */ + &parse_number, /* 48 */ + &parse_number, /* 49 */ + &parse_number, /* 50 */ + &parse_number, /* 51 */ + &parse_number, /* 52 */ + &parse_number, /* 53 */ + &parse_number, /* 54 */ + &parse_number, /* 55 */ + &parse_number, /* 56 */ + &parse_number, /* 57 */ + &parse_operator2, /* 58 */ + &parse_char, /* 59 */ + &parse_operator2, /* 60 */ + &parse_operator2, /* 61 */ + &parse_operator2, /* 62 */ + &parse_other, /* 63 */ + &parse_var, /* 64 */ + &parse_word, /* 65 */ + &parse_bstring, /* 66 */ + &parse_word, /* 67 */ + &parse_word, /* 68 */ + &parse_estring, /* 69 */ + &parse_word, /* 70 */ + &parse_word, /* 71 */ + &parse_word, /* 72 */ + &parse_word, /* 73 */ + &parse_word, /* 74 */ + &parse_word, /* 75 */ + &parse_word, /* 76 */ + &parse_word, /* 77 */ + &parse_nqstring, /* 78 */ + &parse_word, /* 79 */ + &parse_word, /* 80 */ + &parse_qstring, /* 81 */ + &parse_word, /* 82 */ + &parse_word, /* 83 */ + &parse_word, /* 84 */ + &parse_ustring, /* 85 */ + &parse_word, /* 86 */ + &parse_word, /* 87 */ + &parse_xstring, /* 88 */ + &parse_word, /* 89 */ + &parse_word, /* 90 */ + &parse_bword, /* 91 */ + &parse_backslash, /* 92 */ + &parse_other, /* 93 */ + &parse_operator1, /* 94 */ + &parse_word, /* 95 */ + &parse_tick, /* 96 */ + &parse_word, /* 97 */ + &parse_bstring, /* 98 */ + &parse_word, /* 99 */ + &parse_word, /* 100 */ + &parse_estring, /* 101 */ + &parse_word, /* 102 */ + &parse_word, /* 103 */ + &parse_word, /* 104 */ + &parse_word, /* 105 */ + &parse_word, /* 106 */ + &parse_word, /* 107 */ + &parse_word, /* 108 */ + &parse_word, /* 109 */ + &parse_nqstring, /* 110 */ + &parse_word, /* 111 */ + &parse_word, /* 112 */ + &parse_qstring, /* 113 */ + &parse_word, /* 114 */ + &parse_word, /* 115 */ + &parse_word, /* 116 */ + &parse_ustring, /* 117 */ + &parse_word, /* 118 */ + &parse_word, /* 119 */ + &parse_xstring, /* 120 */ + &parse_word, /* 121 */ + &parse_word, /* 122 */ + &parse_char, /* 123 */ + &parse_operator2, /* 124 */ + &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[] = { + {"!!", 'o'}, + {"!<", 'o'}, + {"!=", 'o'}, + {"!>", 'o'}, + {"%=", 'o'}, + {"&&", '&'}, + {"&=", 'o'}, + {"*=", 'o'}, + {"+=", 'o'}, + {"-=", 'o'}, + {"/=", 'o'}, + {"0&(1)O", 'F'}, + {"0&(1)U", 'F'}, + {"0&(1O(", 'F'}, + {"0&(1OF", 'F'}, + {"0&(1OS", 'F'}, + {"0&(1OV", 'F'}, + {"0&(F()", 'F'}, + {"0&(F(1", 'F'}, + {"0&(F(F", 'F'}, + {"0&(F(N", 'F'}, + {"0&(F(S", 'F'}, + {"0&(F(V", 'F'}, + {"0&(N)O", 'F'}, + {"0&(N)U", 'F'}, + {"0&(NO(", 'F'}, + {"0&(NOF", 'F'}, + {"0&(NOS", 'F'}, + {"0&(NOV", 'F'}, + {"0&(S)O", 'F'}, + {"0&(S)U", 'F'}, + {"0&(SO(", 'F'}, + {"0&(SO1", 'F'}, + {"0&(SOF", 'F'}, + {"0&(SON", 'F'}, + {"0&(SOS", 'F'}, + {"0&(SOV", 'F'}, + {"0&(V)O", 'F'}, + {"0&(V)U", 'F'}, + {"0&(VO(", 'F'}, + {"0&(VOF", 'F'}, + {"0&(VOS", 'F'}, + {"0&1O(1", 'F'}, + {"0&1O(F", 'F'}, + {"0&1O(N", 'F'}, + {"0&1O(S", 'F'}, + {"0&1O(V", 'F'}, + {"0&1OF(", 'F'}, + {"0&1OS(", 'F'}, + {"0&1OS1", 'F'}, + {"0&1OSF", 'F'}, + {"0&1OSU", 'F'}, + {"0&1OSV", 'F'}, + {"0&1OV(", 'F'}, + {"0&1OVF", 'F'}, + {"0&1OVO", 'F'}, + {"0&1OVS", 'F'}, + {"0&1OVU", 'F'}, + {"0&1UE(", 'F'}, + {"0&1UE1", 'F'}, + {"0&1UEF", 'F'}, + {"0&1UEK", 'F'}, + {"0&1UEN", 'F'}, + {"0&1UES", 'F'}, + {"0&1UEV", 'F'}, + {"0&F()O", 'F'}, + {"0&F()U", 'F'}, + {"0&F(1)", 'F'}, + {"0&F(1O", 'F'}, + {"0&F(F(", 'F'}, + {"0&F(N)", 'F'}, + {"0&F(NO", 'F'}, + {"0&F(S)", 'F'}, + {"0&F(SO", 'F'}, + {"0&F(V)", 'F'}, + {"0&F(VO", 'F'}, + {"0&NO(1", 'F'}, + {"0&NO(F", 'F'}, + {"0&NO(N", 'F'}, + {"0&NO(S", 'F'}, + {"0&NO(V", 'F'}, + {"0&NOF(", 'F'}, + {"0&NOS(", 'F'}, + {"0&NOS1", 'F'}, + {"0&NOSF", 'F'}, + {"0&NOSU", 'F'}, + {"0&NOSV", 'F'}, + {"0&NOV(", 'F'}, + {"0&NOVF", 'F'}, + {"0&NOVO", 'F'}, + {"0&NOVS", 'F'}, + {"0&NOVU", 'F'}, + {"0&NUE(", 'F'}, + {"0&NUE1", 'F'}, + {"0&NUEF", 'F'}, + {"0&NUEK", 'F'}, + {"0&NUEN", 'F'}, + {"0&NUES", 'F'}, + {"0&NUEV", 'F'}, + {"0&SO(1", 'F'}, + {"0&SO(F", 'F'}, + {"0&SO(N", 'F'}, + {"0&SO(S", 'F'}, + {"0&SO(V", 'F'}, + {"0&SO1(", 'F'}, + {"0&SO1F", 'F'}, + {"0&SO1N", 'F'}, + {"0&SO1S", 'F'}, + {"0&SO1U", 'F'}, + {"0&SO1V", 'F'}, + {"0&SOF(", 'F'}, + {"0&SON(", 'F'}, + {"0&SON1", 'F'}, + {"0&SONF", 'F'}, + {"0&SONU", 'F'}, + {"0&SOS(", 'F'}, + {"0&SOS1", 'F'}, + {"0&SOSF", 'F'}, + {"0&SOSU", 'F'}, + {"0&SOSV", 'F'}, + {"0&SOV(", 'F'}, + {"0&SOVF", 'F'}, + {"0&SOVO", 'F'}, + {"0&SOVS", 'F'}, + {"0&SOVU", 'F'}, + {"0&SUE(", 'F'}, + {"0&SUE1", 'F'}, + {"0&SUEF", 'F'}, + {"0&SUEK", 'F'}, + {"0&SUEN", 'F'}, + {"0&SUES", 'F'}, + {"0&SUEV", 'F'}, + {"0&VO(1", 'F'}, + {"0&VO(F", 'F'}, + {"0&VO(N", 'F'}, + {"0&VO(S", 'F'}, + {"0&VO(V", 'F'}, + {"0&VOF(", 'F'}, + {"0&VOS(", 'F'}, + {"0&VOS1", 'F'}, + {"0&VOSF", 'F'}, + {"0&VOSU", 'F'}, + {"0&VOSV", 'F'}, + {"0&VUE(", 'F'}, + {"0&VUE1", 'F'}, + {"0&VUEF", 'F'}, + {"0&VUEK", 'F'}, + {"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'}, + {"0)UE(S", 'F'}, + {"0)UE(V", 'F'}, + {"0)UE1K", 'F'}, + {"0)UE1O", 'F'}, + {"0)UEF(", 'F'}, + {"0)UEK(", 'F'}, + {"0)UEK1", 'F'}, + {"0)UEKF", 'F'}, + {"0)UEKN", 'F'}, + {"0)UEKS", 'F'}, + {"0)UEKV", 'F'}, + {"0)UENK", 'F'}, + {"0)UENO", 'F'}, + {"0)UESK", 'F'}, + {"0)UESO", 'F'}, + {"0)UEVK", 'F'}, + {"0)UEVO", 'F'}, + {"01&(1&", 'F'}, + {"01&(1)", 'F'}, + {"01&(1,", 'F'}, + {"01&(1O", 'F'}, + {"01&(E(", 'F'}, + {"01&(E1", 'F'}, + {"01&(EF", 'F'}, + {"01&(EK", 'F'}, + {"01&(EN", 'F'}, + {"01&(EO", 'F'}, + {"01&(ES", 'F'}, + {"01&(EV", 'F'}, + {"01&(F(", 'F'}, + {"01&(N&", 'F'}, + {"01&(N)", 'F'}, + {"01&(N,", 'F'}, + {"01&(NO", 'F'}, + {"01&(S&", 'F'}, + {"01&(S)", 'F'}, + {"01&(S,", 'F'}, + {"01&(SO", 'F'}, + {"01&(V&", 'F'}, + {"01&(V)", 'F'}, + {"01&(V,", 'F'}, + {"01&(VO", 'F'}, + {"01&1", 'F'}, + {"01&1&(", 'F'}, + {"01&1&1", 'F'}, + {"01&1&F", 'F'}, + {"01&1&N", 'F'}, + {"01&1&S", 'F'}, + {"01&1&V", 'F'}, + {"01&1)&", 'F'}, + {"01&1)C", 'F'}, + {"01&1)O", 'F'}, + {"01&1)U", 'F'}, + {"01&1;", 'F'}, + {"01&1;C", 'F'}, + {"01&1;E", 'F'}, + {"01&1;T", 'F'}, + {"01&1B(", 'F'}, + {"01&1B1", 'F'}, + {"01&1BF", 'F'}, + {"01&1BN", 'F'}, + {"01&1BS", 'F'}, + {"01&1BV", 'F'}, + {"01&1C", 'F'}, + {"01&1EK", 'F'}, + {"01&1EN", 'F'}, + {"01&1F(", 'F'}, + {"01&1K(", 'F'}, + {"01&1K1", 'F'}, + {"01&1KF", 'F'}, + {"01&1KN", 'F'}, + {"01&1KS", 'F'}, + {"01&1KV", 'F'}, + {"01&1O(", 'F'}, + {"01&1OF", 'F'}, + {"01&1OS", 'F'}, + {"01&1OV", 'F'}, + {"01&1TN", 'F'}, + {"01&1U", 'F'}, + {"01&1U(", 'F'}, + {"01&1U;", 'F'}, + {"01&1UC", 'F'}, + {"01&1UE", 'F'}, + {"01&E(1", 'F'}, + {"01&E(F", 'F'}, + {"01&E(N", 'F'}, + {"01&E(O", 'F'}, + {"01&E(S", 'F'}, + {"01&E(V", 'F'}, + {"01&E1", 'F'}, + {"01&E1;", 'F'}, + {"01&E1C", 'F'}, + {"01&E1K", 'F'}, + {"01&E1O", 'F'}, + {"01&EF(", 'F'}, + {"01&EK(", 'F'}, + {"01&EK1", 'F'}, + {"01&EKF", 'F'}, + {"01&EKN", 'F'}, + {"01&EKS", 'F'}, + {"01&EKU", 'F'}, + {"01&EKV", 'F'}, + {"01&EN", 'F'}, + {"01&EN;", 'F'}, + {"01&ENC", 'F'}, + {"01&ENK", 'F'}, + {"01&ENO", 'F'}, + {"01&ES", 'F'}, + {"01&ES;", 'F'}, + {"01&ESC", 'F'}, + {"01&ESK", 'F'}, + {"01&ESO", 'F'}, + {"01&EUE", 'F'}, + {"01&EV", 'F'}, + {"01&EV;", 'F'}, + {"01&EVC", 'F'}, + {"01&EVK", 'F'}, + {"01&EVO", 'F'}, + {"01&F()", 'F'}, + {"01&F(1", 'F'}, + {"01&F(E", 'F'}, + {"01&F(F", 'F'}, + {"01&F(N", 'F'}, + {"01&F(S", 'F'}, + {"01&F(V", 'F'}, + {"01&K&(", 'F'}, + {"01&K&1", 'F'}, + {"01&K&F", 'F'}, + {"01&K&N", 'F'}, + {"01&K&S", 'F'}, + {"01&K&V", 'F'}, + {"01&K(1", 'F'}, + {"01&K(F", 'F'}, + {"01&K(N", 'F'}, + {"01&K(S", 'F'}, + {"01&K(V", 'F'}, + {"01&K1O", 'F'}, + {"01&KC", 'F'}, + {"01&KF(", 'F'}, + {"01&KNK", 'F'}, + {"01&KO(", 'F'}, + {"01&KO1", 'F'}, + {"01&KOF", 'F'}, + {"01&KOK", 'F'}, + {"01&KON", 'F'}, + {"01&KOS", 'F'}, + {"01&KOV", 'F'}, + {"01&KSO", 'F'}, + {"01&KVO", 'F'}, + {"01&N&(", 'F'}, + {"01&N&1", 'F'}, + {"01&N&F", 'F'}, + {"01&N&N", 'F'}, + {"01&N&S", 'F'}, + {"01&N&V", 'F'}, + {"01&N)&", 'F'}, + {"01&N)C", 'F'}, + {"01&N)O", 'F'}, + {"01&N)U", 'F'}, + {"01&N;", 'F'}, + {"01&N;C", 'F'}, + {"01&N;E", 'F'}, + {"01&N;T", 'F'}, + {"01&NB(", 'F'}, + {"01&NB1", 'F'}, + {"01&NBF", 'F'}, + {"01&NBN", 'F'}, + {"01&NBS", 'F'}, + {"01&NBV", 'F'}, + {"01&NC", 'F'}, + {"01&NEN", 'F'}, + {"01&NF(", 'F'}, + {"01&NK(", 'F'}, + {"01&NK1", 'F'}, + {"01&NKF", 'F'}, + {"01&NKN", 'F'}, + {"01&NKS", 'F'}, + {"01&NKV", 'F'}, + {"01&NO(", 'F'}, + {"01&NOF", 'F'}, + {"01&NOS", 'F'}, + {"01&NOV", 'F'}, + {"01&NTN", 'F'}, + {"01&NU", 'F'}, + {"01&NU(", 'F'}, + {"01&NU;", 'F'}, + {"01&NUC", 'F'}, + {"01&NUE", 'F'}, + {"01&S", 'F'}, + {"01&S&(", 'F'}, + {"01&S&1", 'F'}, + {"01&S&F", 'F'}, + {"01&S&N", 'F'}, + {"01&S&S", 'F'}, + {"01&S&V", 'F'}, + {"01&S)&", 'F'}, + {"01&S)C", 'F'}, + {"01&S)O", 'F'}, + {"01&S)U", 'F'}, + {"01&S1", 'F'}, + {"01&S1;", 'F'}, + {"01&S1C", 'F'}, + {"01&S;", 'F'}, + {"01&S;C", 'F'}, + {"01&S;E", 'F'}, + {"01&S;T", 'F'}, + {"01&SB(", 'F'}, + {"01&SB1", 'F'}, + {"01&SBF", 'F'}, + {"01&SBN", 'F'}, + {"01&SBS", 'F'}, + {"01&SBV", 'F'}, + {"01&SC", 'F'}, + {"01&SEK", 'F'}, + {"01&SEN", 'F'}, + {"01&SF(", 'F'}, + {"01&SK(", 'F'}, + {"01&SK1", 'F'}, + {"01&SKF", 'F'}, + {"01&SKN", 'F'}, + {"01&SKS", 'F'}, + {"01&SKV", 'F'}, + {"01&SO(", 'F'}, + {"01&SO1", 'F'}, + {"01&SOF", 'F'}, + {"01&SON", 'F'}, + {"01&SOS", 'F'}, + {"01&SOV", 'F'}, + {"01&STN", 'F'}, + {"01&SU", 'F'}, + {"01&SU(", 'F'}, + {"01&SU;", 'F'}, + {"01&SUC", 'F'}, + {"01&SUE", 'F'}, + {"01&SV", 'F'}, + {"01&SV;", 'F'}, + {"01&SVC", 'F'}, + {"01&SVO", 'F'}, + {"01&V", 'F'}, + {"01&V&(", 'F'}, + {"01&V&1", 'F'}, + {"01&V&F", 'F'}, + {"01&V&N", 'F'}, + {"01&V&S", 'F'}, + {"01&V&V", 'F'}, + {"01&V)&", 'F'}, + {"01&V)C", 'F'}, + {"01&V)O", 'F'}, + {"01&V)U", 'F'}, + {"01&V;", 'F'}, + {"01&V;C", 'F'}, + {"01&V;E", 'F'}, + {"01&V;T", 'F'}, + {"01&VB(", 'F'}, + {"01&VB1", 'F'}, + {"01&VBF", 'F'}, + {"01&VBN", 'F'}, + {"01&VBS", 'F'}, + {"01&VBV", 'F'}, + {"01&VC", 'F'}, + {"01&VEK", 'F'}, + {"01&VEN", 'F'}, + {"01&VF(", 'F'}, + {"01&VK(", 'F'}, + {"01&VK1", 'F'}, + {"01&VKF", 'F'}, + {"01&VKN", 'F'}, + {"01&VKS", 'F'}, + {"01&VKV", 'F'}, + {"01&VO(", 'F'}, + {"01&VOF", 'F'}, + {"01&VOS", 'F'}, + {"01&VS", 'F'}, + {"01&VS;", 'F'}, + {"01&VSC", 'F'}, + {"01&VSO", 'F'}, + {"01&VTN", 'F'}, + {"01&VU", 'F'}, + {"01&VU(", 'F'}, + {"01&VU;", 'F'}, + {"01&VUC", 'F'}, + {"01&VUE", 'F'}, + {"01(EF(", 'F'}, + {"01(EKF", 'F'}, + {"01(EKN", 'F'}, + {"01(ENK", 'F'}, + {"01(U(E", 'F'}, + {"01)&(1", 'F'}, + {"01)&(E", 'F'}, + {"01)&(F", 'F'}, + {"01)&(N", 'F'}, + {"01)&(S", 'F'}, + {"01)&(V", 'F'}, + {"01)&1", 'F'}, + {"01)&1&", 'F'}, + {"01)&1)", 'F'}, + {"01)&1;", 'F'}, + {"01)&1B", 'F'}, + {"01)&1C", 'F'}, + {"01)&1F", 'F'}, + {"01)&1O", 'F'}, + {"01)&1U", 'F'}, + {"01)&F(", 'F'}, + {"01)&N", 'F'}, + {"01)&N&", 'F'}, + {"01)&N)", 'F'}, + {"01)&N;", 'F'}, + {"01)&NB", 'F'}, + {"01)&NC", 'F'}, + {"01)&NF", 'F'}, + {"01)&NO", 'F'}, + {"01)&NU", 'F'}, + {"01)&S", 'F'}, + {"01)&S&", 'F'}, + {"01)&S)", 'F'}, + {"01)&S;", 'F'}, + {"01)&SB", 'F'}, + {"01)&SC", 'F'}, + {"01)&SF", 'F'}, + {"01)&SO", 'F'}, + {"01)&SU", 'F'}, + {"01)&V", 'F'}, + {"01)&V&", 'F'}, + {"01)&V)", 'F'}, + {"01)&V;", 'F'}, + {"01)&VB", 'F'}, + {"01)&VC", 'F'}, + {"01)&VF", 'F'}, + {"01)&VO", 'F'}, + {"01)&VU", 'F'}, + {"01),(1", 'F'}, + {"01),(F", 'F'}, + {"01),(N", 'F'}, + {"01),(S", 'F'}, + {"01),(V", 'F'}, + {"01);E(", 'F'}, + {"01);E1", 'F'}, + {"01);EF", 'F'}, + {"01);EK", 'F'}, + {"01);EN", 'F'}, + {"01);EO", 'F'}, + {"01);ES", 'F'}, + {"01);EV", 'F'}, + {"01);T(", 'F'}, + {"01);T1", 'F'}, + {"01);TF", 'F'}, + {"01);TK", 'F'}, + {"01);TN", 'F'}, + {"01);TO", 'F'}, + {"01);TS", 'F'}, + {"01);TV", 'F'}, + {"01)B(1", 'F'}, + {"01)B(F", 'F'}, + {"01)B(N", 'F'}, + {"01)B(S", 'F'}, + {"01)B(V", 'F'}, + {"01)B1", 'F'}, + {"01)B1&", 'F'}, + {"01)B1;", 'F'}, + {"01)B1C", 'F'}, + {"01)B1K", 'F'}, + {"01)B1N", 'F'}, + {"01)B1O", 'F'}, + {"01)B1U", 'F'}, + {"01)BF(", 'F'}, + {"01)BN", 'F'}, + {"01)BN&", 'F'}, + {"01)BN;", 'F'}, + {"01)BNC", 'F'}, + {"01)BNK", 'F'}, + {"01)BNO", 'F'}, + {"01)BNU", 'F'}, + {"01)BS", 'F'}, + {"01)BS&", 'F'}, + {"01)BS;", 'F'}, + {"01)BSC", 'F'}, + {"01)BSK", 'F'}, + {"01)BSO", 'F'}, + {"01)BSU", 'F'}, + {"01)BV", 'F'}, + {"01)BV&", 'F'}, + {"01)BV;", 'F'}, + {"01)BVC", 'F'}, + {"01)BVK", 'F'}, + {"01)BVO", 'F'}, + {"01)BVU", 'F'}, + {"01)C", 'F'}, + {"01)E(1", 'F'}, + {"01)E(F", 'F'}, + {"01)E(N", 'F'}, + {"01)E(S", 'F'}, + {"01)E(V", 'F'}, + {"01)E1C", 'F'}, + {"01)E1O", 'F'}, + {"01)EF(", 'F'}, + {"01)EK(", 'F'}, + {"01)EK1", 'F'}, + {"01)EKF", 'F'}, + {"01)EKN", 'F'}, + {"01)EKS", 'F'}, + {"01)EKV", 'F'}, + {"01)ENC", 'F'}, + {"01)ENO", 'F'}, + {"01)ESC", 'F'}, + {"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'}, + {"01)K(S", 'F'}, + {"01)K(V", 'F'}, + {"01)K1&", 'F'}, + {"01)K1;", 'F'}, + {"01)K1B", 'F'}, + {"01)K1E", 'F'}, + {"01)K1O", 'F'}, + {"01)K1U", 'F'}, + {"01)KB(", 'F'}, + {"01)KB1", 'F'}, + {"01)KBF", 'F'}, + {"01)KBN", 'F'}, + {"01)KBS", 'F'}, + {"01)KBV", 'F'}, + {"01)KF(", 'F'}, + {"01)KN&", 'F'}, + {"01)KN;", 'F'}, + {"01)KNB", 'F'}, + {"01)KNC", 'F'}, + {"01)KNE", 'F'}, + {"01)KNK", 'F'}, + {"01)KNU", 'F'}, + {"01)KS&", 'F'}, + {"01)KS;", 'F'}, + {"01)KSB", 'F'}, + {"01)KSE", 'F'}, + {"01)KSO", 'F'}, + {"01)KSU", 'F'}, + {"01)KUE", 'F'}, + {"01)KV&", 'F'}, + {"01)KV;", 'F'}, + {"01)KVB", 'F'}, + {"01)KVE", 'F'}, + {"01)KVO", 'F'}, + {"01)KVU", 'F'}, + {"01)O(1", 'F'}, + {"01)O(E", 'F'}, + {"01)O(F", 'F'}, + {"01)O(N", 'F'}, + {"01)O(S", 'F'}, + {"01)O(V", 'F'}, + {"01)O1", 'F'}, + {"01)O1&", 'F'}, + {"01)O1)", 'F'}, + {"01)O1;", 'F'}, + {"01)O1B", 'F'}, + {"01)O1C", 'F'}, + {"01)O1K", 'F'}, + {"01)O1U", 'F'}, + {"01)OF(", 'F'}, + {"01)ON&", 'F'}, + {"01)ON)", 'F'}, + {"01)ON;", 'F'}, + {"01)ONB", 'F'}, + {"01)ONC", 'F'}, + {"01)ONK", 'F'}, + {"01)ONU", 'F'}, + {"01)OS", 'F'}, + {"01)OS&", 'F'}, + {"01)OS)", 'F'}, + {"01)OS;", 'F'}, + {"01)OSB", 'F'}, + {"01)OSC", 'F'}, + {"01)OSK", 'F'}, + {"01)OSU", 'F'}, + {"01)OV", 'F'}, + {"01)OV&", 'F'}, + {"01)OV)", 'F'}, + {"01)OV;", 'F'}, + {"01)OVB", 'F'}, + {"01)OVC", 'F'}, + {"01)OVK", 'F'}, + {"01)OVO", 'F'}, + {"01)OVU", 'F'}, + {"01)U(E", 'F'}, + {"01)UE(", 'F'}, + {"01)UE1", 'F'}, + {"01)UEF", 'F'}, + {"01)UEK", 'F'}, + {"01)UEN", 'F'}, + {"01)UES", 'F'}, + {"01)UEV", 'F'}, + {"01,(1)", 'F'}, + {"01,(1O", 'F'}, + {"01,(E(", 'F'}, + {"01,(E1", 'F'}, + {"01,(EF", 'F'}, + {"01,(EK", 'F'}, + {"01,(EN", 'F'}, + {"01,(ES", 'F'}, + {"01,(EV", 'F'}, + {"01,(F(", 'F'}, + {"01,(N)", 'F'}, + {"01,(NO", 'F'}, + {"01,(S)", 'F'}, + {"01,(SO", 'F'}, + {"01,(V)", 'F'}, + {"01,(VO", 'F'}, + {"01,F()", 'F'}, + {"01,F(1", 'F'}, + {"01,F(F", 'F'}, + {"01,F(N", 'F'}, + {"01,F(S", 'F'}, + {"01,F(V", 'F'}, + {"01;E(1", 'F'}, + {"01;E(E", 'F'}, + {"01;E(F", 'F'}, + {"01;E(N", 'F'}, + {"01;E(S", 'F'}, + {"01;E(V", 'F'}, + {"01;E1,", 'F'}, + {"01;E1;", 'F'}, + {"01;E1C", 'F'}, + {"01;E1K", 'F'}, + {"01;E1O", 'F'}, + {"01;E1T", 'F'}, + {"01;EF(", 'F'}, + {"01;EK(", 'F'}, + {"01;EK1", 'F'}, + {"01;EKF", 'F'}, + {"01;EKN", 'F'}, + {"01;EKO", 'F'}, + {"01;EKS", 'F'}, + {"01;EKV", 'F'}, + {"01;EN,", 'F'}, + {"01;EN;", 'F'}, + {"01;ENC", 'F'}, + {"01;ENE", 'F'}, + {"01;ENK", 'F'}, + {"01;ENO", 'F'}, + {"01;ENT", 'F'}, + {"01;ES,", 'F'}, + {"01;ES;", 'F'}, + {"01;ESC", 'F'}, + {"01;ESK", 'F'}, + {"01;ESO", 'F'}, + {"01;EST", 'F'}, + {"01;EV,", 'F'}, + {"01;EV;", 'F'}, + {"01;EVC", 'F'}, + {"01;EVK", 'F'}, + {"01;EVO", 'F'}, + {"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'}, + {"01;T1F", 'F'}, + {"01;T1K", 'F'}, + {"01;T1O", 'F'}, + {"01;T1T", 'F'}, + {"01;T;", 'F'}, + {"01;T;C", 'F'}, + {"01;TF(", 'F'}, + {"01;TK(", 'F'}, + {"01;TK1", 'F'}, + {"01;TKF", 'F'}, + {"01;TKK", 'F'}, + {"01;TKN", 'F'}, + {"01;TKO", 'F'}, + {"01;TKS", 'F'}, + {"01;TKV", 'F'}, + {"01;TN(", 'F'}, + {"01;TN,", 'F'}, + {"01;TN1", 'F'}, + {"01;TN;", 'F'}, + {"01;TNC", 'F'}, + {"01;TNF", 'F'}, + {"01;TNK", 'F'}, + {"01;TNN", 'F'}, + {"01;TNO", 'F'}, + {"01;TNS", 'F'}, + {"01;TNT", 'F'}, + {"01;TNV", 'F'}, + {"01;TO(", 'F'}, + {"01;TS(", 'F'}, + {"01;TS,", 'F'}, + {"01;TS;", 'F'}, + {"01;TSC", 'F'}, + {"01;TSF", 'F'}, + {"01;TSK", 'F'}, + {"01;TSO", 'F'}, + {"01;TST", 'F'}, + {"01;TTN", 'F'}, + {"01;TV(", 'F'}, + {"01;TV,", 'F'}, + {"01;TV;", 'F'}, + {"01;TVC", 'F'}, + {"01;TVF", 'F'}, + {"01;TVK", 'F'}, + {"01;TVO", 'F'}, + {"01;TVT", 'F'}, + {"01A(F(", 'F'}, + {"01A(N)", 'F'}, + {"01A(NO", 'F'}, + {"01A(S)", 'F'}, + {"01A(SO", 'F'}, + {"01A(V)", 'F'}, + {"01A(VO", 'F'}, + {"01AF()", 'F'}, + {"01AF(1", 'F'}, + {"01AF(F", 'F'}, + {"01AF(N", 'F'}, + {"01AF(S", 'F'}, + {"01AF(V", 'F'}, + {"01ASO(", 'F'}, + {"01ASO1", 'F'}, + {"01ASOF", 'F'}, + {"01ASON", 'F'}, + {"01ASOS", 'F'}, + {"01ASOV", 'F'}, + {"01ASUE", 'F'}, + {"01ATO(", 'F'}, + {"01ATO1", 'F'}, + {"01ATOF", 'F'}, + {"01ATON", 'F'}, + {"01ATOS", 'F'}, + {"01ATOV", 'F'}, + {"01ATUE", 'F'}, + {"01AVO(", 'F'}, + {"01AVOF", 'F'}, + {"01AVOS", 'F'}, + {"01AVUE", 'F'}, + {"01B(1)", 'F'}, + {"01B(1O", 'F'}, + {"01B(F(", 'F'}, + {"01B(NO", 'F'}, + {"01B(S)", 'F'}, + {"01B(SO", 'F'}, + {"01B(V)", 'F'}, + {"01B(VO", 'F'}, + {"01B1", 'F'}, + {"01B1&(", 'F'}, + {"01B1&1", 'F'}, + {"01B1&F", 'F'}, + {"01B1&N", 'F'}, + {"01B1&S", 'F'}, + {"01B1&V", 'F'}, + {"01B1,(", 'F'}, + {"01B1,F", 'F'}, + {"01B1;", 'F'}, + {"01B1;C", 'F'}, + {"01B1B(", 'F'}, + {"01B1B1", 'F'}, + {"01B1BF", 'F'}, + {"01B1BN", 'F'}, + {"01B1BS", 'F'}, + {"01B1BV", 'F'}, + {"01B1C", 'F'}, + {"01B1K(", 'F'}, + {"01B1K1", 'F'}, + {"01B1KF", 'F'}, + {"01B1KN", 'F'}, + {"01B1KS", 'F'}, + {"01B1KV", 'F'}, + {"01B1O(", 'F'}, + {"01B1OF", 'F'}, + {"01B1OS", 'F'}, + {"01B1OV", 'F'}, + {"01B1U(", 'F'}, + {"01B1UE", 'F'}, + {"01BE(1", 'F'}, + {"01BE(F", 'F'}, + {"01BE(N", 'F'}, + {"01BE(S", 'F'}, + {"01BE(V", 'F'}, + {"01BEK(", 'F'}, + {"01BF()", 'F'}, + {"01BF(1", 'F'}, + {"01BF(F", 'F'}, + {"01BF(N", 'F'}, + {"01BF(S", 'F'}, + {"01BF(V", 'F'}, + {"01BN", 'F'}, + {"01BN&(", 'F'}, + {"01BN&1", 'F'}, + {"01BN&F", 'F'}, + {"01BN&N", 'F'}, + {"01BN&S", 'F'}, + {"01BN&V", 'F'}, + {"01BN,(", 'F'}, + {"01BN,F", 'F'}, + {"01BN;", 'F'}, + {"01BN;C", 'F'}, + {"01BNB(", 'F'}, + {"01BNB1", 'F'}, + {"01BNBF", 'F'}, + {"01BNBN", 'F'}, + {"01BNBS", 'F'}, + {"01BNBV", 'F'}, + {"01BNC", 'F'}, + {"01BNK(", 'F'}, + {"01BNK1", 'F'}, + {"01BNKF", 'F'}, + {"01BNKN", 'F'}, + {"01BNKS", 'F'}, + {"01BNKV", 'F'}, + {"01BNO(", 'F'}, + {"01BNOF", 'F'}, + {"01BNOS", 'F'}, + {"01BNOV", 'F'}, + {"01BNU(", 'F'}, + {"01BNUE", 'F'}, + {"01BS", 'F'}, + {"01BS&(", 'F'}, + {"01BS&1", 'F'}, + {"01BS&F", 'F'}, + {"01BS&N", 'F'}, + {"01BS&S", 'F'}, + {"01BS&V", 'F'}, + {"01BS,(", 'F'}, + {"01BS,F", 'F'}, + {"01BS;", 'F'}, + {"01BS;C", 'F'}, + {"01BSB(", 'F'}, + {"01BSB1", 'F'}, + {"01BSBF", 'F'}, + {"01BSBN", 'F'}, + {"01BSBS", 'F'}, + {"01BSBV", 'F'}, + {"01BSC", 'F'}, + {"01BSK(", 'F'}, + {"01BSK1", 'F'}, + {"01BSKF", 'F'}, + {"01BSKN", 'F'}, + {"01BSKS", 'F'}, + {"01BSKV", 'F'}, + {"01BSO(", 'F'}, + {"01BSO1", 'F'}, + {"01BSOF", 'F'}, + {"01BSON", 'F'}, + {"01BSOS", 'F'}, + {"01BSOV", 'F'}, + {"01BSU(", 'F'}, + {"01BSUE", 'F'}, + {"01BV", 'F'}, + {"01BV&(", 'F'}, + {"01BV&1", 'F'}, + {"01BV&F", 'F'}, + {"01BV&N", 'F'}, + {"01BV&S", 'F'}, + {"01BV&V", 'F'}, + {"01BV,(", 'F'}, + {"01BV,F", 'F'}, + {"01BV;", 'F'}, + {"01BV;C", 'F'}, + {"01BVB(", 'F'}, + {"01BVB1", 'F'}, + {"01BVBF", 'F'}, + {"01BVBN", 'F'}, + {"01BVBS", 'F'}, + {"01BVBV", 'F'}, + {"01BVC", 'F'}, + {"01BVK(", 'F'}, + {"01BVK1", 'F'}, + {"01BVKF", 'F'}, + {"01BVKN", 'F'}, + {"01BVKS", 'F'}, + {"01BVKV", 'F'}, + {"01BVO(", 'F'}, + {"01BVOF", 'F'}, + {"01BVOS", 'F'}, + {"01BVU(", 'F'}, + {"01BVUE", 'F'}, + {"01C", 'F'}, + {"01E(1)", 'F'}, + {"01E(1O", 'F'}, + {"01E(F(", 'F'}, + {"01E(N)", 'F'}, + {"01E(NO", 'F'}, + {"01E(S)", 'F'}, + {"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'}, + {"01EF(F", 'F'}, + {"01EF(N", 'F'}, + {"01EF(S", 'F'}, + {"01EF(V", 'F'}, + {"01EK(1", 'F'}, + {"01EK(E", 'F'}, + {"01EK(F", 'F'}, + {"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'}, + {"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'}, + {"01ESOF", 'F'}, + {"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'}, + {"01EU(N", 'F'}, + {"01EU(S", 'F'}, + {"01EU(V", 'F'}, + {"01EU1,", 'F'}, + {"01EU1C", 'F'}, + {"01EU1O", 'F'}, + {"01EUEF", 'F'}, + {"01EUEK", 'F'}, + {"01EUF(", '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'}, + {"01F()K", 'F'}, + {"01F()N", 'F'}, + {"01F()O", 'F'}, + {"01F()S", 'F'}, + {"01F()U", 'F'}, + {"01F()V", 'F'}, + {"01F(1)", 'F'}, + {"01F(1N", 'F'}, + {"01F(1O", 'F'}, + {"01F(E(", 'F'}, + {"01F(E1", 'F'}, + {"01F(EF", 'F'}, + {"01F(EK", 'F'}, + {"01F(EN", 'F'}, + {"01F(ES", 'F'}, + {"01F(EV", 'F'}, + {"01F(F(", 'F'}, + {"01F(N)", 'F'}, + {"01F(N,", 'F'}, + {"01F(NO", 'F'}, + {"01F(S)", 'F'}, + {"01F(SO", 'F'}, + {"01F(V)", 'F'}, + {"01F(VO", 'F'}, + {"01K(1O", 'F'}, + {"01K(F(", 'F'}, + {"01K(N)", 'F'}, + {"01K(NO", 'F'}, + {"01K(S)", 'F'}, + {"01K(SO", 'F'}, + {"01K(V)", 'F'}, + {"01K(VO", 'F'}, + {"01K)&(", 'F'}, + {"01K)&1", 'F'}, + {"01K)&F", 'F'}, + {"01K)&N", 'F'}, + {"01K)&S", 'F'}, + {"01K)&V", 'F'}, + {"01K);E", 'F'}, + {"01K);T", 'F'}, + {"01K)B(", 'F'}, + {"01K)B1", 'F'}, + {"01K)BF", 'F'}, + {"01K)BN", 'F'}, + {"01K)BS", 'F'}, + {"01K)BV", 'F'}, + {"01K)E(", 'F'}, + {"01K)E1", 'F'}, + {"01K)EF", 'F'}, + {"01K)EK", 'F'}, + {"01K)EN", 'F'}, + {"01K)ES", 'F'}, + {"01K)EV", 'F'}, + {"01K)F(", 'F'}, + {"01K)O(", 'F'}, + {"01K)OF", 'F'}, + {"01K)UE", 'F'}, + {"01K1", 'F'}, + {"01K1&(", 'F'}, + {"01K1&1", 'F'}, + {"01K1&F", 'F'}, + {"01K1&N", 'F'}, + {"01K1&S", 'F'}, + {"01K1&V", 'F'}, + {"01K1;", 'F'}, + {"01K1;C", 'F'}, + {"01K1;E", 'F'}, + {"01K1;T", 'F'}, + {"01K1B(", 'F'}, + {"01K1B1", 'F'}, + {"01K1BF", 'F'}, + {"01K1BN", 'F'}, + {"01K1BS", 'F'}, + {"01K1BV", 'F'}, + {"01K1C", 'F'}, + {"01K1E(", 'F'}, + {"01K1E1", 'F'}, + {"01K1EF", 'F'}, + {"01K1EK", 'F'}, + {"01K1EN", 'F'}, + {"01K1ES", 'F'}, + {"01K1EV", 'F'}, + {"01K1O(", 'F'}, + {"01K1OF", 'F'}, + {"01K1OS", 'F'}, + {"01K1OV", 'F'}, + {"01K1U(", 'F'}, + {"01K1UE", 'F'}, + {"01KF()", 'F'}, + {"01KF(1", 'F'}, + {"01KF(F", 'F'}, + {"01KF(N", 'F'}, + {"01KF(S", 'F'}, + {"01KF(V", 'F'}, + {"01KN", 'F'}, + {"01KN&(", 'F'}, + {"01KN&1", 'F'}, + {"01KN&F", 'F'}, + {"01KN&N", 'F'}, + {"01KN&S", 'F'}, + {"01KN&V", 'F'}, + {"01KN;", 'F'}, + {"01KN;C", 'F'}, + {"01KN;E", 'F'}, + {"01KN;T", 'F'}, + {"01KNB(", 'F'}, + {"01KNB1", 'F'}, + {"01KNBF", 'F'}, + {"01KNBN", 'F'}, + {"01KNBS", 'F'}, + {"01KNBV", 'F'}, + {"01KNC", 'F'}, + {"01KNE(", 'F'}, + {"01KNE1", 'F'}, + {"01KNEF", 'F'}, + {"01KNEN", 'F'}, + {"01KNES", 'F'}, + {"01KNEV", 'F'}, + {"01KNU(", 'F'}, + {"01KNUE", 'F'}, + {"01KS", 'F'}, + {"01KS&(", 'F'}, + {"01KS&1", 'F'}, + {"01KS&F", 'F'}, + {"01KS&N", 'F'}, + {"01KS&S", 'F'}, + {"01KS&V", 'F'}, + {"01KS;", 'F'}, + {"01KS;C", 'F'}, + {"01KS;E", 'F'}, + {"01KS;T", 'F'}, + {"01KSB(", 'F'}, + {"01KSB1", 'F'}, + {"01KSBF", 'F'}, + {"01KSBN", 'F'}, + {"01KSBS", 'F'}, + {"01KSBV", 'F'}, + {"01KSC", 'F'}, + {"01KSE(", 'F'}, + {"01KSE1", 'F'}, + {"01KSEF", 'F'}, + {"01KSEK", 'F'}, + {"01KSEN", 'F'}, + {"01KSES", 'F'}, + {"01KSEV", 'F'}, + {"01KSO(", 'F'}, + {"01KSO1", 'F'}, + {"01KSOF", 'F'}, + {"01KSON", 'F'}, + {"01KSOS", 'F'}, + {"01KSOV", 'F'}, + {"01KSU(", 'F'}, + {"01KSUE", 'F'}, + {"01KUE(", 'F'}, + {"01KUE1", 'F'}, + {"01KUEF", 'F'}, + {"01KUEK", 'F'}, + {"01KUEN", 'F'}, + {"01KUES", 'F'}, + {"01KUEV", 'F'}, + {"01KV", 'F'}, + {"01KV&(", 'F'}, + {"01KV&1", 'F'}, + {"01KV&F", 'F'}, + {"01KV&N", 'F'}, + {"01KV&S", 'F'}, + {"01KV&V", 'F'}, + {"01KV;", 'F'}, + {"01KV;C", 'F'}, + {"01KV;E", 'F'}, + {"01KV;T", 'F'}, + {"01KVB(", 'F'}, + {"01KVB1", 'F'}, + {"01KVBF", 'F'}, + {"01KVBN", 'F'}, + {"01KVBS", 'F'}, + {"01KVBV", 'F'}, + {"01KVC", 'F'}, + {"01KVE(", 'F'}, + {"01KVE1", 'F'}, + {"01KVEF", 'F'}, + {"01KVEK", 'F'}, + {"01KVEN", 'F'}, + {"01KVES", 'F'}, + {"01KVEV", 'F'}, + {"01KVO(", 'F'}, + {"01KVOF", 'F'}, + {"01KVOS", 'F'}, + {"01KVU(", 'F'}, + {"01KVUE", 'F'}, + {"01N&F(", 'F'}, + {"01N(1O", 'F'}, + {"01N(F(", 'F'}, + {"01N(S)", 'F'}, + {"01N(SO", 'F'}, + {"01N(V)", 'F'}, + {"01N(VO", 'F'}, + {"01N)UE", 'F'}, + {"01N,F(", 'F'}, + {"01NE(1", 'F'}, + {"01NE(F", 'F'}, + {"01NE(N", 'F'}, + {"01NE(S", 'F'}, + {"01NE(V", 'F'}, + {"01NE1C", 'F'}, + {"01NE1O", 'F'}, + {"01NEF(", 'F'}, + {"01NENC", 'F'}, + {"01NENO", 'F'}, + {"01NESC", 'F'}, + {"01NESO", 'F'}, + {"01NEVC", 'F'}, + {"01NEVO", 'F'}, + {"01NU(E", 'F'}, + {"01NUE", 'F'}, + {"01NUE(", 'F'}, + {"01NUE1", 'F'}, + {"01NUE;", 'F'}, + {"01NUEC", 'F'}, + {"01NUEF", 'F'}, + {"01NUEK", 'F'}, + {"01NUEN", 'F'}, + {"01NUES", 'F'}, + {"01NUEV", 'F'}, + {"01O(1&", 'F'}, + {"01O(1)", 'F'}, + {"01O(1,", 'F'}, + {"01O(1O", 'F'}, + {"01O(E(", 'F'}, + {"01O(E1", 'F'}, + {"01O(EE", 'F'}, + {"01O(EF", 'F'}, + {"01O(EK", 'F'}, + {"01O(EN", 'F'}, + {"01O(EO", 'F'}, + {"01O(ES", 'F'}, + {"01O(EV", 'F'}, + {"01O(F(", 'F'}, + {"01O(N&", 'F'}, + {"01O(N)", 'F'}, + {"01O(N,", 'F'}, + {"01O(NO", 'F'}, + {"01O(S&", 'F'}, + {"01O(S)", 'F'}, + {"01O(S,", 'F'}, + {"01O(SO", 'F'}, + {"01O(V&", 'F'}, + {"01O(V)", 'F'}, + {"01O(V,", 'F'}, + {"01O(VO", 'F'}, + {"01OF()", 'F'}, + {"01OF(1", 'F'}, + {"01OF(E", 'F'}, + {"01OF(F", 'F'}, + {"01OF(N", 'F'}, + {"01OF(S", 'F'}, + {"01OF(V", 'F'}, + {"01OK&(", 'F'}, + {"01OK&1", 'F'}, + {"01OK&F", 'F'}, + {"01OK&N", 'F'}, + {"01OK&S", 'F'}, + {"01OK&V", 'F'}, + {"01OK(1", 'F'}, + {"01OK(F", 'F'}, + {"01OK(N", 'F'}, + {"01OK(S", 'F'}, + {"01OK(V", 'F'}, + {"01OK1C", 'F'}, + {"01OK1O", 'F'}, + {"01OKF(", 'F'}, + {"01OKNC", 'F'}, + {"01OKO(", 'F'}, + {"01OKO1", 'F'}, + {"01OKOF", 'F'}, + {"01OKON", 'F'}, + {"01OKOS", 'F'}, + {"01OKOV", 'F'}, + {"01OKSC", 'F'}, + {"01OKSO", 'F'}, + {"01OKVC", 'F'}, + {"01OKVO", 'F'}, + {"01ONSU", 'F'}, + {"01OS&(", 'F'}, + {"01OS&1", 'F'}, + {"01OS&E", 'F'}, + {"01OS&F", 'F'}, + {"01OS&K", 'F'}, + {"01OS&N", 'F'}, + {"01OS&S", 'F'}, + {"01OS&U", 'F'}, + {"01OS&V", 'F'}, + {"01OS(E", 'F'}, + {"01OS(U", 'F'}, + {"01OS)&", 'F'}, + {"01OS),", 'F'}, + {"01OS);", 'F'}, + {"01OS)B", 'F'}, + {"01OS)C", 'F'}, + {"01OS)E", 'F'}, + {"01OS)F", 'F'}, + {"01OS)K", 'F'}, + {"01OS)O", 'F'}, + {"01OS)U", 'F'}, + {"01OS,(", 'F'}, + {"01OS,F", 'F'}, + {"01OS1(", 'F'}, + {"01OS1F", 'F'}, + {"01OS1N", 'F'}, + {"01OS1S", 'F'}, + {"01OS1U", 'F'}, + {"01OS1V", 'F'}, + {"01OS;", 'F'}, + {"01OS;C", 'F'}, + {"01OS;E", 'F'}, + {"01OS;N", 'F'}, + {"01OS;T", 'F'}, + {"01OSA(", 'F'}, + {"01OSAF", 'F'}, + {"01OSAS", 'F'}, + {"01OSAT", 'F'}, + {"01OSAV", 'F'}, + {"01OSB(", 'F'}, + {"01OSB1", 'F'}, + {"01OSBE", 'F'}, + {"01OSBF", 'F'}, + {"01OSBN", 'F'}, + {"01OSBS", 'F'}, + {"01OSBV", 'F'}, + {"01OSC", 'F'}, + {"01OSE(", 'F'}, + {"01OSE1", 'F'}, + {"01OSEF", 'F'}, + {"01OSEK", 'F'}, + {"01OSEN", 'F'}, + {"01OSEO", 'F'}, + {"01OSES", 'F'}, + {"01OSEU", 'F'}, + {"01OSEV", 'F'}, + {"01OSF(", 'F'}, + {"01OSK(", 'F'}, + {"01OSK)", 'F'}, + {"01OSK1", 'F'}, + {"01OSKB", 'F'}, + {"01OSKF", 'F'}, + {"01OSKN", 'F'}, + {"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'}, + {"01OSU;", 'F'}, + {"01OSUC", 'F'}, + {"01OSUE", 'F'}, + {"01OSUF", 'F'}, + {"01OSUK", 'F'}, + {"01OSUO", 'F'}, + {"01OSUS", 'F'}, + {"01OSUT", 'F'}, + {"01OSUV", 'F'}, + {"01OSV(", 'F'}, + {"01OSVF", 'F'}, + {"01OSVO", 'F'}, + {"01OSVS", 'F'}, + {"01OSVU", 'F'}, + {"01OU(E", 'F'}, + {"01OUEK", 'F'}, + {"01OUEN", 'F'}, + {"01OV", 'F'}, + {"01OV&(", 'F'}, + {"01OV&1", 'F'}, + {"01OV&E", 'F'}, + {"01OV&F", 'F'}, + {"01OV&K", 'F'}, + {"01OV&N", 'F'}, + {"01OV&S", 'F'}, + {"01OV&U", 'F'}, + {"01OV&V", 'F'}, + {"01OV(E", 'F'}, + {"01OV(U", 'F'}, + {"01OV)&", 'F'}, + {"01OV),", 'F'}, + {"01OV);", 'F'}, + {"01OV)B", 'F'}, + {"01OV)C", 'F'}, + {"01OV)E", 'F'}, + {"01OV)F", 'F'}, + {"01OV)K", 'F'}, + {"01OV)O", 'F'}, + {"01OV)U", 'F'}, + {"01OV,(", 'F'}, + {"01OV,F", 'F'}, + {"01OV;", 'F'}, + {"01OV;C", 'F'}, + {"01OV;E", 'F'}, + {"01OV;N", 'F'}, + {"01OV;T", 'F'}, + {"01OVA(", 'F'}, + {"01OVAF", 'F'}, + {"01OVAS", 'F'}, + {"01OVAT", 'F'}, + {"01OVAV", 'F'}, + {"01OVB(", 'F'}, + {"01OVB1", 'F'}, + {"01OVBE", 'F'}, + {"01OVBF", 'F'}, + {"01OVBN", 'F'}, + {"01OVBS", 'F'}, + {"01OVBV", 'F'}, + {"01OVC", 'F'}, + {"01OVE(", 'F'}, + {"01OVE1", 'F'}, + {"01OVEF", 'F'}, + {"01OVEK", 'F'}, + {"01OVEN", 'F'}, + {"01OVEO", 'F'}, + {"01OVES", 'F'}, + {"01OVEU", 'F'}, + {"01OVEV", 'F'}, + {"01OVF(", 'F'}, + {"01OVK(", 'F'}, + {"01OVK)", 'F'}, + {"01OVK1", 'F'}, + {"01OVKB", 'F'}, + {"01OVKF", 'F'}, + {"01OVKN", 'F'}, + {"01OVKS", 'F'}, + {"01OVKU", 'F'}, + {"01OVKV", 'F'}, + {"01OVO(", 'F'}, + {"01OVOF", 'F'}, + {"01OVOK", 'F'}, + {"01OVOS", 'F'}, + {"01OVOU", 'F'}, + {"01OVS(", 'F'}, + {"01OVS1", 'F'}, + {"01OVSF", 'F'}, + {"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'}, + {"01OVU;", 'F'}, + {"01OVUC", 'F'}, + {"01OVUE", 'F'}, + {"01OVUF", 'F'}, + {"01OVUK", 'F'}, + {"01OVUO", 'F'}, + {"01OVUS", 'F'}, + {"01OVUT", 'F'}, + {"01OVUV", 'F'}, + {"01SF()", 'F'}, + {"01SF(1", 'F'}, + {"01SF(F", 'F'}, + {"01SF(N", 'F'}, + {"01SF(S", 'F'}, + {"01SF(V", 'F'}, + {"01SUE", 'F'}, + {"01SUE;", 'F'}, + {"01SUEC", 'F'}, + {"01SUEK", 'F'}, + {"01SV", 'F'}, + {"01SV;", 'F'}, + {"01SV;C", 'F'}, + {"01SVC", 'F'}, + {"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'}, + {"01U(E(", 'F'}, + {"01U(E1", 'F'}, + {"01U(EF", 'F'}, + {"01U(EK", 'F'}, + {"01U(EN", 'F'}, + {"01U(ES", 'F'}, + {"01U(EV", 'F'}, + {"01U(F(", 'F'}, + {"01U(N)", 'F'}, + {"01U(NO", 'F'}, + {"01U(S)", 'F'}, + {"01U(SO", 'F'}, + {"01U(V)", 'F'}, + {"01U(VO", 'F'}, + {"01U1,(", 'F'}, + {"01U1,F", 'F'}, + {"01U1C", 'F'}, + {"01U1O(", 'F'}, + {"01U1OF", 'F'}, + {"01U1OS", 'F'}, + {"01U1OV", 'F'}, + {"01U;", 'F'}, + {"01U;C", 'F'}, + {"01UC", 'F'}, + {"01UE", 'F'}, + {"01UE(1", 'F'}, + {"01UE(E", 'F'}, + {"01UE(F", 'F'}, + {"01UE(N", 'F'}, + {"01UE(O", 'F'}, + {"01UE(S", 'F'}, + {"01UE(V", 'F'}, + {"01UE1", 'F'}, + {"01UE1&", 'F'}, + {"01UE1(", 'F'}, + {"01UE1)", 'F'}, + {"01UE1,", 'F'}, + {"01UE1;", 'F'}, + {"01UE1B", 'F'}, + {"01UE1C", 'F'}, + {"01UE1F", 'F'}, + {"01UE1K", 'F'}, + {"01UE1N", 'F'}, + {"01UE1O", 'F'}, + {"01UE1S", 'F'}, + {"01UE1U", 'F'}, + {"01UE1V", 'F'}, + {"01UE;", 'F'}, + {"01UE;C", 'F'}, + {"01UEC", 'F'}, + {"01UEF", 'F'}, + {"01UEF(", 'F'}, + {"01UEF,", 'F'}, + {"01UEF;", 'F'}, + {"01UEFC", 'F'}, + {"01UEK", 'F'}, + {"01UEK(", 'F'}, + {"01UEK1", 'F'}, + {"01UEK;", 'F'}, + {"01UEKC", 'F'}, + {"01UEKF", 'F'}, + {"01UEKN", 'F'}, + {"01UEKO", 'F'}, + {"01UEKS", 'F'}, + {"01UEKV", 'F'}, + {"01UEN", 'F'}, + {"01UEN&", 'F'}, + {"01UEN(", 'F'}, + {"01UEN)", 'F'}, + {"01UEN,", 'F'}, + {"01UEN1", 'F'}, + {"01UEN;", 'F'}, + {"01UENB", 'F'}, + {"01UENC", 'F'}, + {"01UENF", 'F'}, + {"01UENK", 'F'}, + {"01UENN", 'F'}, + {"01UENO", 'F'}, + {"01UENS", 'F'}, + {"01UENU", 'F'}, + {"01UEOK", 'F'}, + {"01UEON", 'F'}, + {"01UES", 'F'}, + {"01UES&", 'F'}, + {"01UES(", 'F'}, + {"01UES)", 'F'}, + {"01UES,", 'F'}, + {"01UES1", 'F'}, + {"01UES;", 'F'}, + {"01UESB", 'F'}, + {"01UESC", 'F'}, + {"01UESF", 'F'}, + {"01UESK", 'F'}, + {"01UESO", 'F'}, + {"01UESU", 'F'}, + {"01UESV", 'F'}, + {"01UEV", 'F'}, + {"01UEV&", 'F'}, + {"01UEV(", 'F'}, + {"01UEV)", 'F'}, + {"01UEV,", 'F'}, + {"01UEV;", 'F'}, + {"01UEVB", 'F'}, + {"01UEVC", 'F'}, + {"01UEVF", 'F'}, + {"01UEVK", 'F'}, + {"01UEVN", 'F'}, + {"01UEVO", 'F'}, + {"01UEVS", 'F'}, + {"01UEVU", 'F'}, + {"01UF()", 'F'}, + {"01UF(1", 'F'}, + {"01UF(F", 'F'}, + {"01UF(N", 'F'}, + {"01UF(S", 'F'}, + {"01UF(V", 'F'}, + {"01UK(E", 'F'}, + {"01UO(E", 'F'}, + {"01UON(", 'F'}, + {"01UON1", 'F'}, + {"01UONF", 'F'}, + {"01UONS", 'F'}, + {"01US,(", 'F'}, + {"01US,F", 'F'}, + {"01USC", 'F'}, + {"01USO(", 'F'}, + {"01USO1", 'F'}, + {"01USOF", 'F'}, + {"01USON", 'F'}, + {"01USOS", 'F'}, + {"01USOV", 'F'}, + {"01UTN(", 'F'}, + {"01UTN1", 'F'}, + {"01UTNF", 'F'}, + {"01UTNN", 'F'}, + {"01UTNS", 'F'}, + {"01UTNV", 'F'}, + {"01UV,(", 'F'}, + {"01UV,F", 'F'}, + {"01UVC", 'F'}, + {"01UVO(", 'F'}, + {"01UVOF", 'F'}, + {"01UVOS", 'F'}, + {"01VF()", 'F'}, + {"01VF(1", 'F'}, + {"01VF(F", 'F'}, + {"01VF(N", 'F'}, + {"01VF(S", 'F'}, + {"01VF(V", 'F'}, + {"01VO(1", 'F'}, + {"01VO(F", 'F'}, + {"01VO(N", 'F'}, + {"01VO(S", 'F'}, + {"01VO(V", 'F'}, + {"01VOF(", 'F'}, + {"01VOS(", 'F'}, + {"01VOS1", 'F'}, + {"01VOSF", 'F'}, + {"01VOSU", 'F'}, + {"01VOSV", 'F'}, + {"01VS", 'F'}, + {"01VS;", 'F'}, + {"01VS;C", 'F'}, + {"01VSC", 'F'}, + {"01VSO(", 'F'}, + {"01VSO1", 'F'}, + {"01VSOF", 'F'}, + {"01VSON", 'F'}, + {"01VSOS", 'F'}, + {"01VSOV", 'F'}, + {"01VUE", 'F'}, + {"01VUE;", 'F'}, + {"01VUEC", 'F'}, + {"01VUEK", 'F'}, + {"0;T(EF", 'F'}, + {"0;T(EK", 'F'}, + {"0;TKNC", 'F'}, + {"0E(1&(", 'F'}, + {"0E(1&1", 'F'}, + {"0E(1&F", 'F'}, + {"0E(1&N", 'F'}, + {"0E(1&S", 'F'}, + {"0E(1&V", 'F'}, + {"0E(1)&", 'F'}, + {"0E(1),", 'F'}, + {"0E(1)1", 'F'}, + {"0E(1);", 'F'}, + {"0E(1)B", 'F'}, + {"0E(1)C", 'F'}, + {"0E(1)F", 'F'}, + {"0E(1)K", 'F'}, + {"0E(1)N", 'F'}, + {"0E(1)O", 'F'}, + {"0E(1)S", 'F'}, + {"0E(1)U", 'F'}, + {"0E(1)V", 'F'}, + {"0E(1,F", 'F'}, + {"0E(1F(", 'F'}, + {"0E(1N)", 'F'}, + {"0E(1O(", 'F'}, + {"0E(1OF", 'F'}, + {"0E(1OS", 'F'}, + {"0E(1OV", 'F'}, + {"0E(1S)", 'F'}, + {"0E(1V)", 'F'}, + {"0E(1VO", 'F'}, + {"0E(E(1", 'F'}, + {"0E(E(E", 'F'}, + {"0E(E(F", 'F'}, + {"0E(E(N", 'F'}, + {"0E(E(S", 'F'}, + {"0E(E(V", 'F'}, + {"0E(E1&", 'F'}, + {"0E(E1)", 'F'}, + {"0E(E1O", 'F'}, + {"0E(EF(", 'F'}, + {"0E(EK(", 'F'}, + {"0E(EK1", 'F'}, + {"0E(EKF", 'F'}, + {"0E(EKN", 'F'}, + {"0E(EKS", 'F'}, + {"0E(EKV", 'F'}, + {"0E(EN&", 'F'}, + {"0E(EN)", 'F'}, + {"0E(ENO", 'F'}, + {"0E(ES&", 'F'}, + {"0E(ES)", 'F'}, + {"0E(ESO", 'F'}, + {"0E(EV&", 'F'}, + {"0E(EV)", 'F'}, + {"0E(EVO", 'F'}, + {"0E(F()", 'F'}, + {"0E(F(1", 'F'}, + {"0E(F(E", 'F'}, + {"0E(F(F", 'F'}, + {"0E(F(N", 'F'}, + {"0E(F(S", 'F'}, + {"0E(F(V", 'F'}, + {"0E(N&(", 'F'}, + {"0E(N&1", 'F'}, + {"0E(N&F", 'F'}, + {"0E(N&N", 'F'}, + {"0E(N&S", 'F'}, + {"0E(N&V", 'F'}, + {"0E(N(1", 'F'}, + {"0E(N(F", 'F'}, + {"0E(N(S", 'F'}, + {"0E(N(V", 'F'}, + {"0E(N)&", 'F'}, + {"0E(N),", 'F'}, + {"0E(N)1", 'F'}, + {"0E(N);", 'F'}, + {"0E(N)B", 'F'}, + {"0E(N)C", 'F'}, + {"0E(N)F", 'F'}, + {"0E(N)K", 'F'}, + {"0E(N)N", 'F'}, + {"0E(N)O", 'F'}, + {"0E(N)S", 'F'}, + {"0E(N)U", 'F'}, + {"0E(N)V", 'F'}, + {"0E(N,F", 'F'}, + {"0E(N1)", 'F'}, + {"0E(N1O", 'F'}, + {"0E(NF(", 'F'}, + {"0E(NO(", 'F'}, + {"0E(NOF", 'F'}, + {"0E(NOS", 'F'}, + {"0E(NOV", 'F'}, + {"0E(S&(", 'F'}, + {"0E(S&1", 'F'}, + {"0E(S&F", 'F'}, + {"0E(S&N", 'F'}, + {"0E(S&S", 'F'}, + {"0E(S&V", 'F'}, + {"0E(S)&", 'F'}, + {"0E(S),", 'F'}, + {"0E(S)1", 'F'}, + {"0E(S);", 'F'}, + {"0E(S)B", 'F'}, + {"0E(S)C", 'F'}, + {"0E(S)F", 'F'}, + {"0E(S)K", 'F'}, + {"0E(S)N", 'F'}, + {"0E(S)O", 'F'}, + {"0E(S)S", 'F'}, + {"0E(S)U", 'F'}, + {"0E(S)V", 'F'}, + {"0E(S,F", 'F'}, + {"0E(S1)", 'F'}, + {"0E(SF(", 'F'}, + {"0E(SO(", 'F'}, + {"0E(SO1", 'F'}, + {"0E(SOF", 'F'}, + {"0E(SON", 'F'}, + {"0E(SOS", 'F'}, + {"0E(SOV", 'F'}, + {"0E(SV)", 'F'}, + {"0E(SVO", 'F'}, + {"0E(V&(", 'F'}, + {"0E(V&1", 'F'}, + {"0E(V&F", 'F'}, + {"0E(V&N", 'F'}, + {"0E(V&S", 'F'}, + {"0E(V&V", 'F'}, + {"0E(V)&", 'F'}, + {"0E(V),", 'F'}, + {"0E(V)1", 'F'}, + {"0E(V);", 'F'}, + {"0E(V)B", 'F'}, + {"0E(V)C", 'F'}, + {"0E(V)F", 'F'}, + {"0E(V)K", 'F'}, + {"0E(V)N", 'F'}, + {"0E(V)O", 'F'}, + {"0E(V)S", 'F'}, + {"0E(V)U", 'F'}, + {"0E(V)V", 'F'}, + {"0E(V,F", 'F'}, + {"0E(VF(", 'F'}, + {"0E(VO(", 'F'}, + {"0E(VOF", 'F'}, + {"0E(VOS", 'F'}, + {"0E(VS)", 'F'}, + {"0E(VSO", 'F'}, + {"0E1&(1", 'F'}, + {"0E1&(E", 'F'}, + {"0E1&(F", 'F'}, + {"0E1&(N", 'F'}, + {"0E1&(S", 'F'}, + {"0E1&(V", 'F'}, + {"0E1&1)", 'F'}, + {"0E1&1O", 'F'}, + {"0E1&F(", 'F'}, + {"0E1&N)", 'F'}, + {"0E1&NO", 'F'}, + {"0E1&S)", 'F'}, + {"0E1&SO", 'F'}, + {"0E1&V)", 'F'}, + {"0E1&VO", 'F'}, + {"0E1)", 'F'}, + {"0E1)&(", 'F'}, + {"0E1)&1", 'F'}, + {"0E1)&F", 'F'}, + {"0E1)&N", 'F'}, + {"0E1)&S", 'F'}, + {"0E1)&V", 'F'}, + {"0E1);", 'F'}, + {"0E1);(", 'F'}, + {"0E1);C", 'F'}, + {"0E1);E", 'F'}, + {"0E1);T", 'F'}, + {"0E1)C", 'F'}, + {"0E1)KN", 'F'}, + {"0E1)O(", 'F'}, + {"0E1)O1", 'F'}, + {"0E1)OF", 'F'}, + {"0E1)ON", 'F'}, + {"0E1)OS", 'F'}, + {"0E1)OV", 'F'}, + {"0E1)UE", 'F'}, + {"0E1,(1", 'F'}, + {"0E1,(F", 'F'}, + {"0E1,(N", 'F'}, + {"0E1,(S", 'F'}, + {"0E1,(V", 'F'}, + {"0E1,F(", 'F'}, + {"0E1;(E", 'F'}, + {"0E1B(1", 'F'}, + {"0E1B(F", 'F'}, + {"0E1B(N", 'F'}, + {"0E1B(S", 'F'}, + {"0E1B(V", 'F'}, + {"0E1B1)", 'F'}, + {"0E1B1O", 'F'}, + {"0E1BF(", 'F'}, + {"0E1BN)", 'F'}, + {"0E1BNO", 'F'}, + {"0E1BS)", 'F'}, + {"0E1BSO", 'F'}, + {"0E1BV)", 'F'}, + {"0E1BVO", 'F'}, + {"0E1F()", 'F'}, + {"0E1F(1", 'F'}, + {"0E1F(F", 'F'}, + {"0E1F(N", 'F'}, + {"0E1F(S", 'F'}, + {"0E1F(V", 'F'}, + {"0E1K(1", 'F'}, + {"0E1K(E", 'F'}, + {"0E1K(F", 'F'}, + {"0E1K(N", 'F'}, + {"0E1K(S", 'F'}, + {"0E1K(V", 'F'}, + {"0E1K1)", 'F'}, + {"0E1K1K", 'F'}, + {"0E1K1O", 'F'}, + {"0E1KF(", 'F'}, + {"0E1KN", 'F'}, + {"0E1KN)", 'F'}, + {"0E1KN;", 'F'}, + {"0E1KNC", 'F'}, + {"0E1KNK", 'F'}, + {"0E1KNU", 'F'}, + {"0E1KS)", 'F'}, + {"0E1KSK", 'F'}, + {"0E1KSO", 'F'}, + {"0E1KV)", 'F'}, + {"0E1KVK", 'F'}, + {"0E1KVO", 'F'}, + {"0E1N)U", 'F'}, + {"0E1N;", 'F'}, + {"0E1N;C", 'F'}, + {"0E1NC", 'F'}, + {"0E1NKN", 'F'}, + {"0E1O(1", 'F'}, + {"0E1O(E", 'F'}, + {"0E1O(F", 'F'}, + {"0E1O(N", 'F'}, + {"0E1O(S", 'F'}, + {"0E1O(V", 'F'}, + {"0E1OF(", 'F'}, + {"0E1OS&", 'F'}, + {"0E1OS(", 'F'}, + {"0E1OS)", 'F'}, + {"0E1OS,", 'F'}, + {"0E1OS1", 'F'}, + {"0E1OS;", 'F'}, + {"0E1OSB", 'F'}, + {"0E1OSF", 'F'}, + {"0E1OSK", 'F'}, + {"0E1OSU", 'F'}, + {"0E1OSV", 'F'}, + {"0E1OV&", 'F'}, + {"0E1OV(", 'F'}, + {"0E1OV)", 'F'}, + {"0E1OV,", 'F'}, + {"0E1OV;", 'F'}, + {"0E1OVB", 'F'}, + {"0E1OVF", 'F'}, + {"0E1OVK", 'F'}, + {"0E1OVO", 'F'}, + {"0E1OVS", 'F'}, + {"0E1OVU", 'F'}, + {"0E1S;", 'F'}, + {"0E1S;C", 'F'}, + {"0E1SC", 'F'}, + {"0E1U(E", 'F'}, + {"0E1UE(", 'F'}, + {"0E1UE1", 'F'}, + {"0E1UEF", 'F'}, + {"0E1UEK", 'F'}, + {"0E1UEN", 'F'}, + {"0E1UES", 'F'}, + {"0E1UEV", 'F'}, + {"0E1V", 'F'}, + {"0E1V;", 'F'}, + {"0E1V;C", 'F'}, + {"0E1VC", 'F'}, + {"0E1VO(", 'F'}, + {"0E1VOF", 'F'}, + {"0E1VOS", 'F'}, + {"0EE(F(", 'F'}, + {"0EEK(F", 'F'}, + {"0EF()&", 'F'}, + {"0EF(),", 'F'}, + {"0EF()1", 'F'}, + {"0EF();", 'F'}, + {"0EF()B", 'F'}, + {"0EF()F", 'F'}, + {"0EF()K", 'F'}, + {"0EF()N", 'F'}, + {"0EF()O", 'F'}, + {"0EF()S", 'F'}, + {"0EF()U", 'F'}, + {"0EF()V", 'F'}, + {"0EF(1&", 'F'}, + {"0EF(1)", 'F'}, + {"0EF(1,", 'F'}, + {"0EF(1O", 'F'}, + {"0EF(E(", 'F'}, + {"0EF(E1", 'F'}, + {"0EF(EF", 'F'}, + {"0EF(EK", 'F'}, + {"0EF(EN", 'F'}, + {"0EF(ES", 'F'}, + {"0EF(EV", 'F'}, + {"0EF(F(", 'F'}, + {"0EF(N&", 'F'}, + {"0EF(N)", 'F'}, + {"0EF(N,", 'F'}, + {"0EF(NO", 'F'}, + {"0EF(O)", 'F'}, + {"0EF(S&", 'F'}, + {"0EF(S)", 'F'}, + {"0EF(S,", 'F'}, + {"0EF(SO", 'F'}, + {"0EF(V&", 'F'}, + {"0EF(V)", 'F'}, + {"0EF(V,", 'F'}, + {"0EF(VO", 'F'}, + {"0EK(1&", 'F'}, + {"0EK(1(", 'F'}, + {"0EK(1)", 'F'}, + {"0EK(1,", 'F'}, + {"0EK(1F", 'F'}, + {"0EK(1N", 'F'}, + {"0EK(1O", 'F'}, + {"0EK(1S", 'F'}, + {"0EK(1V", 'F'}, + {"0EK(E(", 'F'}, + {"0EK(E1", 'F'}, + {"0EK(EF", 'F'}, + {"0EK(EK", 'F'}, + {"0EK(EN", 'F'}, + {"0EK(ES", 'F'}, + {"0EK(EV", 'F'}, + {"0EK(F(", 'F'}, + {"0EK(N&", 'F'}, + {"0EK(N(", 'F'}, + {"0EK(N)", 'F'}, + {"0EK(N,", 'F'}, + {"0EK(N1", 'F'}, + {"0EK(NF", 'F'}, + {"0EK(NO", 'F'}, + {"0EK(S&", 'F'}, + {"0EK(S(", 'F'}, + {"0EK(S)", 'F'}, + {"0EK(S,", 'F'}, + {"0EK(S1", 'F'}, + {"0EK(SF", 'F'}, + {"0EK(SO", 'F'}, + {"0EK(SV", 'F'}, + {"0EK(V&", 'F'}, + {"0EK(V(", 'F'}, + {"0EK(V)", 'F'}, + {"0EK(V,", 'F'}, + {"0EK(VF", 'F'}, + {"0EK(VO", 'F'}, + {"0EK(VS", 'F'}, + {"0EK1&(", 'F'}, + {"0EK1&1", 'F'}, + {"0EK1&F", 'F'}, + {"0EK1&N", 'F'}, + {"0EK1&S", 'F'}, + {"0EK1&V", 'F'}, + {"0EK1)", 'F'}, + {"0EK1)&", 'F'}, + {"0EK1);", 'F'}, + {"0EK1)C", 'F'}, + {"0EK1)K", 'F'}, + {"0EK1)O", 'F'}, + {"0EK1)U", 'F'}, + {"0EK1,(", 'F'}, + {"0EK1,F", 'F'}, + {"0EK1;(", 'F'}, + {"0EK1B(", 'F'}, + {"0EK1B1", 'F'}, + {"0EK1BF", 'F'}, + {"0EK1BN", 'F'}, + {"0EK1BS", 'F'}, + {"0EK1BV", 'F'}, + {"0EK1F(", 'F'}, + {"0EK1K(", 'F'}, + {"0EK1K1", 'F'}, + {"0EK1KF", 'F'}, + {"0EK1KN", 'F'}, + {"0EK1KS", 'F'}, + {"0EK1KV", 'F'}, + {"0EK1N", 'F'}, + {"0EK1N)", 'F'}, + {"0EK1N;", 'F'}, + {"0EK1NC", 'F'}, + {"0EK1NK", 'F'}, + {"0EK1O(", 'F'}, + {"0EK1OF", 'F'}, + {"0EK1OS", 'F'}, + {"0EK1OV", 'F'}, + {"0EK1S", 'F'}, + {"0EK1S;", 'F'}, + {"0EK1SC", 'F'}, + {"0EK1SF", 'F'}, + {"0EK1SK", 'F'}, + {"0EK1U(", 'F'}, + {"0EK1UE", 'F'}, + {"0EK1V", 'F'}, + {"0EK1V;", 'F'}, + {"0EK1VC", 'F'}, + {"0EK1VF", 'F'}, + {"0EK1VK", 'F'}, + {"0EK1VO", 'F'}, + {"0EKE(F", 'F'}, + {"0EKEK(", 'F'}, + {"0EKF()", 'F'}, + {"0EKF(1", 'F'}, + {"0EKF(E", 'F'}, + {"0EKF(F", 'F'}, + {"0EKF(N", 'F'}, + {"0EKF(O", 'F'}, + {"0EKF(S", 'F'}, + {"0EKF(V", 'F'}, + {"0EKN&(", 'F'}, + {"0EKN&1", 'F'}, + {"0EKN&F", 'F'}, + {"0EKN&N", 'F'}, + {"0EKN&S", 'F'}, + {"0EKN&V", 'F'}, + {"0EKN(1", 'F'}, + {"0EKN(F", 'F'}, + {"0EKN(S", 'F'}, + {"0EKN(V", 'F'}, + {"0EKN)", 'F'}, + {"0EKN)&", 'F'}, + {"0EKN);", 'F'}, + {"0EKN)C", 'F'}, + {"0EKN)K", 'F'}, + {"0EKN)O", 'F'}, + {"0EKN)U", 'F'}, + {"0EKN,(", 'F'}, + {"0EKN,F", 'F'}, + {"0EKN1", 'F'}, + {"0EKN1;", 'F'}, + {"0EKN1C", 'F'}, + {"0EKN1K", 'F'}, + {"0EKN1O", 'F'}, + {"0EKN;(", 'F'}, + {"0EKNB(", 'F'}, + {"0EKNB1", 'F'}, + {"0EKNBF", 'F'}, + {"0EKNBN", 'F'}, + {"0EKNBS", 'F'}, + {"0EKNBV", 'F'}, + {"0EKNF(", 'F'}, + {"0EKNK(", 'F'}, + {"0EKNK1", 'F'}, + {"0EKNKF", 'F'}, + {"0EKNKN", 'F'}, + {"0EKNKS", 'F'}, + {"0EKNKV", 'F'}, + {"0EKNU(", 'F'}, + {"0EKNUE", 'F'}, + {"0EKO(1", 'F'}, + {"0EKO(F", 'F'}, + {"0EKO(N", 'F'}, + {"0EKO(S", 'F'}, + {"0EKO(V", 'F'}, + {"0EKOK(", 'F'}, + {"0EKOKN", 'F'}, + {"0EKS&(", 'F'}, + {"0EKS&1", 'F'}, + {"0EKS&F", 'F'}, + {"0EKS&N", 'F'}, + {"0EKS&S", 'F'}, + {"0EKS&V", 'F'}, + {"0EKS)", 'F'}, + {"0EKS)&", 'F'}, + {"0EKS);", 'F'}, + {"0EKS)C", 'F'}, + {"0EKS)K", 'F'}, + {"0EKS)O", 'F'}, + {"0EKS)U", 'F'}, + {"0EKS,(", 'F'}, + {"0EKS,F", 'F'}, + {"0EKS1", 'F'}, + {"0EKS1;", 'F'}, + {"0EKS1C", 'F'}, + {"0EKS1F", 'F'}, + {"0EKS1K", 'F'}, + {"0EKS;(", 'F'}, + {"0EKSB(", 'F'}, + {"0EKSB1", 'F'}, + {"0EKSBF", 'F'}, + {"0EKSBN", 'F'}, + {"0EKSBS", 'F'}, + {"0EKSBV", 'F'}, + {"0EKSF(", 'F'}, + {"0EKSK(", 'F'}, + {"0EKSK1", 'F'}, + {"0EKSKF", 'F'}, + {"0EKSKN", 'F'}, + {"0EKSKS", 'F'}, + {"0EKSKV", 'F'}, + {"0EKSO(", 'F'}, + {"0EKSO1", 'F'}, + {"0EKSOF", 'F'}, + {"0EKSON", 'F'}, + {"0EKSOS", 'F'}, + {"0EKSOV", 'F'}, + {"0EKSU(", 'F'}, + {"0EKSUE", 'F'}, + {"0EKSV", 'F'}, + {"0EKSV;", 'F'}, + {"0EKSVC", 'F'}, + {"0EKSVF", 'F'}, + {"0EKSVK", 'F'}, + {"0EKSVO", 'F'}, + {"0EKV&(", 'F'}, + {"0EKV&1", 'F'}, + {"0EKV&F", 'F'}, + {"0EKV&N", 'F'}, + {"0EKV&S", 'F'}, + {"0EKV&V", 'F'}, + {"0EKV)", 'F'}, + {"0EKV)&", 'F'}, + {"0EKV);", 'F'}, + {"0EKV)C", 'F'}, + {"0EKV)K", 'F'}, + {"0EKV)O", 'F'}, + {"0EKV)U", 'F'}, + {"0EKV,(", 'F'}, + {"0EKV,F", 'F'}, + {"0EKV;(", 'F'}, + {"0EKVB(", 'F'}, + {"0EKVB1", 'F'}, + {"0EKVBF", 'F'}, + {"0EKVBN", 'F'}, + {"0EKVBS", 'F'}, + {"0EKVBV", 'F'}, + {"0EKVF(", 'F'}, + {"0EKVK(", 'F'}, + {"0EKVK1", 'F'}, + {"0EKVKF", 'F'}, + {"0EKVKN", 'F'}, + {"0EKVKS", 'F'}, + {"0EKVKV", 'F'}, + {"0EKVO(", 'F'}, + {"0EKVOF", 'F'}, + {"0EKVOS", 'F'}, + {"0EKVS", 'F'}, + {"0EKVS;", 'F'}, + {"0EKVSC", 'F'}, + {"0EKVSF", 'F'}, + {"0EKVSK", 'F'}, + {"0EKVSO", 'F'}, + {"0EKVU(", 'F'}, + {"0EKVUE", 'F'}, + {"0EN&(1", 'F'}, + {"0EN&(E", 'F'}, + {"0EN&(F", 'F'}, + {"0EN&(N", 'F'}, + {"0EN&(S", 'F'}, + {"0EN&(V", 'F'}, + {"0EN&1)", 'F'}, + {"0EN&1O", 'F'}, + {"0EN&F(", 'F'}, + {"0EN&N)", 'F'}, + {"0EN&NO", 'F'}, + {"0EN&S)", 'F'}, + {"0EN&SO", 'F'}, + {"0EN&V)", 'F'}, + {"0EN&VO", 'F'}, + {"0EN(1O", 'F'}, + {"0EN(F(", 'F'}, + {"0EN(S)", 'F'}, + {"0EN(SO", 'F'}, + {"0EN(V)", 'F'}, + {"0EN(VO", 'F'}, + {"0EN)", 'F'}, + {"0EN)&(", 'F'}, + {"0EN)&1", 'F'}, + {"0EN)&F", 'F'}, + {"0EN)&N", 'F'}, + {"0EN)&S", 'F'}, + {"0EN)&V", 'F'}, + {"0EN);", 'F'}, + {"0EN);(", 'F'}, + {"0EN);C", 'F'}, + {"0EN);E", 'F'}, + {"0EN);T", 'F'}, + {"0EN)C", 'F'}, + {"0EN)KN", 'F'}, + {"0EN)O(", 'F'}, + {"0EN)O1", 'F'}, + {"0EN)OF", 'F'}, + {"0EN)ON", 'F'}, + {"0EN)OS", 'F'}, + {"0EN)OV", 'F'}, + {"0EN)UE", 'F'}, + {"0EN,(1", 'F'}, + {"0EN,(F", 'F'}, + {"0EN,(N", 'F'}, + {"0EN,(S", 'F'}, + {"0EN,(V", 'F'}, + {"0EN,F(", 'F'}, + {"0EN1;", 'F'}, + {"0EN1;C", 'F'}, + {"0EN1O(", 'F'}, + {"0EN1OF", 'F'}, + {"0EN1OS", 'F'}, + {"0EN1OV", 'F'}, + {"0EN;(E", 'F'}, + {"0ENB(1", 'F'}, + {"0ENB(F", 'F'}, + {"0ENB(N", 'F'}, + {"0ENB(S", 'F'}, + {"0ENB(V", 'F'}, + {"0ENB1)", 'F'}, + {"0ENB1O", 'F'}, + {"0ENBF(", 'F'}, + {"0ENBN)", 'F'}, + {"0ENBNO", 'F'}, + {"0ENBS)", 'F'}, + {"0ENBSO", 'F'}, + {"0ENBV)", 'F'}, + {"0ENBVO", 'F'}, + {"0ENF()", 'F'}, + {"0ENF(1", 'F'}, + {"0ENF(F", 'F'}, + {"0ENF(N", 'F'}, + {"0ENF(S", 'F'}, + {"0ENF(V", 'F'}, + {"0ENK(1", 'F'}, + {"0ENK(E", 'F'}, + {"0ENK(F", 'F'}, + {"0ENK(N", 'F'}, + {"0ENK(S", 'F'}, + {"0ENK(V", 'F'}, + {"0ENK1)", 'F'}, + {"0ENK1K", 'F'}, + {"0ENK1O", 'F'}, + {"0ENKF(", 'F'}, + {"0ENKN)", 'F'}, + {"0ENKN,", 'F'}, + {"0ENKN;", 'F'}, + {"0ENKNB", 'F'}, + {"0ENKNC", 'F'}, + {"0ENKNK", 'F'}, + {"0ENKNU", 'F'}, + {"0ENKS)", 'F'}, + {"0ENKSK", 'F'}, + {"0ENKSO", 'F'}, + {"0ENKV)", 'F'}, + {"0ENKVK", 'F'}, + {"0ENKVO", 'F'}, + {"0ENO(1", 'F'}, + {"0ENO(E", 'F'}, + {"0ENO(F", 'F'}, + {"0ENO(N", 'F'}, + {"0ENO(S", 'F'}, + {"0ENO(V", 'F'}, + {"0ENOF(", 'F'}, + {"0ENOS&", 'F'}, + {"0ENOS(", 'F'}, + {"0ENOS)", 'F'}, + {"0ENOS,", 'F'}, + {"0ENOS1", 'F'}, + {"0ENOS;", 'F'}, + {"0ENOSB", 'F'}, + {"0ENOSF", 'F'}, + {"0ENOSK", 'F'}, + {"0ENOSU", 'F'}, + {"0ENOSV", 'F'}, + {"0ENOV&", 'F'}, + {"0ENOV(", 'F'}, + {"0ENOV)", 'F'}, + {"0ENOV,", 'F'}, + {"0ENOV;", 'F'}, + {"0ENOVB", 'F'}, + {"0ENOVF", 'F'}, + {"0ENOVK", 'F'}, + {"0ENOVO", 'F'}, + {"0ENOVS", 'F'}, + {"0ENOVU", 'F'}, + {"0ENU(E", 'F'}, + {"0ENUE(", 'F'}, + {"0ENUE1", 'F'}, + {"0ENUEF", 'F'}, + {"0ENUEK", 'F'}, + {"0ENUEN", 'F'}, + {"0ENUES", 'F'}, + {"0ENUEV", 'F'}, + {"0EOK(E", 'F'}, + {"0EOKNK", 'F'}, + {"0ES&(1", 'F'}, + {"0ES&(E", 'F'}, + {"0ES&(F", 'F'}, + {"0ES&(N", 'F'}, + {"0ES&(S", 'F'}, + {"0ES&(V", 'F'}, + {"0ES&1)", 'F'}, + {"0ES&1O", 'F'}, + {"0ES&F(", 'F'}, + {"0ES&N)", 'F'}, + {"0ES&NO", 'F'}, + {"0ES&S)", 'F'}, + {"0ES&SO", 'F'}, + {"0ES&V)", 'F'}, + {"0ES&VO", 'F'}, + {"0ES)", 'F'}, + {"0ES)&(", 'F'}, + {"0ES)&1", 'F'}, + {"0ES)&F", 'F'}, + {"0ES)&N", 'F'}, + {"0ES)&S", 'F'}, + {"0ES)&V", 'F'}, + {"0ES);", 'F'}, + {"0ES);(", 'F'}, + {"0ES);C", 'F'}, + {"0ES);E", 'F'}, + {"0ES);T", 'F'}, + {"0ES)C", 'F'}, + {"0ES)KN", 'F'}, + {"0ES)O(", 'F'}, + {"0ES)O1", 'F'}, + {"0ES)OF", 'F'}, + {"0ES)ON", 'F'}, + {"0ES)OS", 'F'}, + {"0ES)OV", 'F'}, + {"0ES)UE", 'F'}, + {"0ES,(1", 'F'}, + {"0ES,(F", 'F'}, + {"0ES,(N", 'F'}, + {"0ES,(S", 'F'}, + {"0ES,(V", 'F'}, + {"0ES,F(", 'F'}, + {"0ES1", 'F'}, + {"0ES1;", 'F'}, + {"0ES1;C", 'F'}, + {"0ES1C", 'F'}, + {"0ES;(E", 'F'}, + {"0ESB(1", 'F'}, + {"0ESB(F", 'F'}, + {"0ESB(N", 'F'}, + {"0ESB(S", 'F'}, + {"0ESB(V", 'F'}, + {"0ESB1)", 'F'}, + {"0ESB1O", 'F'}, + {"0ESBF(", 'F'}, + {"0ESBN)", 'F'}, + {"0ESBNO", 'F'}, + {"0ESBS)", 'F'}, + {"0ESBSO", 'F'}, + {"0ESBV)", 'F'}, + {"0ESBVO", 'F'}, + {"0ESF()", 'F'}, + {"0ESF(1", 'F'}, + {"0ESF(F", 'F'}, + {"0ESF(N", 'F'}, + {"0ESF(S", 'F'}, + {"0ESF(V", 'F'}, + {"0ESK(1", 'F'}, + {"0ESK(E", 'F'}, + {"0ESK(F", 'F'}, + {"0ESK(N", 'F'}, + {"0ESK(S", 'F'}, + {"0ESK(V", 'F'}, + {"0ESK1)", 'F'}, + {"0ESK1K", 'F'}, + {"0ESK1O", 'F'}, + {"0ESKF(", 'F'}, + {"0ESKN", 'F'}, + {"0ESKN)", 'F'}, + {"0ESKN;", 'F'}, + {"0ESKNC", 'F'}, + {"0ESKNK", 'F'}, + {"0ESKNU", 'F'}, + {"0ESKS)", 'F'}, + {"0ESKSK", 'F'}, + {"0ESKSO", 'F'}, + {"0ESKV)", 'F'}, + {"0ESKVK", 'F'}, + {"0ESKVO", 'F'}, + {"0ESO(1", 'F'}, + {"0ESO(E", 'F'}, + {"0ESO(F", 'F'}, + {"0ESO(N", 'F'}, + {"0ESO(S", 'F'}, + {"0ESO(V", 'F'}, + {"0ESO1&", 'F'}, + {"0ESO1(", 'F'}, + {"0ESO1)", 'F'}, + {"0ESO1,", 'F'}, + {"0ESO1;", 'F'}, + {"0ESO1B", 'F'}, + {"0ESO1F", 'F'}, + {"0ESO1K", 'F'}, + {"0ESO1N", 'F'}, + {"0ESO1S", 'F'}, + {"0ESO1U", 'F'}, + {"0ESO1V", 'F'}, + {"0ESOF(", 'F'}, + {"0ESON&", 'F'}, + {"0ESON(", 'F'}, + {"0ESON)", 'F'}, + {"0ESON,", 'F'}, + {"0ESON1", 'F'}, + {"0ESON;", 'F'}, + {"0ESONB", 'F'}, + {"0ESONF", 'F'}, + {"0ESONK", 'F'}, + {"0ESONU", 'F'}, + {"0ESOS&", 'F'}, + {"0ESOS(", 'F'}, + {"0ESOS)", 'F'}, + {"0ESOS,", 'F'}, + {"0ESOS1", 'F'}, + {"0ESOS;", 'F'}, + {"0ESOSB", 'F'}, + {"0ESOSF", 'F'}, + {"0ESOSK", 'F'}, + {"0ESOSU", 'F'}, + {"0ESOSV", 'F'}, + {"0ESOV&", 'F'}, + {"0ESOV(", 'F'}, + {"0ESOV)", 'F'}, + {"0ESOV,", 'F'}, + {"0ESOV;", 'F'}, + {"0ESOVB", 'F'}, + {"0ESOVF", 'F'}, + {"0ESOVK", 'F'}, + {"0ESOVO", 'F'}, + {"0ESOVS", 'F'}, + {"0ESOVU", 'F'}, + {"0ESU(E", 'F'}, + {"0ESUE(", 'F'}, + {"0ESUE1", 'F'}, + {"0ESUEF", 'F'}, + {"0ESUEK", 'F'}, + {"0ESUEN", 'F'}, + {"0ESUES", 'F'}, + {"0ESUEV", 'F'}, + {"0ESV", 'F'}, + {"0ESV;", 'F'}, + {"0ESV;C", 'F'}, + {"0ESVC", 'F'}, + {"0ESVO(", 'F'}, + {"0ESVOF", 'F'}, + {"0ESVOS", 'F'}, + {"0EV&(1", 'F'}, + {"0EV&(E", 'F'}, + {"0EV&(F", 'F'}, + {"0EV&(N", 'F'}, + {"0EV&(S", 'F'}, + {"0EV&(V", 'F'}, + {"0EV&1)", 'F'}, + {"0EV&1O", 'F'}, + {"0EV&F(", 'F'}, + {"0EV&N)", 'F'}, + {"0EV&NO", 'F'}, + {"0EV&S)", 'F'}, + {"0EV&SO", 'F'}, + {"0EV&V)", 'F'}, + {"0EV&VO", 'F'}, + {"0EV)", 'F'}, + {"0EV)&(", 'F'}, + {"0EV)&1", 'F'}, + {"0EV)&F", 'F'}, + {"0EV)&N", 'F'}, + {"0EV)&S", 'F'}, + {"0EV)&V", 'F'}, + {"0EV);", 'F'}, + {"0EV);(", 'F'}, + {"0EV);C", 'F'}, + {"0EV);E", 'F'}, + {"0EV);T", 'F'}, + {"0EV)C", 'F'}, + {"0EV)KN", 'F'}, + {"0EV)O(", 'F'}, + {"0EV)O1", 'F'}, + {"0EV)OF", 'F'}, + {"0EV)ON", 'F'}, + {"0EV)OS", 'F'}, + {"0EV)OV", 'F'}, + {"0EV)UE", 'F'}, + {"0EV,(1", 'F'}, + {"0EV,(F", 'F'}, + {"0EV,(N", 'F'}, + {"0EV,(S", 'F'}, + {"0EV,(V", 'F'}, + {"0EV,F(", 'F'}, + {"0EV;(E", 'F'}, + {"0EVB(1", 'F'}, + {"0EVB(F", 'F'}, + {"0EVB(N", 'F'}, + {"0EVB(S", 'F'}, + {"0EVB(V", 'F'}, + {"0EVB1)", 'F'}, + {"0EVB1O", 'F'}, + {"0EVBF(", 'F'}, + {"0EVBN)", 'F'}, + {"0EVBNO", 'F'}, + {"0EVBS)", 'F'}, + {"0EVBSO", 'F'}, + {"0EVBV)", 'F'}, + {"0EVBVO", 'F'}, + {"0EVF()", 'F'}, + {"0EVF(1", 'F'}, + {"0EVF(F", 'F'}, + {"0EVF(N", 'F'}, + {"0EVF(S", 'F'}, + {"0EVF(V", 'F'}, + {"0EVK(1", 'F'}, + {"0EVK(E", 'F'}, + {"0EVK(F", 'F'}, + {"0EVK(N", 'F'}, + {"0EVK(S", 'F'}, + {"0EVK(V", 'F'}, + {"0EVK1)", 'F'}, + {"0EVK1K", 'F'}, + {"0EVK1O", 'F'}, + {"0EVKF(", 'F'}, + {"0EVKN", 'F'}, + {"0EVKN)", 'F'}, + {"0EVKN;", 'F'}, + {"0EVKNC", 'F'}, + {"0EVKNK", 'F'}, + {"0EVKNU", 'F'}, + {"0EVKS)", 'F'}, + {"0EVKSK", 'F'}, + {"0EVKSO", 'F'}, + {"0EVKV)", 'F'}, + {"0EVKVK", 'F'}, + {"0EVKVO", 'F'}, + {"0EVN", 'F'}, + {"0EVN)U", 'F'}, + {"0EVN;", 'F'}, + {"0EVN;C", 'F'}, + {"0EVNC", 'F'}, + {"0EVNKN", 'F'}, + {"0EVNO(", 'F'}, + {"0EVNOF", 'F'}, + {"0EVNOS", 'F'}, + {"0EVNOV", 'F'}, + {"0EVO(1", 'F'}, + {"0EVO(E", 'F'}, + {"0EVO(F", 'F'}, + {"0EVO(N", 'F'}, + {"0EVO(S", 'F'}, + {"0EVO(V", 'F'}, + {"0EVOF(", 'F'}, + {"0EVOS&", 'F'}, + {"0EVOS(", 'F'}, + {"0EVOS)", 'F'}, + {"0EVOS,", 'F'}, + {"0EVOS1", 'F'}, + {"0EVOS;", 'F'}, + {"0EVOSB", 'F'}, + {"0EVOSF", 'F'}, + {"0EVOSK", 'F'}, + {"0EVOSU", 'F'}, + {"0EVOSV", 'F'}, + {"0EVS", 'F'}, + {"0EVS;", 'F'}, + {"0EVS;C", 'F'}, + {"0EVSC", 'F'}, + {"0EVSO(", 'F'}, + {"0EVSO1", 'F'}, + {"0EVSOF", 'F'}, + {"0EVSON", 'F'}, + {"0EVSOS", 'F'}, + {"0EVSOV", 'F'}, + {"0EVU(E", 'F'}, + {"0EVUE(", 'F'}, + {"0EVUE1", 'F'}, + {"0EVUEF", 'F'}, + {"0EVUEK", 'F'}, + {"0EVUEN", 'F'}, + {"0EVUES", 'F'}, + {"0EVUEV", 'F'}, + {"0F()&(", 'F'}, + {"0F()&1", 'F'}, + {"0F()&E", 'F'}, + {"0F()&F", 'F'}, + {"0F()&K", 'F'}, + {"0F()&N", 'F'}, + {"0F()&S", 'F'}, + {"0F()&V", 'F'}, + {"0F(),(", 'F'}, + {"0F(),1", 'F'}, + {"0F(),F", 'F'}, + {"0F(),N", 'F'}, + {"0F(),S", 'F'}, + {"0F(),V", 'F'}, + {"0F()1(", 'F'}, + {"0F()1F", 'F'}, + {"0F()1N", 'F'}, + {"0F()1O", 'F'}, + {"0F()1S", 'F'}, + {"0F()1U", 'F'}, + {"0F()1V", 'F'}, + {"0F();E", 'F'}, + {"0F();N", 'F'}, + {"0F();T", 'F'}, + {"0F()A(", 'F'}, + {"0F()AF", 'F'}, + {"0F()AS", 'F'}, + {"0F()AT", 'F'}, + {"0F()AV", 'F'}, + {"0F()B(", 'F'}, + {"0F()B1", 'F'}, + {"0F()BE", 'F'}, + {"0F()BF", 'F'}, + {"0F()BN", 'F'}, + {"0F()BS", 'F'}, + {"0F()BV", 'F'}, + {"0F()C", 'F'}, + {"0F()E(", 'F'}, + {"0F()E1", 'F'}, + {"0F()EF", 'F'}, + {"0F()EK", 'F'}, + {"0F()EN", 'F'}, + {"0F()EO", 'F'}, + {"0F()ES", 'F'}, + {"0F()EU", 'F'}, + {"0F()EV", 'F'}, + {"0F()F(", 'F'}, + {"0F()K(", 'F'}, + {"0F()K)", 'F'}, + {"0F()K1", 'F'}, + {"0F()KF", 'F'}, + {"0F()KN", 'F'}, + {"0F()KS", 'F'}, + {"0F()KU", 'F'}, + {"0F()KV", 'F'}, + {"0F()N&", 'F'}, + {"0F()N(", 'F'}, + {"0F()N)", 'F'}, + {"0F()N,", 'F'}, + {"0F()N1", 'F'}, + {"0F()NE", 'F'}, + {"0F()NF", 'F'}, + {"0F()NO", 'F'}, + {"0F()NU", 'F'}, + {"0F()O(", 'F'}, + {"0F()O1", 'F'}, + {"0F()OF", 'F'}, + {"0F()OK", 'F'}, + {"0F()ON", 'F'}, + {"0F()OS", 'F'}, + {"0F()OU", 'F'}, + {"0F()OV", 'F'}, + {"0F()S(", 'F'}, + {"0F()S1", 'F'}, + {"0F()SF", 'F'}, + {"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'}, + {"0F()U;", 'F'}, + {"0F()UC", 'F'}, + {"0F()UE", 'F'}, + {"0F()UF", 'F'}, + {"0F()UK", 'F'}, + {"0F()UO", 'F'}, + {"0F()US", 'F'}, + {"0F()UT", 'F'}, + {"0F()UV", 'F'}, + {"0F()V(", 'F'}, + {"0F()VF", 'F'}, + {"0F()VO", 'F'}, + {"0F()VS", 'F'}, + {"0F()VU", 'F'}, + {"0F(1&(", 'F'}, + {"0F(1&1", 'F'}, + {"0F(1&F", 'F'}, + {"0F(1&N", 'F'}, + {"0F(1&S", 'F'}, + {"0F(1&V", 'F'}, + {"0F(1)", 'F'}, + {"0F(1)&", 'F'}, + {"0F(1),", 'F'}, + {"0F(1)1", 'F'}, + {"0F(1);", 'F'}, + {"0F(1)A", 'F'}, + {"0F(1)B", 'F'}, + {"0F(1)C", 'F'}, + {"0F(1)E", 'F'}, + {"0F(1)F", 'F'}, + {"0F(1)K", 'F'}, + {"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'}, + {"0F(1,F", 'F'}, + {"0F(1O(", 'F'}, + {"0F(1OF", 'F'}, + {"0F(1OS", 'F'}, + {"0F(1OV", 'F'}, + {"0F(E(1", 'F'}, + {"0F(E(E", 'F'}, + {"0F(E(F", 'F'}, + {"0F(E(N", 'F'}, + {"0F(E(S", 'F'}, + {"0F(E(V", 'F'}, + {"0F(E1&", 'F'}, + {"0F(E1)", 'F'}, + {"0F(E1K", 'F'}, + {"0F(E1O", 'F'}, + {"0F(EF(", 'F'}, + {"0F(EK(", 'F'}, + {"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'}, + {"0F(ESO", 'F'}, + {"0F(EV&", 'F'}, + {"0F(EV)", 'F'}, + {"0F(EVK", 'F'}, + {"0F(EVO", 'F'}, + {"0F(F()", 'F'}, + {"0F(F(1", 'F'}, + {"0F(F(E", 'F'}, + {"0F(F(F", 'F'}, + {"0F(F(N", 'F'}, + {"0F(F(S", 'F'}, + {"0F(F(V", 'F'}, + {"0F(K()", 'F'}, + {"0F(K,(", 'F'}, + {"0F(K,F", 'F'}, + {"0F(N&(", 'F'}, + {"0F(N&1", 'F'}, + {"0F(N&F", 'F'}, + {"0F(N&N", 'F'}, + {"0F(N&S", 'F'}, + {"0F(N&V", 'F'}, + {"0F(N)", 'F'}, + {"0F(N)&", 'F'}, + {"0F(N),", 'F'}, + {"0F(N)1", 'F'}, + {"0F(N);", 'F'}, + {"0F(N)A", 'F'}, + {"0F(N)B", 'F'}, + {"0F(N)C", 'F'}, + {"0F(N)E", 'F'}, + {"0F(N)F", 'F'}, + {"0F(N)K", 'F'}, + {"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'}, + {"0F(N,F", 'F'}, + {"0F(NO(", 'F'}, + {"0F(NOF", 'F'}, + {"0F(NOS", 'F'}, + {"0F(NOV", 'F'}, + {"0F(S&(", 'F'}, + {"0F(S&1", 'F'}, + {"0F(S&F", 'F'}, + {"0F(S&N", 'F'}, + {"0F(S&S", 'F'}, + {"0F(S&V", 'F'}, + {"0F(S)", 'F'}, + {"0F(S)&", 'F'}, + {"0F(S),", 'F'}, + {"0F(S)1", 'F'}, + {"0F(S);", 'F'}, + {"0F(S)A", 'F'}, + {"0F(S)B", 'F'}, + {"0F(S)C", 'F'}, + {"0F(S)E", 'F'}, + {"0F(S)F", 'F'}, + {"0F(S)K", 'F'}, + {"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'}, + {"0F(S,F", 'F'}, + {"0F(SO(", 'F'}, + {"0F(SO1", 'F'}, + {"0F(SOF", 'F'}, + {"0F(SON", 'F'}, + {"0F(SOS", 'F'}, + {"0F(SOV", 'F'}, + {"0F(T,(", 'F'}, + {"0F(T,F", 'F'}, + {"0F(V&(", 'F'}, + {"0F(V&1", 'F'}, + {"0F(V&F", 'F'}, + {"0F(V&N", 'F'}, + {"0F(V&S", 'F'}, + {"0F(V&V", 'F'}, + {"0F(V)", 'F'}, + {"0F(V)&", 'F'}, + {"0F(V),", 'F'}, + {"0F(V)1", 'F'}, + {"0F(V);", 'F'}, + {"0F(V)A", 'F'}, + {"0F(V)B", 'F'}, + {"0F(V)C", 'F'}, + {"0F(V)E", 'F'}, + {"0F(V)F", 'F'}, + {"0F(V)K", 'F'}, + {"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'}, + {"0F(V,F", 'F'}, + {"0F(VO(", 'F'}, + {"0F(VOF", 'F'}, + {"0F(VOS", 'F'}, + {"0K(1),", 'F'}, + {"0K(1)A", 'F'}, + {"0K(1)K", 'F'}, + {"0K(1)O", 'F'}, + {"0K(1O(", 'F'}, + {"0K(1OF", 'F'}, + {"0K(1OS", 'F'}, + {"0K(1OV", 'F'}, + {"0K(F()", 'F'}, + {"0K(F(1", 'F'}, + {"0K(F(F", 'F'}, + {"0K(F(N", 'F'}, + {"0K(F(S", 'F'}, + {"0K(F(V", 'F'}, + {"0K(N),", 'F'}, + {"0K(N)A", 'F'}, + {"0K(N)K", 'F'}, + {"0K(N)O", 'F'}, + {"0K(NO(", 'F'}, + {"0K(NOF", 'F'}, + {"0K(NOS", 'F'}, + {"0K(NOV", 'F'}, + {"0K(S),", 'F'}, + {"0K(S)A", 'F'}, + {"0K(S)K", 'F'}, + {"0K(S)O", 'F'}, + {"0K(SO(", 'F'}, + {"0K(SO1", 'F'}, + {"0K(SOF", 'F'}, + {"0K(SON", 'F'}, + {"0K(SOS", 'F'}, + {"0K(SOV", 'F'}, + {"0K(V),", 'F'}, + {"0K(V)A", 'F'}, + {"0K(V)K", 'F'}, + {"0K(V)O", 'F'}, + {"0K(VO(", 'F'}, + {"0K(VOF", 'F'}, + {"0K(VOS", 'F'}, + {"0K1,(1", 'F'}, + {"0K1,(F", 'F'}, + {"0K1,(N", 'F'}, + {"0K1,(S", 'F'}, + {"0K1,(V", 'F'}, + {"0K1,F(", 'F'}, + {"0K1A(F", 'F'}, + {"0K1A(N", 'F'}, + {"0K1A(S", 'F'}, + {"0K1A(V", 'F'}, + {"0K1AF(", 'F'}, + {"0K1ASO", 'F'}, + {"0K1AVO", 'F'}, + {"0K1K(1", 'F'}, + {"0K1K(F", 'F'}, + {"0K1K(N", 'F'}, + {"0K1K(S", 'F'}, + {"0K1K(V", 'F'}, + {"0K1K1O", 'F'}, + {"0K1K1U", 'F'}, + {"0K1KF(", 'F'}, + {"0K1KNU", 'F'}, + {"0K1KSO", 'F'}, + {"0K1KSU", 'F'}, + {"0K1KVO", 'F'}, + {"0K1KVU", 'F'}, + {"0K1O(1", 'F'}, + {"0K1O(F", 'F'}, + {"0K1O(N", 'F'}, + {"0K1O(S", 'F'}, + {"0K1O(V", 'F'}, + {"0K1OF(", 'F'}, + {"0K1OS(", 'F'}, + {"0K1OS,", 'F'}, + {"0K1OS1", 'F'}, + {"0K1OSA", 'F'}, + {"0K1OSF", 'F'}, + {"0K1OSK", 'F'}, + {"0K1OSV", 'F'}, + {"0K1OV(", 'F'}, + {"0K1OV,", 'F'}, + {"0K1OVA", 'F'}, + {"0K1OVF", 'F'}, + {"0K1OVK", 'F'}, + {"0K1OVO", 'F'}, + {"0K1OVS", 'F'}, + {"0KF(),", 'F'}, + {"0KF()A", 'F'}, + {"0KF()K", 'F'}, + {"0KF()O", 'F'}, + {"0KF(1)", 'F'}, + {"0KF(1O", 'F'}, + {"0KF(F(", 'F'}, + {"0KF(N)", 'F'}, + {"0KF(NO", 'F'}, + {"0KF(S)", 'F'}, + {"0KF(SO", 'F'}, + {"0KF(V)", 'F'}, + {"0KF(VO", 'F'}, + {"0KN,(1", 'F'}, + {"0KN,(F", 'F'}, + {"0KN,(N", 'F'}, + {"0KN,(S", 'F'}, + {"0KN,(V", 'F'}, + {"0KN,F(", 'F'}, + {"0KNA(F", 'F'}, + {"0KNA(N", 'F'}, + {"0KNA(S", 'F'}, + {"0KNA(V", 'F'}, + {"0KNAF(", 'F'}, + {"0KNASO", 'F'}, + {"0KNAVO", 'F'}, + {"0KNK(1", 'F'}, + {"0KNK(F", 'F'}, + {"0KNK(N", 'F'}, + {"0KNK(S", 'F'}, + {"0KNK(V", 'F'}, + {"0KNK1O", 'F'}, + {"0KNK1U", 'F'}, + {"0KNKF(", 'F'}, + {"0KNKNU", 'F'}, + {"0KNKSO", 'F'}, + {"0KNKSU", 'F'}, + {"0KNKVO", 'F'}, + {"0KNKVU", 'F'}, + {"0KS,(1", 'F'}, + {"0KS,(F", 'F'}, + {"0KS,(N", 'F'}, + {"0KS,(S", 'F'}, + {"0KS,(V", 'F'}, + {"0KS,F(", 'F'}, + {"0KSA(F", 'F'}, + {"0KSA(N", 'F'}, + {"0KSA(S", 'F'}, + {"0KSA(V", 'F'}, + {"0KSAF(", 'F'}, + {"0KSASO", 'F'}, + {"0KSAVO", 'F'}, + {"0KSK(1", 'F'}, + {"0KSK(F", 'F'}, + {"0KSK(N", 'F'}, + {"0KSK(S", 'F'}, + {"0KSK(V", 'F'}, + {"0KSK1O", 'F'}, + {"0KSK1U", 'F'}, + {"0KSKF(", 'F'}, + {"0KSKNU", 'F'}, + {"0KSKSO", 'F'}, + {"0KSKSU", 'F'}, + {"0KSKVO", 'F'}, + {"0KSKVU", 'F'}, + {"0KSO(1", 'F'}, + {"0KSO(F", 'F'}, + {"0KSO(N", 'F'}, + {"0KSO(S", 'F'}, + {"0KSO(V", 'F'}, + {"0KSO1(", 'F'}, + {"0KSO1,", 'F'}, + {"0KSO1A", 'F'}, + {"0KSO1F", 'F'}, + {"0KSO1K", 'F'}, + {"0KSO1N", 'F'}, + {"0KSO1S", 'F'}, + {"0KSO1V", 'F'}, + {"0KSOF(", 'F'}, + {"0KSON(", 'F'}, + {"0KSON,", 'F'}, + {"0KSON1", 'F'}, + {"0KSONA", 'F'}, + {"0KSONF", 'F'}, + {"0KSONK", 'F'}, + {"0KSOS(", 'F'}, + {"0KSOS,", 'F'}, + {"0KSOS1", 'F'}, + {"0KSOSA", 'F'}, + {"0KSOSF", 'F'}, + {"0KSOSK", 'F'}, + {"0KSOSV", 'F'}, + {"0KSOV(", 'F'}, + {"0KSOV,", 'F'}, + {"0KSOVA", 'F'}, + {"0KSOVF", 'F'}, + {"0KSOVK", 'F'}, + {"0KSOVO", 'F'}, + {"0KSOVS", 'F'}, + {"0KV,(1", 'F'}, + {"0KV,(F", 'F'}, + {"0KV,(N", 'F'}, + {"0KV,(S", 'F'}, + {"0KV,(V", 'F'}, + {"0KV,F(", 'F'}, + {"0KVA(F", 'F'}, + {"0KVA(N", 'F'}, + {"0KVA(S", 'F'}, + {"0KVA(V", 'F'}, + {"0KVAF(", 'F'}, + {"0KVASO", 'F'}, + {"0KVAVO", 'F'}, + {"0KVK(1", 'F'}, + {"0KVK(F", 'F'}, + {"0KVK(N", 'F'}, + {"0KVK(S", 'F'}, + {"0KVK(V", 'F'}, + {"0KVK1O", 'F'}, + {"0KVK1U", 'F'}, + {"0KVKF(", 'F'}, + {"0KVKNU", 'F'}, + {"0KVKSO", 'F'}, + {"0KVKSU", 'F'}, + {"0KVKVO", 'F'}, + {"0KVKVU", 'F'}, + {"0KVO(1", 'F'}, + {"0KVO(F", 'F'}, + {"0KVO(N", 'F'}, + {"0KVO(S", 'F'}, + {"0KVO(V", 'F'}, + {"0KVOF(", 'F'}, + {"0KVOS(", 'F'}, + {"0KVOS,", 'F'}, + {"0KVOS1", 'F'}, + {"0KVOSA", 'F'}, + {"0KVOSF", 'F'}, + {"0KVOSK", 'F'}, + {"0KVOSV", 'F'}, + {"0N&(1&", 'F'}, + {"0N&(1)", 'F'}, + {"0N&(1,", 'F'}, + {"0N&(1O", 'F'}, + {"0N&(E(", 'F'}, + {"0N&(E1", 'F'}, + {"0N&(EF", 'F'}, + {"0N&(EK", 'F'}, + {"0N&(EN", 'F'}, + {"0N&(EO", 'F'}, + {"0N&(ES", 'F'}, + {"0N&(EV", 'F'}, + {"0N&(F(", 'F'}, + {"0N&(N&", 'F'}, + {"0N&(N)", 'F'}, + {"0N&(N,", 'F'}, + {"0N&(NO", 'F'}, + {"0N&(S&", 'F'}, + {"0N&(S)", 'F'}, + {"0N&(S,", 'F'}, + {"0N&(SO", 'F'}, + {"0N&(V&", 'F'}, + {"0N&(V)", 'F'}, + {"0N&(V,", 'F'}, + {"0N&(VO", 'F'}, + {"0N&1", 'F'}, + {"0N&1&(", 'F'}, + {"0N&1&1", 'F'}, + {"0N&1&F", 'F'}, + {"0N&1&N", 'F'}, + {"0N&1&S", 'F'}, + {"0N&1&V", 'F'}, + {"0N&1)&", 'F'}, + {"0N&1)C", 'F'}, + {"0N&1)O", 'F'}, + {"0N&1)U", 'F'}, + {"0N&1;", 'F'}, + {"0N&1;C", 'F'}, + {"0N&1;E", 'F'}, + {"0N&1;T", 'F'}, + {"0N&1B(", 'F'}, + {"0N&1B1", 'F'}, + {"0N&1BF", 'F'}, + {"0N&1BN", 'F'}, + {"0N&1BS", 'F'}, + {"0N&1BV", 'F'}, + {"0N&1C", 'F'}, + {"0N&1EK", 'F'}, + {"0N&1EN", 'F'}, + {"0N&1F(", 'F'}, + {"0N&1K(", 'F'}, + {"0N&1K1", 'F'}, + {"0N&1KF", 'F'}, + {"0N&1KN", 'F'}, + {"0N&1KS", 'F'}, + {"0N&1KV", 'F'}, + {"0N&1O(", 'F'}, + {"0N&1OF", 'F'}, + {"0N&1OS", 'F'}, + {"0N&1OV", 'F'}, + {"0N&1TN", 'F'}, + {"0N&1U", 'F'}, + {"0N&1U(", 'F'}, + {"0N&1U;", 'F'}, + {"0N&1UC", 'F'}, + {"0N&1UE", 'F'}, + {"0N&E(1", 'F'}, + {"0N&E(F", 'F'}, + {"0N&E(N", 'F'}, + {"0N&E(O", 'F'}, + {"0N&E(S", 'F'}, + {"0N&E(V", 'F'}, + {"0N&E1", 'F'}, + {"0N&E1;", 'F'}, + {"0N&E1C", 'F'}, + {"0N&E1K", 'F'}, + {"0N&E1O", 'F'}, + {"0N&EF(", 'F'}, + {"0N&EK(", 'F'}, + {"0N&EK1", 'F'}, + {"0N&EKF", 'F'}, + {"0N&EKN", 'F'}, + {"0N&EKS", 'F'}, + {"0N&EKV", 'F'}, + {"0N&EN;", 'F'}, + {"0N&ENC", 'F'}, + {"0N&ENK", 'F'}, + {"0N&ENO", 'F'}, + {"0N&ES", 'F'}, + {"0N&ES;", 'F'}, + {"0N&ESC", 'F'}, + {"0N&ESK", 'F'}, + {"0N&ESO", 'F'}, + {"0N&EV", 'F'}, + {"0N&EV;", 'F'}, + {"0N&EVC", 'F'}, + {"0N&EVK", 'F'}, + {"0N&EVO", 'F'}, + {"0N&F()", 'F'}, + {"0N&F(1", 'F'}, + {"0N&F(E", 'F'}, + {"0N&F(F", 'F'}, + {"0N&F(N", 'F'}, + {"0N&F(S", 'F'}, + {"0N&F(V", 'F'}, + {"0N&K&(", 'F'}, + {"0N&K&1", 'F'}, + {"0N&K&F", 'F'}, + {"0N&K&N", 'F'}, + {"0N&K&S", 'F'}, + {"0N&K&V", 'F'}, + {"0N&K(1", 'F'}, + {"0N&K(F", 'F'}, + {"0N&K(N", 'F'}, + {"0N&K(S", 'F'}, + {"0N&K(V", 'F'}, + {"0N&K1O", 'F'}, + {"0N&KC", 'F'}, + {"0N&KF(", 'F'}, + {"0N&KNK", 'F'}, + {"0N&KO(", 'F'}, + {"0N&KO1", 'F'}, + {"0N&KOF", 'F'}, + {"0N&KOK", 'F'}, + {"0N&KON", 'F'}, + {"0N&KOS", 'F'}, + {"0N&KOV", 'F'}, + {"0N&KSO", 'F'}, + {"0N&KVO", 'F'}, + {"0N&N&(", 'F'}, + {"0N&N&1", 'F'}, + {"0N&N&F", 'F'}, + {"0N&N&S", 'F'}, + {"0N&N&V", 'F'}, + {"0N&N)&", 'F'}, + {"0N&N)C", 'F'}, + {"0N&N)O", 'F'}, + {"0N&N)U", 'F'}, + {"0N&N;C", 'F'}, + {"0N&N;E", 'F'}, + {"0N&N;T", 'F'}, + {"0N&NB(", 'F'}, + {"0N&NB1", 'F'}, + {"0N&NBF", 'F'}, + {"0N&NBS", 'F'}, + {"0N&NBV", 'F'}, + {"0N&NF(", 'F'}, + {"0N&NK(", 'F'}, + {"0N&NK1", 'F'}, + {"0N&NKF", 'F'}, + {"0N&NKS", 'F'}, + {"0N&NKV", 'F'}, + {"0N&NO(", 'F'}, + {"0N&NOF", 'F'}, + {"0N&NOS", 'F'}, + {"0N&NOV", 'F'}, + {"0N&NU", 'F'}, + {"0N&NU(", 'F'}, + {"0N&NU;", 'F'}, + {"0N&NUC", 'F'}, + {"0N&NUE", 'F'}, + {"0N&S&(", 'F'}, + {"0N&S&1", 'F'}, + {"0N&S&F", 'F'}, + {"0N&S&N", 'F'}, + {"0N&S&S", 'F'}, + {"0N&S&V", 'F'}, + {"0N&S)&", 'F'}, + {"0N&S)C", 'F'}, + {"0N&S)O", 'F'}, + {"0N&S)U", 'F'}, + {"0N&S1", 'F'}, + {"0N&S1;", 'F'}, + {"0N&S1C", 'F'}, + {"0N&S;", 'F'}, + {"0N&S;C", 'F'}, + {"0N&S;E", 'F'}, + {"0N&S;T", 'F'}, + {"0N&SB(", 'F'}, + {"0N&SB1", 'F'}, + {"0N&SBF", 'F'}, + {"0N&SBN", 'F'}, + {"0N&SBS", 'F'}, + {"0N&SBV", 'F'}, + {"0N&SC", 'F'}, + {"0N&SEK", 'F'}, + {"0N&SEN", 'F'}, + {"0N&SF(", 'F'}, + {"0N&SK(", 'F'}, + {"0N&SK1", 'F'}, + {"0N&SKF", 'F'}, + {"0N&SKN", 'F'}, + {"0N&SKS", 'F'}, + {"0N&SKV", 'F'}, + {"0N&SO(", 'F'}, + {"0N&SO1", 'F'}, + {"0N&SOF", 'F'}, + {"0N&SON", 'F'}, + {"0N&SOS", 'F'}, + {"0N&SOV", 'F'}, + {"0N&STN", 'F'}, + {"0N&SU", 'F'}, + {"0N&SU(", 'F'}, + {"0N&SU;", 'F'}, + {"0N&SUC", 'F'}, + {"0N&SUE", 'F'}, + {"0N&SV", 'F'}, + {"0N&SV;", 'F'}, + {"0N&SVC", 'F'}, + {"0N&SVO", 'F'}, + {"0N&V", 'F'}, + {"0N&V&(", 'F'}, + {"0N&V&1", 'F'}, + {"0N&V&F", 'F'}, + {"0N&V&N", 'F'}, + {"0N&V&S", 'F'}, + {"0N&V&V", 'F'}, + {"0N&V)&", 'F'}, + {"0N&V)C", 'F'}, + {"0N&V)O", 'F'}, + {"0N&V)U", 'F'}, + {"0N&V;", 'F'}, + {"0N&V;C", 'F'}, + {"0N&V;E", 'F'}, + {"0N&V;T", 'F'}, + {"0N&VB(", 'F'}, + {"0N&VB1", 'F'}, + {"0N&VBF", 'F'}, + {"0N&VBN", 'F'}, + {"0N&VBS", 'F'}, + {"0N&VBV", 'F'}, + {"0N&VC", 'F'}, + {"0N&VEK", 'F'}, + {"0N&VEN", 'F'}, + {"0N&VF(", 'F'}, + {"0N&VK(", 'F'}, + {"0N&VK1", 'F'}, + {"0N&VKF", 'F'}, + {"0N&VKN", 'F'}, + {"0N&VKS", 'F'}, + {"0N&VKV", 'F'}, + {"0N&VO(", 'F'}, + {"0N&VOF", 'F'}, + {"0N&VOS", 'F'}, + {"0N&VS", 'F'}, + {"0N&VS;", 'F'}, + {"0N&VSC", 'F'}, + {"0N&VSO", 'F'}, + {"0N&VTN", 'F'}, + {"0N&VU", 'F'}, + {"0N&VU(", 'F'}, + {"0N&VU;", 'F'}, + {"0N&VUC", 'F'}, + {"0N&VUE", 'F'}, + {"0N)&(1", 'F'}, + {"0N)&(E", 'F'}, + {"0N)&(F", 'F'}, + {"0N)&(N", 'F'}, + {"0N)&(S", 'F'}, + {"0N)&(V", 'F'}, + {"0N)&1", 'F'}, + {"0N)&1&", 'F'}, + {"0N)&1)", 'F'}, + {"0N)&1;", 'F'}, + {"0N)&1B", 'F'}, + {"0N)&1C", 'F'}, + {"0N)&1F", 'F'}, + {"0N)&1O", 'F'}, + {"0N)&1U", 'F'}, + {"0N)&F(", 'F'}, + {"0N)&N", 'F'}, + {"0N)&N&", 'F'}, + {"0N)&N)", 'F'}, + {"0N)&N;", 'F'}, + {"0N)&NB", 'F'}, + {"0N)&NC", 'F'}, + {"0N)&NF", 'F'}, + {"0N)&NO", 'F'}, + {"0N)&NU", 'F'}, + {"0N)&S", 'F'}, + {"0N)&S&", 'F'}, + {"0N)&S)", 'F'}, + {"0N)&S;", 'F'}, + {"0N)&SB", 'F'}, + {"0N)&SC", 'F'}, + {"0N)&SF", 'F'}, + {"0N)&SO", 'F'}, + {"0N)&SU", 'F'}, + {"0N)&V", 'F'}, + {"0N)&V&", 'F'}, + {"0N)&V)", 'F'}, + {"0N)&V;", 'F'}, + {"0N)&VB", 'F'}, + {"0N)&VC", 'F'}, + {"0N)&VF", 'F'}, + {"0N)&VO", 'F'}, + {"0N)&VU", 'F'}, + {"0N),(1", 'F'}, + {"0N),(F", 'F'}, + {"0N),(N", 'F'}, + {"0N),(S", 'F'}, + {"0N),(V", 'F'}, + {"0N);E(", 'F'}, + {"0N);E1", 'F'}, + {"0N);EF", 'F'}, + {"0N);EK", 'F'}, + {"0N);EN", 'F'}, + {"0N);EO", 'F'}, + {"0N);ES", 'F'}, + {"0N);EV", 'F'}, + {"0N);T(", 'F'}, + {"0N);T1", 'F'}, + {"0N);TF", 'F'}, + {"0N);TK", 'F'}, + {"0N);TN", 'F'}, + {"0N);TO", 'F'}, + {"0N);TS", 'F'}, + {"0N);TV", 'F'}, + {"0N)B(1", 'F'}, + {"0N)B(F", 'F'}, + {"0N)B(N", 'F'}, + {"0N)B(S", 'F'}, + {"0N)B(V", 'F'}, + {"0N)B1", 'F'}, + {"0N)B1&", 'F'}, + {"0N)B1;", 'F'}, + {"0N)B1C", 'F'}, + {"0N)B1K", 'F'}, + {"0N)B1N", 'F'}, + {"0N)B1O", 'F'}, + {"0N)B1U", 'F'}, + {"0N)BF(", 'F'}, + {"0N)BN", 'F'}, + {"0N)BN&", 'F'}, + {"0N)BN;", 'F'}, + {"0N)BNC", 'F'}, + {"0N)BNK", 'F'}, + {"0N)BNO", 'F'}, + {"0N)BNU", 'F'}, + {"0N)BS", 'F'}, + {"0N)BS&", 'F'}, + {"0N)BS;", 'F'}, + {"0N)BSC", 'F'}, + {"0N)BSK", 'F'}, + {"0N)BSO", 'F'}, + {"0N)BSU", 'F'}, + {"0N)BV", 'F'}, + {"0N)BV&", 'F'}, + {"0N)BV;", 'F'}, + {"0N)BVC", 'F'}, + {"0N)BVK", 'F'}, + {"0N)BVO", 'F'}, + {"0N)BVU", 'F'}, + {"0N)E(1", 'F'}, + {"0N)E(F", 'F'}, + {"0N)E(N", 'F'}, + {"0N)E(S", 'F'}, + {"0N)E(V", 'F'}, + {"0N)E1C", 'F'}, + {"0N)E1O", 'F'}, + {"0N)EF(", 'F'}, + {"0N)EK(", 'F'}, + {"0N)EK1", 'F'}, + {"0N)EKF", 'F'}, + {"0N)EKN", 'F'}, + {"0N)EKS", 'F'}, + {"0N)EKV", 'F'}, + {"0N)ENC", 'F'}, + {"0N)ENO", 'F'}, + {"0N)ESC", 'F'}, + {"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'}, + {"0N)K(S", 'F'}, + {"0N)K(V", 'F'}, + {"0N)K1&", 'F'}, + {"0N)K1;", 'F'}, + {"0N)K1B", 'F'}, + {"0N)K1E", 'F'}, + {"0N)K1O", 'F'}, + {"0N)K1U", 'F'}, + {"0N)KB(", 'F'}, + {"0N)KB1", 'F'}, + {"0N)KBF", 'F'}, + {"0N)KBN", 'F'}, + {"0N)KBS", 'F'}, + {"0N)KBV", 'F'}, + {"0N)KF(", 'F'}, + {"0N)KN&", 'F'}, + {"0N)KN;", 'F'}, + {"0N)KNB", 'F'}, + {"0N)KNC", 'F'}, + {"0N)KNE", 'F'}, + {"0N)KNK", 'F'}, + {"0N)KNU", 'F'}, + {"0N)KS&", 'F'}, + {"0N)KS;", 'F'}, + {"0N)KSB", 'F'}, + {"0N)KSE", 'F'}, + {"0N)KSO", 'F'}, + {"0N)KSU", 'F'}, + {"0N)KUE", 'F'}, + {"0N)KV&", 'F'}, + {"0N)KV;", 'F'}, + {"0N)KVB", 'F'}, + {"0N)KVE", 'F'}, + {"0N)KVO", 'F'}, + {"0N)KVU", 'F'}, + {"0N)O(1", 'F'}, + {"0N)O(E", 'F'}, + {"0N)O(F", 'F'}, + {"0N)O(N", 'F'}, + {"0N)O(S", 'F'}, + {"0N)O(V", 'F'}, + {"0N)O1&", 'F'}, + {"0N)O1)", 'F'}, + {"0N)O1;", 'F'}, + {"0N)O1B", 'F'}, + {"0N)O1C", 'F'}, + {"0N)O1K", 'F'}, + {"0N)O1U", 'F'}, + {"0N)OF(", 'F'}, + {"0N)ON&", 'F'}, + {"0N)ON)", 'F'}, + {"0N)ON;", 'F'}, + {"0N)ONB", 'F'}, + {"0N)ONC", 'F'}, + {"0N)ONK", 'F'}, + {"0N)ONU", 'F'}, + {"0N)OS", 'F'}, + {"0N)OS&", 'F'}, + {"0N)OS)", 'F'}, + {"0N)OS;", 'F'}, + {"0N)OSB", 'F'}, + {"0N)OSC", 'F'}, + {"0N)OSK", 'F'}, + {"0N)OSU", 'F'}, + {"0N)OV", 'F'}, + {"0N)OV&", 'F'}, + {"0N)OV)", 'F'}, + {"0N)OV;", 'F'}, + {"0N)OVB", 'F'}, + {"0N)OVC", 'F'}, + {"0N)OVK", 'F'}, + {"0N)OVO", 'F'}, + {"0N)OVU", 'F'}, + {"0N)U(E", 'F'}, + {"0N)UE(", 'F'}, + {"0N)UE1", 'F'}, + {"0N)UEF", 'F'}, + {"0N)UEK", 'F'}, + {"0N)UEN", 'F'}, + {"0N)UES", 'F'}, + {"0N)UEV", 'F'}, + {"0N,(1)", 'F'}, + {"0N,(1O", 'F'}, + {"0N,(E(", 'F'}, + {"0N,(E1", 'F'}, + {"0N,(EF", 'F'}, + {"0N,(EK", 'F'}, + {"0N,(EN", 'F'}, + {"0N,(ES", 'F'}, + {"0N,(EV", 'F'}, + {"0N,(F(", 'F'}, + {"0N,(NO", 'F'}, + {"0N,(S)", 'F'}, + {"0N,(SO", 'F'}, + {"0N,(V)", 'F'}, + {"0N,(VO", 'F'}, + {"0N,F()", 'F'}, + {"0N,F(1", 'F'}, + {"0N,F(F", 'F'}, + {"0N,F(N", 'F'}, + {"0N,F(S", 'F'}, + {"0N,F(V", 'F'}, + {"0N1O(1", 'F'}, + {"0N1O(F", 'F'}, + {"0N1O(N", 'F'}, + {"0N1O(S", 'F'}, + {"0N1O(V", 'F'}, + {"0N1OF(", 'F'}, + {"0N1OS(", 'F'}, + {"0N1OS1", 'F'}, + {"0N1OSF", 'F'}, + {"0N1OSU", 'F'}, + {"0N1OSV", 'F'}, + {"0N1OV(", 'F'}, + {"0N1OVF", 'F'}, + {"0N1OVO", 'F'}, + {"0N1OVS", 'F'}, + {"0N1OVU", 'F'}, + {"0N1S;", 'F'}, + {"0N1S;C", 'F'}, + {"0N1SC", 'F'}, + {"0N1UE", 'F'}, + {"0N1UE;", 'F'}, + {"0N1UEC", 'F'}, + {"0N1UEK", 'F'}, + {"0N1V;", 'F'}, + {"0N1V;C", 'F'}, + {"0N1VC", 'F'}, + {"0N1VO(", 'F'}, + {"0N1VOF", 'F'}, + {"0N1VOS", 'F'}, + {"0N;E(1", 'F'}, + {"0N;E(E", 'F'}, + {"0N;E(F", 'F'}, + {"0N;E(N", 'F'}, + {"0N;E(S", 'F'}, + {"0N;E(V", 'F'}, + {"0N;E1,", 'F'}, + {"0N;E1;", 'F'}, + {"0N;E1C", 'F'}, + {"0N;E1K", 'F'}, + {"0N;E1O", 'F'}, + {"0N;E1T", 'F'}, + {"0N;EF(", 'F'}, + {"0N;EK(", 'F'}, + {"0N;EK1", 'F'}, + {"0N;EKF", 'F'}, + {"0N;EKN", 'F'}, + {"0N;EKO", 'F'}, + {"0N;EKS", 'F'}, + {"0N;EKV", 'F'}, + {"0N;EN,", 'F'}, + {"0N;EN;", 'F'}, + {"0N;ENC", 'F'}, + {"0N;ENE", 'F'}, + {"0N;ENK", 'F'}, + {"0N;ENO", 'F'}, + {"0N;ENT", 'F'}, + {"0N;ES,", 'F'}, + {"0N;ES;", 'F'}, + {"0N;ESC", 'F'}, + {"0N;ESK", 'F'}, + {"0N;ESO", 'F'}, + {"0N;EST", 'F'}, + {"0N;EV,", 'F'}, + {"0N;EV;", 'F'}, + {"0N;EVC", 'F'}, + {"0N;EVK", 'F'}, + {"0N;EVO", 'F'}, + {"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'}, + {"0N;T1F", 'F'}, + {"0N;T1K", 'F'}, + {"0N;T1O", 'F'}, + {"0N;T1T", 'F'}, + {"0N;T;", 'F'}, + {"0N;T;C", 'F'}, + {"0N;TF(", 'F'}, + {"0N;TK(", 'F'}, + {"0N;TK1", 'F'}, + {"0N;TKF", 'F'}, + {"0N;TKK", 'F'}, + {"0N;TKO", 'F'}, + {"0N;TKS", 'F'}, + {"0N;TKV", 'F'}, + {"0N;TN(", 'F'}, + {"0N;TN,", 'F'}, + {"0N;TN1", 'F'}, + {"0N;TN;", 'F'}, + {"0N;TNC", 'F'}, + {"0N;TNE", 'F'}, + {"0N;TNF", 'F'}, + {"0N;TNK", 'F'}, + {"0N;TNN", 'F'}, + {"0N;TNO", 'F'}, + {"0N;TNS", 'F'}, + {"0N;TNT", 'F'}, + {"0N;TNV", 'F'}, + {"0N;TO(", 'F'}, + {"0N;TS(", 'F'}, + {"0N;TS,", 'F'}, + {"0N;TS;", 'F'}, + {"0N;TSC", 'F'}, + {"0N;TSF", 'F'}, + {"0N;TSK", 'F'}, + {"0N;TSO", 'F'}, + {"0N;TST", 'F'}, + {"0N;TTN", 'F'}, + {"0N;TV(", 'F'}, + {"0N;TV,", 'F'}, + {"0N;TV;", 'F'}, + {"0N;TVC", 'F'}, + {"0N;TVF", 'F'}, + {"0N;TVK", 'F'}, + {"0N;TVO", 'F'}, + {"0N;TVT", 'F'}, + {"0NA(F(", 'F'}, + {"0NA(N)", 'F'}, + {"0NA(NO", 'F'}, + {"0NA(S)", 'F'}, + {"0NA(SO", 'F'}, + {"0NA(V)", 'F'}, + {"0NA(VO", 'F'}, + {"0NAF()", 'F'}, + {"0NAF(1", 'F'}, + {"0NAF(F", 'F'}, + {"0NAF(N", 'F'}, + {"0NAF(S", 'F'}, + {"0NAF(V", 'F'}, + {"0NASO(", 'F'}, + {"0NASO1", 'F'}, + {"0NASOF", 'F'}, + {"0NASON", 'F'}, + {"0NASOS", 'F'}, + {"0NASOV", 'F'}, + {"0NASUE", 'F'}, + {"0NATO(", 'F'}, + {"0NATO1", 'F'}, + {"0NATOF", 'F'}, + {"0NATON", 'F'}, + {"0NATOS", 'F'}, + {"0NATOV", 'F'}, + {"0NATUE", 'F'}, + {"0NAVO(", 'F'}, + {"0NAVOF", 'F'}, + {"0NAVOS", 'F'}, + {"0NAVUE", 'F'}, + {"0NB(1&", 'F'}, + {"0NB(1)", 'F'}, + {"0NB(1O", 'F'}, + {"0NB(F(", 'F'}, + {"0NB(N&", 'F'}, + {"0NB(NO", 'F'}, + {"0NB(S&", 'F'}, + {"0NB(S)", 'F'}, + {"0NB(SO", 'F'}, + {"0NB(V&", 'F'}, + {"0NB(V)", 'F'}, + {"0NB(VO", 'F'}, + {"0NB1", 'F'}, + {"0NB1&(", 'F'}, + {"0NB1&1", 'F'}, + {"0NB1&F", 'F'}, + {"0NB1&N", 'F'}, + {"0NB1&S", 'F'}, + {"0NB1&V", 'F'}, + {"0NB1,(", 'F'}, + {"0NB1,F", 'F'}, + {"0NB1;", 'F'}, + {"0NB1;C", 'F'}, + {"0NB1B(", 'F'}, + {"0NB1B1", 'F'}, + {"0NB1BF", 'F'}, + {"0NB1BN", 'F'}, + {"0NB1BS", 'F'}, + {"0NB1BV", 'F'}, + {"0NB1C", 'F'}, + {"0NB1K(", 'F'}, + {"0NB1K1", 'F'}, + {"0NB1KF", 'F'}, + {"0NB1KN", 'F'}, + {"0NB1KS", 'F'}, + {"0NB1KV", 'F'}, + {"0NB1O(", 'F'}, + {"0NB1OF", 'F'}, + {"0NB1OS", 'F'}, + {"0NB1OV", 'F'}, + {"0NB1U(", 'F'}, + {"0NB1UE", 'F'}, + {"0NBE(1", 'F'}, + {"0NBE(F", 'F'}, + {"0NBE(N", 'F'}, + {"0NBE(S", 'F'}, + {"0NBE(V", 'F'}, + {"0NBEK(", 'F'}, + {"0NBF()", 'F'}, + {"0NBF(1", 'F'}, + {"0NBF(F", 'F'}, + {"0NBF(N", 'F'}, + {"0NBF(S", 'F'}, + {"0NBF(V", 'F'}, + {"0NBN&(", 'F'}, + {"0NBN&1", 'F'}, + {"0NBN&F", 'F'}, + {"0NBN&N", 'F'}, + {"0NBN&S", 'F'}, + {"0NBN&V", 'F'}, + {"0NBN,(", 'F'}, + {"0NBN,F", 'F'}, + {"0NBN;", 'F'}, + {"0NBN;C", 'F'}, + {"0NBNB(", 'F'}, + {"0NBNB1", 'F'}, + {"0NBNBF", 'F'}, + {"0NBNBN", 'F'}, + {"0NBNBS", 'F'}, + {"0NBNBV", 'F'}, + {"0NBNC", 'F'}, + {"0NBNK(", 'F'}, + {"0NBNK1", 'F'}, + {"0NBNKF", 'F'}, + {"0NBNKN", 'F'}, + {"0NBNKS", 'F'}, + {"0NBNKV", 'F'}, + {"0NBNO(", 'F'}, + {"0NBNOF", 'F'}, + {"0NBNOS", 'F'}, + {"0NBNOV", 'F'}, + {"0NBNU(", 'F'}, + {"0NBNUE", 'F'}, + {"0NBS", 'F'}, + {"0NBS&(", 'F'}, + {"0NBS&1", 'F'}, + {"0NBS&F", 'F'}, + {"0NBS&N", 'F'}, + {"0NBS&S", 'F'}, + {"0NBS&V", 'F'}, + {"0NBS,(", 'F'}, + {"0NBS,F", 'F'}, + {"0NBS;", 'F'}, + {"0NBS;C", 'F'}, + {"0NBSB(", 'F'}, + {"0NBSB1", 'F'}, + {"0NBSBF", 'F'}, + {"0NBSBN", 'F'}, + {"0NBSBS", 'F'}, + {"0NBSBV", 'F'}, + {"0NBSC", 'F'}, + {"0NBSK(", 'F'}, + {"0NBSK1", 'F'}, + {"0NBSKF", 'F'}, + {"0NBSKN", 'F'}, + {"0NBSKS", 'F'}, + {"0NBSKV", 'F'}, + {"0NBSO(", 'F'}, + {"0NBSO1", 'F'}, + {"0NBSOF", 'F'}, + {"0NBSON", 'F'}, + {"0NBSOS", 'F'}, + {"0NBSOV", 'F'}, + {"0NBSU(", 'F'}, + {"0NBSUE", 'F'}, + {"0NBV", 'F'}, + {"0NBV&(", 'F'}, + {"0NBV&1", 'F'}, + {"0NBV&F", 'F'}, + {"0NBV&N", 'F'}, + {"0NBV&S", 'F'}, + {"0NBV&V", 'F'}, + {"0NBV,(", 'F'}, + {"0NBV,F", 'F'}, + {"0NBV;", 'F'}, + {"0NBV;C", 'F'}, + {"0NBVB(", 'F'}, + {"0NBVB1", 'F'}, + {"0NBVBF", 'F'}, + {"0NBVBN", 'F'}, + {"0NBVBS", 'F'}, + {"0NBVBV", 'F'}, + {"0NBVC", 'F'}, + {"0NBVK(", 'F'}, + {"0NBVK1", 'F'}, + {"0NBVKF", 'F'}, + {"0NBVKN", 'F'}, + {"0NBVKS", 'F'}, + {"0NBVKV", 'F'}, + {"0NBVO(", 'F'}, + {"0NBVOF", 'F'}, + {"0NBVOS", 'F'}, + {"0NBVU(", 'F'}, + {"0NBVUE", 'F'}, + {"0NC", 'F'}, + {"0NE(1)", 'F'}, + {"0NE(1O", 'F'}, + {"0NE(F(", 'F'}, + {"0NE(N)", 'F'}, + {"0NE(NO", 'F'}, + {"0NE(S)", 'F'}, + {"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'}, + {"0NEF(F", 'F'}, + {"0NEF(N", 'F'}, + {"0NEF(S", 'F'}, + {"0NEF(V", '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'}, + {"0NESOF", 'F'}, + {"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'}, + {"0NEU(N", 'F'}, + {"0NEU(S", 'F'}, + {"0NEU(V", 'F'}, + {"0NEU1,", 'F'}, + {"0NEU1C", 'F'}, + {"0NEU1O", 'F'}, + {"0NEUEF", 'F'}, + {"0NEUEK", 'F'}, + {"0NEUF(", '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'}, + {"0NF()K", 'F'}, + {"0NF()N", 'F'}, + {"0NF()O", 'F'}, + {"0NF()S", 'F'}, + {"0NF()U", 'F'}, + {"0NF()V", 'F'}, + {"0NF(1)", 'F'}, + {"0NF(1O", 'F'}, + {"0NF(E(", 'F'}, + {"0NF(E1", 'F'}, + {"0NF(EF", 'F'}, + {"0NF(EK", 'F'}, + {"0NF(EN", 'F'}, + {"0NF(ES", 'F'}, + {"0NF(EV", 'F'}, + {"0NF(F(", 'F'}, + {"0NF(N,", 'F'}, + {"0NF(NO", 'F'}, + {"0NF(S)", 'F'}, + {"0NF(SO", 'F'}, + {"0NF(V)", 'F'}, + {"0NF(VO", 'F'}, + {"0NK(1)", 'F'}, + {"0NK(1O", 'F'}, + {"0NK(F(", 'F'}, + {"0NK(NO", 'F'}, + {"0NK(S)", 'F'}, + {"0NK(SO", 'F'}, + {"0NK(V)", 'F'}, + {"0NK(VO", 'F'}, + {"0NK)&(", 'F'}, + {"0NK)&1", 'F'}, + {"0NK)&F", 'F'}, + {"0NK)&N", 'F'}, + {"0NK)&S", 'F'}, + {"0NK)&V", 'F'}, + {"0NK);E", 'F'}, + {"0NK);T", 'F'}, + {"0NK)B(", 'F'}, + {"0NK)B1", 'F'}, + {"0NK)BF", 'F'}, + {"0NK)BN", 'F'}, + {"0NK)BS", 'F'}, + {"0NK)BV", 'F'}, + {"0NK)E(", 'F'}, + {"0NK)E1", 'F'}, + {"0NK)EF", 'F'}, + {"0NK)EK", 'F'}, + {"0NK)EN", 'F'}, + {"0NK)ES", 'F'}, + {"0NK)EV", 'F'}, + {"0NK)F(", 'F'}, + {"0NK)O(", 'F'}, + {"0NK)OF", 'F'}, + {"0NK)UE", 'F'}, + {"0NK1", 'F'}, + {"0NK1&(", 'F'}, + {"0NK1&1", 'F'}, + {"0NK1&F", 'F'}, + {"0NK1&N", 'F'}, + {"0NK1&S", 'F'}, + {"0NK1&V", 'F'}, + {"0NK1;C", 'F'}, + {"0NK1;E", 'F'}, + {"0NK1;T", 'F'}, + {"0NK1B(", 'F'}, + {"0NK1B1", 'F'}, + {"0NK1BF", 'F'}, + {"0NK1BN", 'F'}, + {"0NK1BS", 'F'}, + {"0NK1BV", 'F'}, + {"0NK1C", 'F'}, + {"0NK1E(", 'F'}, + {"0NK1E1", 'F'}, + {"0NK1EF", 'F'}, + {"0NK1EK", 'F'}, + {"0NK1EN", 'F'}, + {"0NK1ES", 'F'}, + {"0NK1EV", 'F'}, + {"0NK1O(", 'F'}, + {"0NK1OF", 'F'}, + {"0NK1OS", 'F'}, + {"0NK1OV", 'F'}, + {"0NK1U(", 'F'}, + {"0NK1UE", 'F'}, + {"0NKF()", 'F'}, + {"0NKF(1", 'F'}, + {"0NKF(F", 'F'}, + {"0NKF(N", 'F'}, + {"0NKF(S", 'F'}, + {"0NKF(V", 'F'}, + {"0NKN", 'F'}, + {"0NKN&(", 'F'}, + {"0NKN&1", 'F'}, + {"0NKN&F", 'F'}, + {"0NKN&S", 'F'}, + {"0NKN&V", 'F'}, + {"0NKN;C", 'F'}, + {"0NKN;E", 'F'}, + {"0NKN;T", 'F'}, + {"0NKNB(", 'F'}, + {"0NKNB1", 'F'}, + {"0NKNBF", 'F'}, + {"0NKNBN", 'F'}, + {"0NKNBS", 'F'}, + {"0NKNBV", 'F'}, + {"0NKNE(", 'F'}, + {"0NKNE1", 'F'}, + {"0NKNEF", 'F'}, + {"0NKNES", 'F'}, + {"0NKNEV", 'F'}, + {"0NKNU(", 'F'}, + {"0NKNUE", 'F'}, + {"0NKS", 'F'}, + {"0NKS&(", 'F'}, + {"0NKS&1", 'F'}, + {"0NKS&F", 'F'}, + {"0NKS&N", 'F'}, + {"0NKS&S", 'F'}, + {"0NKS&V", 'F'}, + {"0NKS;", 'F'}, + {"0NKS;C", 'F'}, + {"0NKS;E", 'F'}, + {"0NKS;T", 'F'}, + {"0NKSB(", 'F'}, + {"0NKSB1", 'F'}, + {"0NKSBF", 'F'}, + {"0NKSBN", 'F'}, + {"0NKSBS", 'F'}, + {"0NKSBV", 'F'}, + {"0NKSC", 'F'}, + {"0NKSE(", 'F'}, + {"0NKSE1", 'F'}, + {"0NKSEF", 'F'}, + {"0NKSEK", 'F'}, + {"0NKSEN", 'F'}, + {"0NKSES", 'F'}, + {"0NKSEV", 'F'}, + {"0NKSO(", 'F'}, + {"0NKSO1", 'F'}, + {"0NKSOF", 'F'}, + {"0NKSON", 'F'}, + {"0NKSOS", 'F'}, + {"0NKSOV", 'F'}, + {"0NKSU(", 'F'}, + {"0NKSUE", 'F'}, + {"0NKUE(", 'F'}, + {"0NKUE1", 'F'}, + {"0NKUEF", 'F'}, + {"0NKUEK", 'F'}, + {"0NKUEN", 'F'}, + {"0NKUES", 'F'}, + {"0NKUEV", 'F'}, + {"0NKV", 'F'}, + {"0NKV&(", 'F'}, + {"0NKV&1", 'F'}, + {"0NKV&F", 'F'}, + {"0NKV&N", 'F'}, + {"0NKV&S", 'F'}, + {"0NKV&V", 'F'}, + {"0NKV;", 'F'}, + {"0NKV;C", 'F'}, + {"0NKV;E", 'F'}, + {"0NKV;T", 'F'}, + {"0NKVB(", 'F'}, + {"0NKVB1", 'F'}, + {"0NKVBF", 'F'}, + {"0NKVBN", 'F'}, + {"0NKVBS", 'F'}, + {"0NKVBV", 'F'}, + {"0NKVC", 'F'}, + {"0NKVE(", 'F'}, + {"0NKVE1", 'F'}, + {"0NKVEF", 'F'}, + {"0NKVEK", 'F'}, + {"0NKVEN", 'F'}, + {"0NKVES", 'F'}, + {"0NKVEV", 'F'}, + {"0NKVO(", 'F'}, + {"0NKVOF", 'F'}, + {"0NKVOS", 'F'}, + {"0NKVU(", 'F'}, + {"0NKVUE", 'F'}, + {"0NO(1&", 'F'}, + {"0NO(1)", 'F'}, + {"0NO(1,", 'F'}, + {"0NO(1O", 'F'}, + {"0NO(E(", 'F'}, + {"0NO(E1", 'F'}, + {"0NO(EE", 'F'}, + {"0NO(EF", 'F'}, + {"0NO(EK", 'F'}, + {"0NO(EN", 'F'}, + {"0NO(EO", 'F'}, + {"0NO(ES", 'F'}, + {"0NO(EV", 'F'}, + {"0NO(F(", 'F'}, + {"0NO(N&", 'F'}, + {"0NO(N)", 'F'}, + {"0NO(N,", 'F'}, + {"0NO(NO", 'F'}, + {"0NO(S&", 'F'}, + {"0NO(S)", 'F'}, + {"0NO(S,", 'F'}, + {"0NO(SO", 'F'}, + {"0NO(V&", 'F'}, + {"0NO(V)", 'F'}, + {"0NO(V,", 'F'}, + {"0NO(VO", 'F'}, + {"0NOF()", 'F'}, + {"0NOF(1", 'F'}, + {"0NOF(E", 'F'}, + {"0NOF(F", 'F'}, + {"0NOF(N", 'F'}, + {"0NOF(S", 'F'}, + {"0NOF(V", 'F'}, + {"0NOK&(", 'F'}, + {"0NOK(1", 'F'}, + {"0NOK(F", 'F'}, + {"0NOK(N", 'F'}, + {"0NOK(S", 'F'}, + {"0NOK(V", 'F'}, + {"0NOK1C", 'F'}, + {"0NOK1O", 'F'}, + {"0NOKF(", 'F'}, + {"0NOKNC", 'F'}, + {"0NOKO(", 'F'}, + {"0NOKO1", 'F'}, + {"0NOKOF", 'F'}, + {"0NOKON", 'F'}, + {"0NOKOS", 'F'}, + {"0NOKOV", 'F'}, + {"0NOKSC", 'F'}, + {"0NOKSO", 'F'}, + {"0NOKVC", 'F'}, + {"0NOKVO", 'F'}, + {"0NONSU", 'F'}, + {"0NOS&(", 'F'}, + {"0NOS&1", 'F'}, + {"0NOS&E", 'F'}, + {"0NOS&F", 'F'}, + {"0NOS&K", 'F'}, + {"0NOS&N", 'F'}, + {"0NOS&S", 'F'}, + {"0NOS&U", 'F'}, + {"0NOS&V", 'F'}, + {"0NOS(E", 'F'}, + {"0NOS(U", 'F'}, + {"0NOS)&", 'F'}, + {"0NOS),", 'F'}, + {"0NOS);", 'F'}, + {"0NOS)B", 'F'}, + {"0NOS)C", 'F'}, + {"0NOS)E", 'F'}, + {"0NOS)F", 'F'}, + {"0NOS)K", 'F'}, + {"0NOS)O", 'F'}, + {"0NOS)U", 'F'}, + {"0NOS,(", 'F'}, + {"0NOS,F", 'F'}, + {"0NOS1(", 'F'}, + {"0NOS1F", 'F'}, + {"0NOS1N", 'F'}, + {"0NOS1S", 'F'}, + {"0NOS1U", 'F'}, + {"0NOS1V", 'F'}, + {"0NOS;", 'F'}, + {"0NOS;C", 'F'}, + {"0NOS;E", 'F'}, + {"0NOS;T", 'F'}, + {"0NOSA(", 'F'}, + {"0NOSAF", 'F'}, + {"0NOSAS", 'F'}, + {"0NOSAT", 'F'}, + {"0NOSAV", 'F'}, + {"0NOSB(", 'F'}, + {"0NOSB1", 'F'}, + {"0NOSBE", 'F'}, + {"0NOSBF", 'F'}, + {"0NOSBN", 'F'}, + {"0NOSBS", 'F'}, + {"0NOSBV", 'F'}, + {"0NOSC", 'F'}, + {"0NOSE(", 'F'}, + {"0NOSE1", 'F'}, + {"0NOSEF", 'F'}, + {"0NOSEK", 'F'}, + {"0NOSEN", 'F'}, + {"0NOSEO", 'F'}, + {"0NOSES", 'F'}, + {"0NOSEU", 'F'}, + {"0NOSEV", 'F'}, + {"0NOSF(", 'F'}, + {"0NOSK(", 'F'}, + {"0NOSK)", 'F'}, + {"0NOSK1", 'F'}, + {"0NOSKB", 'F'}, + {"0NOSKF", 'F'}, + {"0NOSKN", 'F'}, + {"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'}, + {"0NOSU;", 'F'}, + {"0NOSUC", 'F'}, + {"0NOSUE", 'F'}, + {"0NOSUF", 'F'}, + {"0NOSUK", 'F'}, + {"0NOSUO", 'F'}, + {"0NOSUS", 'F'}, + {"0NOSUT", 'F'}, + {"0NOSUV", 'F'}, + {"0NOSV(", 'F'}, + {"0NOSVF", 'F'}, + {"0NOSVO", 'F'}, + {"0NOSVS", 'F'}, + {"0NOSVU", 'F'}, + {"0NOU(E", 'F'}, + {"0NOUEK", 'F'}, + {"0NOUEN", 'F'}, + {"0NOV&(", 'F'}, + {"0NOV&1", 'F'}, + {"0NOV&E", 'F'}, + {"0NOV&F", 'F'}, + {"0NOV&K", 'F'}, + {"0NOV&N", 'F'}, + {"0NOV&S", 'F'}, + {"0NOV&U", 'F'}, + {"0NOV&V", 'F'}, + {"0NOV(E", 'F'}, + {"0NOV(U", 'F'}, + {"0NOV)&", 'F'}, + {"0NOV),", 'F'}, + {"0NOV);", 'F'}, + {"0NOV)B", 'F'}, + {"0NOV)C", 'F'}, + {"0NOV)E", 'F'}, + {"0NOV)F", 'F'}, + {"0NOV)K", 'F'}, + {"0NOV)O", 'F'}, + {"0NOV)U", 'F'}, + {"0NOV,(", 'F'}, + {"0NOV,F", 'F'}, + {"0NOV;", 'F'}, + {"0NOV;C", 'F'}, + {"0NOV;E", 'F'}, + {"0NOV;N", 'F'}, + {"0NOV;T", 'F'}, + {"0NOVA(", 'F'}, + {"0NOVAF", 'F'}, + {"0NOVAS", 'F'}, + {"0NOVAT", 'F'}, + {"0NOVAV", 'F'}, + {"0NOVB(", 'F'}, + {"0NOVB1", 'F'}, + {"0NOVBE", 'F'}, + {"0NOVBF", 'F'}, + {"0NOVBN", 'F'}, + {"0NOVBS", 'F'}, + {"0NOVBV", 'F'}, + {"0NOVC", 'F'}, + {"0NOVE(", 'F'}, + {"0NOVE1", 'F'}, + {"0NOVEF", 'F'}, + {"0NOVEK", 'F'}, + {"0NOVEN", 'F'}, + {"0NOVEO", 'F'}, + {"0NOVES", 'F'}, + {"0NOVEU", 'F'}, + {"0NOVEV", 'F'}, + {"0NOVF(", 'F'}, + {"0NOVK(", 'F'}, + {"0NOVK)", 'F'}, + {"0NOVK1", 'F'}, + {"0NOVKB", 'F'}, + {"0NOVKF", 'F'}, + {"0NOVKN", 'F'}, + {"0NOVKS", 'F'}, + {"0NOVKU", 'F'}, + {"0NOVKV", 'F'}, + {"0NOVO(", 'F'}, + {"0NOVOF", 'F'}, + {"0NOVOK", 'F'}, + {"0NOVOS", 'F'}, + {"0NOVOU", 'F'}, + {"0NOVS(", 'F'}, + {"0NOVS1", 'F'}, + {"0NOVSF", 'F'}, + {"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'}, + {"0NOVU;", 'F'}, + {"0NOVUC", 'F'}, + {"0NOVUE", 'F'}, + {"0NOVUF", 'F'}, + {"0NOVUK", 'F'}, + {"0NOVUO", 'F'}, + {"0NOVUS", 'F'}, + {"0NOVUT", 'F'}, + {"0NOVUV", 'F'}, + {"0NSO1U", 'F'}, + {"0NSONU", 'F'}, + {"0NSOSU", 'F'}, + {"0NSOVU", 'F'}, + {"0NSUE", 'F'}, + {"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'}, + {"0NU(E1", 'F'}, + {"0NU(EF", 'F'}, + {"0NU(EK", 'F'}, + {"0NU(EN", 'F'}, + {"0NU(ES", 'F'}, + {"0NU(EV", 'F'}, + {"0NU(F(", 'F'}, + {"0NU(N)", 'F'}, + {"0NU(NO", 'F'}, + {"0NU(S)", 'F'}, + {"0NU(SO", 'F'}, + {"0NU(V)", 'F'}, + {"0NU(VO", 'F'}, + {"0NU1,(", 'F'}, + {"0NU1,F", 'F'}, + {"0NU1C", 'F'}, + {"0NU1O(", 'F'}, + {"0NU1OF", 'F'}, + {"0NU1OS", 'F'}, + {"0NU1OV", 'F'}, + {"0NU;", 'F'}, + {"0NU;C", 'F'}, + {"0NUC", 'F'}, + {"0NUE", 'F'}, + {"0NUE(1", 'F'}, + {"0NUE(E", 'F'}, + {"0NUE(F", 'F'}, + {"0NUE(N", 'F'}, + {"0NUE(O", 'F'}, + {"0NUE(S", 'F'}, + {"0NUE(V", 'F'}, + {"0NUE1", 'F'}, + {"0NUE1&", 'F'}, + {"0NUE1(", 'F'}, + {"0NUE1)", 'F'}, + {"0NUE1,", 'F'}, + {"0NUE1;", 'F'}, + {"0NUE1B", 'F'}, + {"0NUE1C", 'F'}, + {"0NUE1F", 'F'}, + {"0NUE1K", 'F'}, + {"0NUE1N", 'F'}, + {"0NUE1O", 'F'}, + {"0NUE1S", 'F'}, + {"0NUE1U", 'F'}, + {"0NUE1V", 'F'}, + {"0NUE;", 'F'}, + {"0NUE;C", 'F'}, + {"0NUEC", 'F'}, + {"0NUEF", 'F'}, + {"0NUEF(", 'F'}, + {"0NUEF,", 'F'}, + {"0NUEF;", 'F'}, + {"0NUEFC", 'F'}, + {"0NUEK", 'F'}, + {"0NUEK(", 'F'}, + {"0NUEK1", 'F'}, + {"0NUEK;", 'F'}, + {"0NUEKC", 'F'}, + {"0NUEKF", 'F'}, + {"0NUEKN", 'F'}, + {"0NUEKO", 'F'}, + {"0NUEKS", 'F'}, + {"0NUEKV", 'F'}, + {"0NUEN", 'F'}, + {"0NUEN&", 'F'}, + {"0NUEN(", 'F'}, + {"0NUEN)", 'F'}, + {"0NUEN,", 'F'}, + {"0NUEN1", 'F'}, + {"0NUEN;", 'F'}, + {"0NUENB", 'F'}, + {"0NUENC", 'F'}, + {"0NUENF", 'F'}, + {"0NUENK", 'F'}, + {"0NUENO", 'F'}, + {"0NUENS", 'F'}, + {"0NUENU", 'F'}, + {"0NUEOK", 'F'}, + {"0NUEON", 'F'}, + {"0NUES", 'F'}, + {"0NUES&", 'F'}, + {"0NUES(", 'F'}, + {"0NUES)", 'F'}, + {"0NUES,", 'F'}, + {"0NUES1", 'F'}, + {"0NUES;", 'F'}, + {"0NUESB", 'F'}, + {"0NUESC", 'F'}, + {"0NUESF", 'F'}, + {"0NUESK", 'F'}, + {"0NUESO", 'F'}, + {"0NUESU", 'F'}, + {"0NUESV", 'F'}, + {"0NUEV", 'F'}, + {"0NUEV&", 'F'}, + {"0NUEV(", 'F'}, + {"0NUEV)", 'F'}, + {"0NUEV,", 'F'}, + {"0NUEV;", 'F'}, + {"0NUEVB", 'F'}, + {"0NUEVC", 'F'}, + {"0NUEVF", 'F'}, + {"0NUEVK", 'F'}, + {"0NUEVN", 'F'}, + {"0NUEVO", 'F'}, + {"0NUEVS", 'F'}, + {"0NUEVU", 'F'}, + {"0NUF()", 'F'}, + {"0NUF(1", 'F'}, + {"0NUF(F", 'F'}, + {"0NUF(N", 'F'}, + {"0NUF(S", 'F'}, + {"0NUF(V", 'F'}, + {"0NUK(E", 'F'}, + {"0NUO(E", 'F'}, + {"0NUON(", 'F'}, + {"0NUON1", 'F'}, + {"0NUONF", 'F'}, + {"0NUONS", 'F'}, + {"0NUS,(", 'F'}, + {"0NUS,F", 'F'}, + {"0NUSC", 'F'}, + {"0NUSO(", 'F'}, + {"0NUSO1", 'F'}, + {"0NUSOF", 'F'}, + {"0NUSON", 'F'}, + {"0NUSOS", 'F'}, + {"0NUSOV", 'F'}, + {"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'}, + {"0S&(1&", 'F'}, + {"0S&(1)", 'F'}, + {"0S&(1,", 'F'}, + {"0S&(1O", 'F'}, + {"0S&(E(", 'F'}, + {"0S&(E1", 'F'}, + {"0S&(EF", 'F'}, + {"0S&(EK", 'F'}, + {"0S&(EN", 'F'}, + {"0S&(EO", 'F'}, + {"0S&(ES", 'F'}, + {"0S&(EV", 'F'}, + {"0S&(F(", 'F'}, + {"0S&(N&", 'F'}, + {"0S&(N)", 'F'}, + {"0S&(N,", 'F'}, + {"0S&(NO", 'F'}, + {"0S&(S&", 'F'}, + {"0S&(S)", 'F'}, + {"0S&(S,", 'F'}, + {"0S&(SO", 'F'}, + {"0S&(V&", 'F'}, + {"0S&(V)", 'F'}, + {"0S&(V,", 'F'}, + {"0S&(VO", 'F'}, + {"0S&1", 'F'}, + {"0S&1&(", 'F'}, + {"0S&1&1", 'F'}, + {"0S&1&F", 'F'}, + {"0S&1&N", 'F'}, + {"0S&1&S", 'F'}, + {"0S&1&V", 'F'}, + {"0S&1)&", 'F'}, + {"0S&1)C", 'F'}, + {"0S&1)O", 'F'}, + {"0S&1)U", 'F'}, + {"0S&1;", 'F'}, + {"0S&1;C", 'F'}, + {"0S&1;E", 'F'}, + {"0S&1;T", 'F'}, + {"0S&1B(", 'F'}, + {"0S&1B1", 'F'}, + {"0S&1BF", 'F'}, + {"0S&1BN", 'F'}, + {"0S&1BS", 'F'}, + {"0S&1BV", 'F'}, + {"0S&1C", 'F'}, + {"0S&1EK", 'F'}, + {"0S&1EN", 'F'}, + {"0S&1F(", 'F'}, + {"0S&1K(", 'F'}, + {"0S&1K1", 'F'}, + {"0S&1KF", 'F'}, + {"0S&1KN", 'F'}, + {"0S&1KS", 'F'}, + {"0S&1KV", 'F'}, + {"0S&1O(", 'F'}, + {"0S&1OF", 'F'}, + {"0S&1OS", 'F'}, + {"0S&1OV", 'F'}, + {"0S&1TN", 'F'}, + {"0S&1U", 'F'}, + {"0S&1U(", 'F'}, + {"0S&1U;", 'F'}, + {"0S&1UC", 'F'}, + {"0S&1UE", 'F'}, + {"0S&E(1", 'F'}, + {"0S&E(F", 'F'}, + {"0S&E(N", 'F'}, + {"0S&E(O", 'F'}, + {"0S&E(S", 'F'}, + {"0S&E(V", 'F'}, + {"0S&E1", 'F'}, + {"0S&E1;", 'F'}, + {"0S&E1C", 'F'}, + {"0S&E1K", 'F'}, + {"0S&E1O", 'F'}, + {"0S&EF(", 'F'}, + {"0S&EK(", 'F'}, + {"0S&EK1", 'F'}, + {"0S&EKF", 'F'}, + {"0S&EKN", 'F'}, + {"0S&EKS", 'F'}, + {"0S&EKV", 'F'}, + {"0S&EN", 'F'}, + {"0S&EN;", 'F'}, + {"0S&ENC", 'F'}, + {"0S&ENK", 'F'}, + {"0S&ENO", 'F'}, + {"0S&ES", 'F'}, + {"0S&ES;", 'F'}, + {"0S&ESC", 'F'}, + {"0S&ESK", 'F'}, + {"0S&ESO", 'F'}, + {"0S&EV", 'F'}, + {"0S&EV;", 'F'}, + {"0S&EVC", 'F'}, + {"0S&EVK", 'F'}, + {"0S&EVO", 'F'}, + {"0S&F()", 'F'}, + {"0S&F(1", 'F'}, + {"0S&F(E", 'F'}, + {"0S&F(F", 'F'}, + {"0S&F(N", 'F'}, + {"0S&F(S", 'F'}, + {"0S&F(V", 'F'}, + {"0S&K&(", 'F'}, + {"0S&K&1", 'F'}, + {"0S&K&F", 'F'}, + {"0S&K&N", 'F'}, + {"0S&K&S", 'F'}, + {"0S&K&V", 'F'}, + {"0S&K(1", 'F'}, + {"0S&K(F", 'F'}, + {"0S&K(N", 'F'}, + {"0S&K(S", 'F'}, + {"0S&K(V", 'F'}, + {"0S&K1O", 'F'}, + {"0S&KC", 'F'}, + {"0S&KF(", 'F'}, + {"0S&KNK", 'F'}, + {"0S&KO(", 'F'}, + {"0S&KO1", 'F'}, + {"0S&KOF", 'F'}, + {"0S&KOK", 'F'}, + {"0S&KON", 'F'}, + {"0S&KOS", 'F'}, + {"0S&KOV", 'F'}, + {"0S&KSO", 'F'}, + {"0S&KVO", 'F'}, + {"0S&N", 'F'}, + {"0S&N&(", 'F'}, + {"0S&N&1", 'F'}, + {"0S&N&F", 'F'}, + {"0S&N&N", 'F'}, + {"0S&N&S", 'F'}, + {"0S&N&V", 'F'}, + {"0S&N)&", 'F'}, + {"0S&N)C", 'F'}, + {"0S&N)O", 'F'}, + {"0S&N)U", 'F'}, + {"0S&N;", 'F'}, + {"0S&N;C", 'F'}, + {"0S&N;E", 'F'}, + {"0S&N;T", 'F'}, + {"0S&NB(", 'F'}, + {"0S&NB1", 'F'}, + {"0S&NBF", 'F'}, + {"0S&NBN", 'F'}, + {"0S&NBS", 'F'}, + {"0S&NBV", 'F'}, + {"0S&NC", 'F'}, + {"0S&NEN", 'F'}, + {"0S&NF(", 'F'}, + {"0S&NK(", 'F'}, + {"0S&NK1", 'F'}, + {"0S&NKF", 'F'}, + {"0S&NKN", 'F'}, + {"0S&NKS", 'F'}, + {"0S&NKV", 'F'}, + {"0S&NO(", 'F'}, + {"0S&NOF", 'F'}, + {"0S&NOS", 'F'}, + {"0S&NOV", 'F'}, + {"0S&NTN", 'F'}, + {"0S&NU", 'F'}, + {"0S&NU(", 'F'}, + {"0S&NU;", 'F'}, + {"0S&NUC", 'F'}, + {"0S&NUE", 'F'}, + {"0S&S", 'F'}, + {"0S&S&(", 'F'}, + {"0S&S&1", 'F'}, + {"0S&S&F", 'F'}, + {"0S&S&N", 'F'}, + {"0S&S&S", 'F'}, + {"0S&S&V", 'F'}, + {"0S&S)&", 'F'}, + {"0S&S)C", 'F'}, + {"0S&S)O", 'F'}, + {"0S&S)U", 'F'}, + {"0S&S1", 'F'}, + {"0S&S1;", 'F'}, + {"0S&S1C", 'F'}, + {"0S&S;", 'F'}, + {"0S&S;C", 'F'}, + {"0S&S;E", 'F'}, + {"0S&S;T", 'F'}, + {"0S&SB(", 'F'}, + {"0S&SB1", 'F'}, + {"0S&SBF", 'F'}, + {"0S&SBN", 'F'}, + {"0S&SBS", 'F'}, + {"0S&SBV", 'F'}, + {"0S&SC", 'F'}, + {"0S&SEK", 'F'}, + {"0S&SEN", 'F'}, + {"0S&SF(", 'F'}, + {"0S&SK(", 'F'}, + {"0S&SK1", 'F'}, + {"0S&SKF", 'F'}, + {"0S&SKN", 'F'}, + {"0S&SKS", 'F'}, + {"0S&SKV", 'F'}, + {"0S&SO(", 'F'}, + {"0S&SO1", 'F'}, + {"0S&SOF", 'F'}, + {"0S&SON", 'F'}, + {"0S&SOS", 'F'}, + {"0S&SOV", 'F'}, + {"0S&STN", 'F'}, + {"0S&SU", 'F'}, + {"0S&SU(", 'F'}, + {"0S&SU;", 'F'}, + {"0S&SUC", 'F'}, + {"0S&SUE", 'F'}, + {"0S&SV", 'F'}, + {"0S&SV;", 'F'}, + {"0S&SVC", 'F'}, + {"0S&SVO", 'F'}, + {"0S&V", 'F'}, + {"0S&V&(", 'F'}, + {"0S&V&1", 'F'}, + {"0S&V&F", 'F'}, + {"0S&V&N", 'F'}, + {"0S&V&S", 'F'}, + {"0S&V&V", 'F'}, + {"0S&V)&", 'F'}, + {"0S&V)C", 'F'}, + {"0S&V)O", 'F'}, + {"0S&V)U", 'F'}, + {"0S&V;", 'F'}, + {"0S&V;C", 'F'}, + {"0S&V;E", 'F'}, + {"0S&V;T", 'F'}, + {"0S&VB(", 'F'}, + {"0S&VB1", 'F'}, + {"0S&VBF", 'F'}, + {"0S&VBN", 'F'}, + {"0S&VBS", 'F'}, + {"0S&VBV", 'F'}, + {"0S&VC", 'F'}, + {"0S&VEK", 'F'}, + {"0S&VEN", 'F'}, + {"0S&VF(", 'F'}, + {"0S&VK(", 'F'}, + {"0S&VK1", 'F'}, + {"0S&VKF", 'F'}, + {"0S&VKN", 'F'}, + {"0S&VKS", 'F'}, + {"0S&VKV", 'F'}, + {"0S&VO(", 'F'}, + {"0S&VOF", 'F'}, + {"0S&VOS", 'F'}, + {"0S&VS", 'F'}, + {"0S&VS;", 'F'}, + {"0S&VSC", 'F'}, + {"0S&VSO", 'F'}, + {"0S&VTN", 'F'}, + {"0S&VU", 'F'}, + {"0S&VU(", 'F'}, + {"0S&VU;", 'F'}, + {"0S&VUC", 'F'}, + {"0S&VUE", 'F'}, + {"0S(EF(", 'F'}, + {"0S(EKF", 'F'}, + {"0S(EKN", 'F'}, + {"0S(ENK", 'F'}, + {"0S(U(E", 'F'}, + {"0S)&(1", 'F'}, + {"0S)&(E", 'F'}, + {"0S)&(F", 'F'}, + {"0S)&(N", 'F'}, + {"0S)&(S", 'F'}, + {"0S)&(V", 'F'}, + {"0S)&1", 'F'}, + {"0S)&1&", 'F'}, + {"0S)&1)", 'F'}, + {"0S)&1;", 'F'}, + {"0S)&1B", 'F'}, + {"0S)&1C", 'F'}, + {"0S)&1F", 'F'}, + {"0S)&1O", 'F'}, + {"0S)&1U", 'F'}, + {"0S)&F(", 'F'}, + {"0S)&N", 'F'}, + {"0S)&N&", 'F'}, + {"0S)&N)", 'F'}, + {"0S)&N;", 'F'}, + {"0S)&NB", 'F'}, + {"0S)&NC", 'F'}, + {"0S)&NF", 'F'}, + {"0S)&NO", 'F'}, + {"0S)&NU", 'F'}, + {"0S)&S", 'F'}, + {"0S)&S&", 'F'}, + {"0S)&S)", 'F'}, + {"0S)&S;", 'F'}, + {"0S)&SB", 'F'}, + {"0S)&SC", 'F'}, + {"0S)&SF", 'F'}, + {"0S)&SO", 'F'}, + {"0S)&SU", 'F'}, + {"0S)&V", 'F'}, + {"0S)&V&", 'F'}, + {"0S)&V)", 'F'}, + {"0S)&V;", 'F'}, + {"0S)&VB", 'F'}, + {"0S)&VC", 'F'}, + {"0S)&VF", 'F'}, + {"0S)&VO", 'F'}, + {"0S)&VU", 'F'}, + {"0S),(1", 'F'}, + {"0S),(F", 'F'}, + {"0S),(N", 'F'}, + {"0S),(S", 'F'}, + {"0S),(V", 'F'}, + {"0S);E(", 'F'}, + {"0S);E1", 'F'}, + {"0S);EF", 'F'}, + {"0S);EK", 'F'}, + {"0S);EN", 'F'}, + {"0S);EO", 'F'}, + {"0S);ES", 'F'}, + {"0S);EV", 'F'}, + {"0S);T(", 'F'}, + {"0S);T1", 'F'}, + {"0S);TF", 'F'}, + {"0S);TK", 'F'}, + {"0S);TN", 'F'}, + {"0S);TO", 'F'}, + {"0S);TS", 'F'}, + {"0S);TV", 'F'}, + {"0S)B(1", 'F'}, + {"0S)B(F", 'F'}, + {"0S)B(N", 'F'}, + {"0S)B(S", 'F'}, + {"0S)B(V", 'F'}, + {"0S)B1", 'F'}, + {"0S)B1&", 'F'}, + {"0S)B1;", 'F'}, + {"0S)B1C", 'F'}, + {"0S)B1K", 'F'}, + {"0S)B1N", 'F'}, + {"0S)B1O", 'F'}, + {"0S)B1U", 'F'}, + {"0S)BF(", 'F'}, + {"0S)BN", 'F'}, + {"0S)BN&", 'F'}, + {"0S)BN;", 'F'}, + {"0S)BNC", 'F'}, + {"0S)BNK", 'F'}, + {"0S)BNO", 'F'}, + {"0S)BNU", 'F'}, + {"0S)BS", 'F'}, + {"0S)BS&", 'F'}, + {"0S)BS;", 'F'}, + {"0S)BSC", 'F'}, + {"0S)BSK", 'F'}, + {"0S)BSO", 'F'}, + {"0S)BSU", 'F'}, + {"0S)BV", 'F'}, + {"0S)BV&", 'F'}, + {"0S)BV;", 'F'}, + {"0S)BVC", 'F'}, + {"0S)BVK", 'F'}, + {"0S)BVO", 'F'}, + {"0S)BVU", 'F'}, + {"0S)C", 'F'}, + {"0S)E(1", 'F'}, + {"0S)E(F", 'F'}, + {"0S)E(N", 'F'}, + {"0S)E(S", 'F'}, + {"0S)E(V", 'F'}, + {"0S)E1C", 'F'}, + {"0S)E1O", 'F'}, + {"0S)EF(", 'F'}, + {"0S)EK(", 'F'}, + {"0S)EK1", 'F'}, + {"0S)EKF", 'F'}, + {"0S)EKN", 'F'}, + {"0S)EKS", 'F'}, + {"0S)EKV", 'F'}, + {"0S)ENC", 'F'}, + {"0S)ENO", 'F'}, + {"0S)ESC", 'F'}, + {"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'}, + {"0S)K(S", 'F'}, + {"0S)K(V", 'F'}, + {"0S)K1&", 'F'}, + {"0S)K1;", 'F'}, + {"0S)K1B", 'F'}, + {"0S)K1E", 'F'}, + {"0S)K1O", 'F'}, + {"0S)K1U", 'F'}, + {"0S)KB(", 'F'}, + {"0S)KB1", 'F'}, + {"0S)KBF", 'F'}, + {"0S)KBN", 'F'}, + {"0S)KBS", 'F'}, + {"0S)KBV", 'F'}, + {"0S)KF(", 'F'}, + {"0S)KN&", 'F'}, + {"0S)KN;", 'F'}, + {"0S)KNB", 'F'}, + {"0S)KNC", 'F'}, + {"0S)KNE", 'F'}, + {"0S)KNK", 'F'}, + {"0S)KNU", 'F'}, + {"0S)KS&", 'F'}, + {"0S)KS;", 'F'}, + {"0S)KSB", 'F'}, + {"0S)KSE", 'F'}, + {"0S)KSO", 'F'}, + {"0S)KSU", 'F'}, + {"0S)KUE", 'F'}, + {"0S)KV&", 'F'}, + {"0S)KV;", 'F'}, + {"0S)KVB", 'F'}, + {"0S)KVE", 'F'}, + {"0S)KVO", 'F'}, + {"0S)KVU", 'F'}, + {"0S)O(1", 'F'}, + {"0S)O(E", 'F'}, + {"0S)O(F", 'F'}, + {"0S)O(N", 'F'}, + {"0S)O(S", 'F'}, + {"0S)O(V", 'F'}, + {"0S)O1", 'F'}, + {"0S)O1&", 'F'}, + {"0S)O1)", 'F'}, + {"0S)O1;", 'F'}, + {"0S)O1B", 'F'}, + {"0S)O1C", 'F'}, + {"0S)O1K", 'F'}, + {"0S)O1U", 'F'}, + {"0S)OF(", 'F'}, + {"0S)ON&", 'F'}, + {"0S)ON)", 'F'}, + {"0S)ON;", 'F'}, + {"0S)ONB", 'F'}, + {"0S)ONC", 'F'}, + {"0S)ONK", 'F'}, + {"0S)ONU", 'F'}, + {"0S)OS", 'F'}, + {"0S)OS&", 'F'}, + {"0S)OS)", 'F'}, + {"0S)OS;", 'F'}, + {"0S)OSB", 'F'}, + {"0S)OSC", 'F'}, + {"0S)OSK", 'F'}, + {"0S)OSU", 'F'}, + {"0S)OV", 'F'}, + {"0S)OV&", 'F'}, + {"0S)OV)", 'F'}, + {"0S)OV;", 'F'}, + {"0S)OVB", 'F'}, + {"0S)OVC", 'F'}, + {"0S)OVK", 'F'}, + {"0S)OVO", 'F'}, + {"0S)OVU", 'F'}, + {"0S)U(E", 'F'}, + {"0S)UE(", 'F'}, + {"0S)UE1", 'F'}, + {"0S)UEF", 'F'}, + {"0S)UEK", 'F'}, + {"0S)UEN", 'F'}, + {"0S)UES", 'F'}, + {"0S)UEV", 'F'}, + {"0S,(1)", 'F'}, + {"0S,(1O", 'F'}, + {"0S,(E(", 'F'}, + {"0S,(E1", 'F'}, + {"0S,(EF", 'F'}, + {"0S,(EK", 'F'}, + {"0S,(EN", 'F'}, + {"0S,(ES", 'F'}, + {"0S,(EV", 'F'}, + {"0S,(F(", 'F'}, + {"0S,(N)", 'F'}, + {"0S,(NO", 'F'}, + {"0S,(S)", 'F'}, + {"0S,(SO", 'F'}, + {"0S,(V)", 'F'}, + {"0S,(VO", 'F'}, + {"0S,F()", 'F'}, + {"0S,F(1", 'F'}, + {"0S,F(F", 'F'}, + {"0S,F(N", 'F'}, + {"0S,F(S", 'F'}, + {"0S,F(V", 'F'}, + {"0S1F()", 'F'}, + {"0S1F(1", 'F'}, + {"0S1F(F", 'F'}, + {"0S1F(N", 'F'}, + {"0S1F(S", 'F'}, + {"0S1F(V", 'F'}, + {"0S1NC", 'F'}, + {"0S1S;", 'F'}, + {"0S1S;C", 'F'}, + {"0S1SC", 'F'}, + {"0S1UE", 'F'}, + {"0S1UE;", 'F'}, + {"0S1UEC", 'F'}, + {"0S1UEK", 'F'}, + {"0S1V", 'F'}, + {"0S1V;", 'F'}, + {"0S1V;C", 'F'}, + {"0S1VC", 'F'}, + {"0S1VO(", 'F'}, + {"0S1VOF", 'F'}, + {"0S1VOS", 'F'}, + {"0S;E(1", 'F'}, + {"0S;E(E", 'F'}, + {"0S;E(F", 'F'}, + {"0S;E(N", 'F'}, + {"0S;E(S", 'F'}, + {"0S;E(V", 'F'}, + {"0S;E1,", 'F'}, + {"0S;E1;", 'F'}, + {"0S;E1C", 'F'}, + {"0S;E1K", 'F'}, + {"0S;E1O", 'F'}, + {"0S;E1T", 'F'}, + {"0S;EF(", 'F'}, + {"0S;EK(", 'F'}, + {"0S;EK1", 'F'}, + {"0S;EKF", 'F'}, + {"0S;EKN", 'F'}, + {"0S;EKO", 'F'}, + {"0S;EKS", 'F'}, + {"0S;EKV", 'F'}, + {"0S;EN,", 'F'}, + {"0S;EN;", 'F'}, + {"0S;ENC", 'F'}, + {"0S;ENE", 'F'}, + {"0S;ENK", 'F'}, + {"0S;ENO", 'F'}, + {"0S;ENT", 'F'}, + {"0S;ES,", 'F'}, + {"0S;ES;", 'F'}, + {"0S;ESC", 'F'}, + {"0S;ESK", 'F'}, + {"0S;ESO", 'F'}, + {"0S;EST", 'F'}, + {"0S;EV,", 'F'}, + {"0S;EV;", 'F'}, + {"0S;EVC", 'F'}, + {"0S;EVK", 'F'}, + {"0S;EVO", 'F'}, + {"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'}, + {"0S;T1F", 'F'}, + {"0S;T1K", 'F'}, + {"0S;T1O", 'F'}, + {"0S;T1T", 'F'}, + {"0S;T;", 'F'}, + {"0S;T;C", 'F'}, + {"0S;TF(", 'F'}, + {"0S;TK(", 'F'}, + {"0S;TK1", 'F'}, + {"0S;TKF", 'F'}, + {"0S;TKK", 'F'}, + {"0S;TKN", 'F'}, + {"0S;TKO", 'F'}, + {"0S;TKS", 'F'}, + {"0S;TKV", 'F'}, + {"0S;TN(", 'F'}, + {"0S;TN,", 'F'}, + {"0S;TN1", 'F'}, + {"0S;TN;", 'F'}, + {"0S;TNC", 'F'}, + {"0S;TNE", 'F'}, + {"0S;TNF", 'F'}, + {"0S;TNK", 'F'}, + {"0S;TNN", 'F'}, + {"0S;TNO", 'F'}, + {"0S;TNS", 'F'}, + {"0S;TNT", 'F'}, + {"0S;TNV", 'F'}, + {"0S;TO(", 'F'}, + {"0S;TS(", 'F'}, + {"0S;TS,", 'F'}, + {"0S;TS;", 'F'}, + {"0S;TSC", 'F'}, + {"0S;TSF", 'F'}, + {"0S;TSK", 'F'}, + {"0S;TSO", 'F'}, + {"0S;TST", 'F'}, + {"0S;TTN", 'F'}, + {"0S;TV(", 'F'}, + {"0S;TV,", 'F'}, + {"0S;TV;", 'F'}, + {"0S;TVC", 'F'}, + {"0S;TVF", 'F'}, + {"0S;TVK", 'F'}, + {"0S;TVO", 'F'}, + {"0S;TVT", 'F'}, + {"0SA(F(", 'F'}, + {"0SA(N)", 'F'}, + {"0SA(NO", 'F'}, + {"0SA(S)", 'F'}, + {"0SA(SO", 'F'}, + {"0SA(V)", 'F'}, + {"0SA(VO", 'F'}, + {"0SAF()", 'F'}, + {"0SAF(1", 'F'}, + {"0SAF(F", 'F'}, + {"0SAF(N", 'F'}, + {"0SAF(S", 'F'}, + {"0SAF(V", 'F'}, + {"0SASO(", 'F'}, + {"0SASO1", 'F'}, + {"0SASOF", 'F'}, + {"0SASON", 'F'}, + {"0SASOS", 'F'}, + {"0SASOV", 'F'}, + {"0SASUE", 'F'}, + {"0SATO(", 'F'}, + {"0SATO1", 'F'}, + {"0SATOF", 'F'}, + {"0SATON", 'F'}, + {"0SATOS", 'F'}, + {"0SATOV", 'F'}, + {"0SATUE", 'F'}, + {"0SAVO(", 'F'}, + {"0SAVOF", 'F'}, + {"0SAVOS", 'F'}, + {"0SAVUE", 'F'}, + {"0SB(1)", 'F'}, + {"0SB(1O", 'F'}, + {"0SB(F(", 'F'}, + {"0SB(NO", 'F'}, + {"0SB(S)", 'F'}, + {"0SB(SO", 'F'}, + {"0SB(V)", 'F'}, + {"0SB(VO", 'F'}, + {"0SB1", 'F'}, + {"0SB1&(", 'F'}, + {"0SB1&1", 'F'}, + {"0SB1&F", 'F'}, + {"0SB1&N", 'F'}, + {"0SB1&S", 'F'}, + {"0SB1&V", 'F'}, + {"0SB1,(", 'F'}, + {"0SB1,F", 'F'}, + {"0SB1;", 'F'}, + {"0SB1;C", 'F'}, + {"0SB1B(", 'F'}, + {"0SB1B1", 'F'}, + {"0SB1BF", 'F'}, + {"0SB1BN", 'F'}, + {"0SB1BS", 'F'}, + {"0SB1BV", 'F'}, + {"0SB1C", 'F'}, + {"0SB1K(", 'F'}, + {"0SB1K1", 'F'}, + {"0SB1KF", 'F'}, + {"0SB1KN", 'F'}, + {"0SB1KS", 'F'}, + {"0SB1KV", 'F'}, + {"0SB1O(", 'F'}, + {"0SB1OF", 'F'}, + {"0SB1OS", 'F'}, + {"0SB1OV", 'F'}, + {"0SB1U(", 'F'}, + {"0SB1UE", 'F'}, + {"0SBE(1", 'F'}, + {"0SBE(F", 'F'}, + {"0SBE(N", 'F'}, + {"0SBE(S", 'F'}, + {"0SBE(V", 'F'}, + {"0SBEK(", 'F'}, + {"0SBF()", 'F'}, + {"0SBF(1", 'F'}, + {"0SBF(F", 'F'}, + {"0SBF(N", 'F'}, + {"0SBF(S", 'F'}, + {"0SBF(V", 'F'}, + {"0SBN", 'F'}, + {"0SBN&(", 'F'}, + {"0SBN&1", 'F'}, + {"0SBN&F", 'F'}, + {"0SBN&N", 'F'}, + {"0SBN&S", 'F'}, + {"0SBN&V", 'F'}, + {"0SBN,(", 'F'}, + {"0SBN,F", 'F'}, + {"0SBN;", 'F'}, + {"0SBN;C", 'F'}, + {"0SBNB(", 'F'}, + {"0SBNB1", 'F'}, + {"0SBNBF", 'F'}, + {"0SBNBN", 'F'}, + {"0SBNBS", 'F'}, + {"0SBNBV", 'F'}, + {"0SBNC", 'F'}, + {"0SBNK(", 'F'}, + {"0SBNK1", 'F'}, + {"0SBNKF", 'F'}, + {"0SBNKN", 'F'}, + {"0SBNKS", 'F'}, + {"0SBNKV", 'F'}, + {"0SBNO(", 'F'}, + {"0SBNOF", 'F'}, + {"0SBNOS", 'F'}, + {"0SBNOV", 'F'}, + {"0SBNU(", 'F'}, + {"0SBNUE", 'F'}, + {"0SBS", 'F'}, + {"0SBS&(", 'F'}, + {"0SBS&1", 'F'}, + {"0SBS&F", 'F'}, + {"0SBS&N", 'F'}, + {"0SBS&S", 'F'}, + {"0SBS&V", 'F'}, + {"0SBS,(", 'F'}, + {"0SBS,F", 'F'}, + {"0SBS;", 'F'}, + {"0SBS;C", 'F'}, + {"0SBSB(", 'F'}, + {"0SBSB1", 'F'}, + {"0SBSBF", 'F'}, + {"0SBSBN", 'F'}, + {"0SBSBS", 'F'}, + {"0SBSBV", 'F'}, + {"0SBSC", 'F'}, + {"0SBSK(", 'F'}, + {"0SBSK1", 'F'}, + {"0SBSKF", 'F'}, + {"0SBSKN", 'F'}, + {"0SBSKS", 'F'}, + {"0SBSKV", 'F'}, + {"0SBSO(", 'F'}, + {"0SBSO1", 'F'}, + {"0SBSOF", 'F'}, + {"0SBSON", 'F'}, + {"0SBSOS", 'F'}, + {"0SBSOV", 'F'}, + {"0SBSU(", 'F'}, + {"0SBSUE", 'F'}, + {"0SBV", 'F'}, + {"0SBV&(", 'F'}, + {"0SBV&1", 'F'}, + {"0SBV&F", 'F'}, + {"0SBV&N", 'F'}, + {"0SBV&S", 'F'}, + {"0SBV&V", 'F'}, + {"0SBV,(", 'F'}, + {"0SBV,F", 'F'}, + {"0SBV;", 'F'}, + {"0SBV;C", 'F'}, + {"0SBVB(", 'F'}, + {"0SBVB1", 'F'}, + {"0SBVBF", 'F'}, + {"0SBVBN", 'F'}, + {"0SBVBS", 'F'}, + {"0SBVBV", 'F'}, + {"0SBVC", 'F'}, + {"0SBVK(", 'F'}, + {"0SBVK1", 'F'}, + {"0SBVKF", 'F'}, + {"0SBVKN", 'F'}, + {"0SBVKS", 'F'}, + {"0SBVKV", 'F'}, + {"0SBVO(", 'F'}, + {"0SBVOF", 'F'}, + {"0SBVOS", 'F'}, + {"0SBVU(", 'F'}, + {"0SBVUE", 'F'}, + {"0SC", 'F'}, + {"0SE(1)", 'F'}, + {"0SE(1O", 'F'}, + {"0SE(F(", 'F'}, + {"0SE(N)", 'F'}, + {"0SE(NO", 'F'}, + {"0SE(S)", 'F'}, + {"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'}, + {"0SEF(F", 'F'}, + {"0SEF(N", 'F'}, + {"0SEF(S", 'F'}, + {"0SEF(V", 'F'}, + {"0SEK(1", 'F'}, + {"0SEK(E", 'F'}, + {"0SEK(F", 'F'}, + {"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'}, + {"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'}, + {"0SESOF", 'F'}, + {"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'}, + {"0SEU(N", 'F'}, + {"0SEU(S", 'F'}, + {"0SEU(V", 'F'}, + {"0SEU1,", 'F'}, + {"0SEU1C", 'F'}, + {"0SEU1O", 'F'}, + {"0SEUEF", 'F'}, + {"0SEUEK", 'F'}, + {"0SEUF(", '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'}, + {"0SF()K", 'F'}, + {"0SF()N", 'F'}, + {"0SF()O", 'F'}, + {"0SF()S", 'F'}, + {"0SF()U", 'F'}, + {"0SF()V", 'F'}, + {"0SF(1)", 'F'}, + {"0SF(1N", 'F'}, + {"0SF(1O", 'F'}, + {"0SF(E(", 'F'}, + {"0SF(E1", 'F'}, + {"0SF(EF", 'F'}, + {"0SF(EK", 'F'}, + {"0SF(EN", 'F'}, + {"0SF(ES", 'F'}, + {"0SF(EV", 'F'}, + {"0SF(F(", 'F'}, + {"0SF(N)", 'F'}, + {"0SF(N,", 'F'}, + {"0SF(NO", 'F'}, + {"0SF(S)", 'F'}, + {"0SF(SO", 'F'}, + {"0SF(V)", 'F'}, + {"0SF(VO", 'F'}, + {"0SK(1)", 'F'}, + {"0SK(1O", 'F'}, + {"0SK(F(", 'F'}, + {"0SK(N)", 'F'}, + {"0SK(NO", 'F'}, + {"0SK(S)", 'F'}, + {"0SK(SO", 'F'}, + {"0SK(V)", 'F'}, + {"0SK(VO", 'F'}, + {"0SK)&(", 'F'}, + {"0SK)&1", 'F'}, + {"0SK)&F", 'F'}, + {"0SK)&N", 'F'}, + {"0SK)&S", 'F'}, + {"0SK)&V", 'F'}, + {"0SK);E", 'F'}, + {"0SK);T", 'F'}, + {"0SK)B(", 'F'}, + {"0SK)B1", 'F'}, + {"0SK)BF", 'F'}, + {"0SK)BN", 'F'}, + {"0SK)BS", 'F'}, + {"0SK)BV", 'F'}, + {"0SK)E(", 'F'}, + {"0SK)E1", 'F'}, + {"0SK)EF", 'F'}, + {"0SK)EK", 'F'}, + {"0SK)EN", 'F'}, + {"0SK)ES", 'F'}, + {"0SK)EV", 'F'}, + {"0SK)F(", 'F'}, + {"0SK)O(", 'F'}, + {"0SK)OF", 'F'}, + {"0SK)UE", 'F'}, + {"0SK1", 'F'}, + {"0SK1&(", 'F'}, + {"0SK1&1", 'F'}, + {"0SK1&F", 'F'}, + {"0SK1&N", 'F'}, + {"0SK1&S", 'F'}, + {"0SK1&V", 'F'}, + {"0SK1;", 'F'}, + {"0SK1;C", 'F'}, + {"0SK1;E", 'F'}, + {"0SK1;T", 'F'}, + {"0SK1B(", 'F'}, + {"0SK1B1", 'F'}, + {"0SK1BF", 'F'}, + {"0SK1BN", 'F'}, + {"0SK1BS", 'F'}, + {"0SK1BV", 'F'}, + {"0SK1C", 'F'}, + {"0SK1E(", 'F'}, + {"0SK1E1", 'F'}, + {"0SK1EF", 'F'}, + {"0SK1EK", 'F'}, + {"0SK1EN", 'F'}, + {"0SK1ES", 'F'}, + {"0SK1EV", 'F'}, + {"0SK1O(", 'F'}, + {"0SK1OF", 'F'}, + {"0SK1OS", 'F'}, + {"0SK1OV", 'F'}, + {"0SK1U(", 'F'}, + {"0SK1UE", 'F'}, + {"0SKF()", 'F'}, + {"0SKF(1", 'F'}, + {"0SKF(F", 'F'}, + {"0SKF(N", 'F'}, + {"0SKF(S", 'F'}, + {"0SKF(V", 'F'}, + {"0SKN", 'F'}, + {"0SKN&(", 'F'}, + {"0SKN&1", 'F'}, + {"0SKN&F", 'F'}, + {"0SKN&N", 'F'}, + {"0SKN&S", 'F'}, + {"0SKN&V", 'F'}, + {"0SKN;", 'F'}, + {"0SKN;C", 'F'}, + {"0SKN;E", 'F'}, + {"0SKN;T", 'F'}, + {"0SKNB(", 'F'}, + {"0SKNB1", 'F'}, + {"0SKNBF", 'F'}, + {"0SKNBN", 'F'}, + {"0SKNBS", 'F'}, + {"0SKNBV", 'F'}, + {"0SKNC", 'F'}, + {"0SKNE(", 'F'}, + {"0SKNE1", 'F'}, + {"0SKNEF", 'F'}, + {"0SKNEN", 'F'}, + {"0SKNES", 'F'}, + {"0SKNEV", 'F'}, + {"0SKNU(", 'F'}, + {"0SKNUE", 'F'}, + {"0SKS", 'F'}, + {"0SKS&(", 'F'}, + {"0SKS&1", 'F'}, + {"0SKS&F", 'F'}, + {"0SKS&N", 'F'}, + {"0SKS&S", 'F'}, + {"0SKS&V", 'F'}, + {"0SKS;", 'F'}, + {"0SKS;C", 'F'}, + {"0SKS;E", 'F'}, + {"0SKS;T", 'F'}, + {"0SKSB(", 'F'}, + {"0SKSB1", 'F'}, + {"0SKSBF", 'F'}, + {"0SKSBN", 'F'}, + {"0SKSBS", 'F'}, + {"0SKSBV", 'F'}, + {"0SKSC", 'F'}, + {"0SKSE(", 'F'}, + {"0SKSE1", 'F'}, + {"0SKSEF", 'F'}, + {"0SKSEK", 'F'}, + {"0SKSEN", 'F'}, + {"0SKSES", 'F'}, + {"0SKSEV", 'F'}, + {"0SKSO(", 'F'}, + {"0SKSO1", 'F'}, + {"0SKSOF", 'F'}, + {"0SKSON", 'F'}, + {"0SKSOS", 'F'}, + {"0SKSOV", 'F'}, + {"0SKSU(", 'F'}, + {"0SKSUE", 'F'}, + {"0SKUE(", 'F'}, + {"0SKUE1", 'F'}, + {"0SKUEF", 'F'}, + {"0SKUEK", 'F'}, + {"0SKUEN", 'F'}, + {"0SKUES", 'F'}, + {"0SKUEV", 'F'}, + {"0SKV", 'F'}, + {"0SKV&(", 'F'}, + {"0SKV&1", 'F'}, + {"0SKV&F", 'F'}, + {"0SKV&N", 'F'}, + {"0SKV&S", 'F'}, + {"0SKV&V", 'F'}, + {"0SKV;", 'F'}, + {"0SKV;C", 'F'}, + {"0SKV;E", 'F'}, + {"0SKV;T", 'F'}, + {"0SKVB(", 'F'}, + {"0SKVB1", 'F'}, + {"0SKVBF", 'F'}, + {"0SKVBN", 'F'}, + {"0SKVBS", 'F'}, + {"0SKVBV", 'F'}, + {"0SKVC", 'F'}, + {"0SKVE(", 'F'}, + {"0SKVE1", 'F'}, + {"0SKVEF", 'F'}, + {"0SKVEK", 'F'}, + {"0SKVEN", 'F'}, + {"0SKVES", 'F'}, + {"0SKVEV", 'F'}, + {"0SKVO(", 'F'}, + {"0SKVOF", 'F'}, + {"0SKVOS", 'F'}, + {"0SKVU(", 'F'}, + {"0SKVUE", 'F'}, + {"0SO(1&", 'F'}, + {"0SO(1)", 'F'}, + {"0SO(1,", 'F'}, + {"0SO(1O", 'F'}, + {"0SO(E(", 'F'}, + {"0SO(E1", 'F'}, + {"0SO(EE", 'F'}, + {"0SO(EF", 'F'}, + {"0SO(EK", 'F'}, + {"0SO(EN", 'F'}, + {"0SO(EO", 'F'}, + {"0SO(ES", 'F'}, + {"0SO(EV", 'F'}, + {"0SO(F(", 'F'}, + {"0SO(N&", 'F'}, + {"0SO(N)", 'F'}, + {"0SO(N,", 'F'}, + {"0SO(NO", 'F'}, + {"0SO(S&", 'F'}, + {"0SO(S)", 'F'}, + {"0SO(S,", 'F'}, + {"0SO(SO", 'F'}, + {"0SO(V&", 'F'}, + {"0SO(V)", 'F'}, + {"0SO(V,", 'F'}, + {"0SO(VO", 'F'}, + {"0SO1&(", 'F'}, + {"0SO1&1", 'F'}, + {"0SO1&E", 'F'}, + {"0SO1&F", 'F'}, + {"0SO1&K", 'F'}, + {"0SO1&N", 'F'}, + {"0SO1&S", 'F'}, + {"0SO1&U", 'F'}, + {"0SO1&V", 'F'}, + {"0SO1(E", 'F'}, + {"0SO1(U", 'F'}, + {"0SO1)&", 'F'}, + {"0SO1),", 'F'}, + {"0SO1);", 'F'}, + {"0SO1)B", 'F'}, + {"0SO1)C", 'F'}, + {"0SO1)E", 'F'}, + {"0SO1)F", 'F'}, + {"0SO1)K", 'F'}, + {"0SO1)O", 'F'}, + {"0SO1)U", 'F'}, + {"0SO1,(", 'F'}, + {"0SO1,F", 'F'}, + {"0SO1;", 'F'}, + {"0SO1;C", 'F'}, + {"0SO1;E", 'F'}, + {"0SO1;N", 'F'}, + {"0SO1;T", 'F'}, + {"0SO1A(", 'F'}, + {"0SO1AF", 'F'}, + {"0SO1AS", 'F'}, + {"0SO1AT", 'F'}, + {"0SO1AV", 'F'}, + {"0SO1B(", 'F'}, + {"0SO1B1", 'F'}, + {"0SO1BE", 'F'}, + {"0SO1BF", 'F'}, + {"0SO1BN", 'F'}, + {"0SO1BS", 'F'}, + {"0SO1BV", 'F'}, + {"0SO1C", 'F'}, + {"0SO1E(", 'F'}, + {"0SO1E1", 'F'}, + {"0SO1EF", 'F'}, + {"0SO1EK", 'F'}, + {"0SO1EN", 'F'}, + {"0SO1EO", 'F'}, + {"0SO1ES", 'F'}, + {"0SO1EU", 'F'}, + {"0SO1EV", 'F'}, + {"0SO1F(", 'F'}, + {"0SO1K(", 'F'}, + {"0SO1K)", 'F'}, + {"0SO1K1", 'F'}, + {"0SO1KB", 'F'}, + {"0SO1KF", 'F'}, + {"0SO1KN", 'F'}, + {"0SO1KS", 'F'}, + {"0SO1KU", 'F'}, + {"0SO1KV", 'F'}, + {"0SO1N&", 'F'}, + {"0SO1N(", 'F'}, + {"0SO1N,", 'F'}, + {"0SO1NE", 'F'}, + {"0SO1NU", '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'}, + {"0SO1U;", 'F'}, + {"0SO1UC", 'F'}, + {"0SO1UE", 'F'}, + {"0SO1UF", 'F'}, + {"0SO1UK", 'F'}, + {"0SO1UO", 'F'}, + {"0SO1US", 'F'}, + {"0SO1UT", 'F'}, + {"0SO1UV", 'F'}, + {"0SO1V(", 'F'}, + {"0SO1VF", 'F'}, + {"0SO1VO", 'F'}, + {"0SO1VS", 'F'}, + {"0SO1VU", 'F'}, + {"0SOF()", 'F'}, + {"0SOF(1", 'F'}, + {"0SOF(E", 'F'}, + {"0SOF(F", 'F'}, + {"0SOF(N", 'F'}, + {"0SOF(S", 'F'}, + {"0SOF(V", 'F'}, + {"0SOK&(", 'F'}, + {"0SOK&1", 'F'}, + {"0SOK&F", 'F'}, + {"0SOK&N", 'F'}, + {"0SOK&S", 'F'}, + {"0SOK&V", 'F'}, + {"0SOK(1", 'F'}, + {"0SOK(F", 'F'}, + {"0SOK(N", 'F'}, + {"0SOK(S", 'F'}, + {"0SOK(V", 'F'}, + {"0SOK1C", 'F'}, + {"0SOK1O", 'F'}, + {"0SOKF(", 'F'}, + {"0SOKNC", 'F'}, + {"0SOKO(", 'F'}, + {"0SOKO1", 'F'}, + {"0SOKOF", 'F'}, + {"0SOKON", 'F'}, + {"0SOKOS", 'F'}, + {"0SOKOV", 'F'}, + {"0SOKSC", 'F'}, + {"0SOKSO", 'F'}, + {"0SOKVC", 'F'}, + {"0SOKVO", 'F'}, + {"0SON&(", 'F'}, + {"0SON&1", 'F'}, + {"0SON&E", 'F'}, + {"0SON&F", 'F'}, + {"0SON&K", 'F'}, + {"0SON&N", 'F'}, + {"0SON&S", 'F'}, + {"0SON&U", 'F'}, + {"0SON&V", 'F'}, + {"0SON(1", 'F'}, + {"0SON(E", 'F'}, + {"0SON(F", 'F'}, + {"0SON(S", 'F'}, + {"0SON(U", 'F'}, + {"0SON(V", 'F'}, + {"0SON)&", 'F'}, + {"0SON),", 'F'}, + {"0SON);", 'F'}, + {"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'}, + {"0SON1O", 'F'}, + {"0SON1U", 'F'}, + {"0SON1V", 'F'}, + {"0SON;", 'F'}, + {"0SON;C", 'F'}, + {"0SON;E", 'F'}, + {"0SON;N", 'F'}, + {"0SON;T", 'F'}, + {"0SONA(", 'F'}, + {"0SONAF", 'F'}, + {"0SONAS", 'F'}, + {"0SONAT", 'F'}, + {"0SONAV", 'F'}, + {"0SONB(", 'F'}, + {"0SONB1", 'F'}, + {"0SONBE", 'F'}, + {"0SONBF", 'F'}, + {"0SONBN", 'F'}, + {"0SONBS", 'F'}, + {"0SONBV", 'F'}, + {"0SONE(", 'F'}, + {"0SONE1", 'F'}, + {"0SONEF", 'F'}, + {"0SONEN", 'F'}, + {"0SONEO", 'F'}, + {"0SONES", 'F'}, + {"0SONEU", 'F'}, + {"0SONEV", 'F'}, + {"0SONF(", 'F'}, + {"0SONK(", 'F'}, + {"0SONK)", 'F'}, + {"0SONK1", 'F'}, + {"0SONKB", 'F'}, + {"0SONKF", 'F'}, + {"0SONKS", 'F'}, + {"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'}, + {"0SONU;", 'F'}, + {"0SONUC", 'F'}, + {"0SONUE", 'F'}, + {"0SONUF", 'F'}, + {"0SONUK", 'F'}, + {"0SONUO", 'F'}, + {"0SONUS", 'F'}, + {"0SONUT", 'F'}, + {"0SONUV", 'F'}, + {"0SOS", 'F'}, + {"0SOS&(", 'F'}, + {"0SOS&1", 'F'}, + {"0SOS&E", 'F'}, + {"0SOS&F", 'F'}, + {"0SOS&K", 'F'}, + {"0SOS&N", 'F'}, + {"0SOS&S", 'F'}, + {"0SOS&U", 'F'}, + {"0SOS&V", 'F'}, + {"0SOS(E", 'F'}, + {"0SOS(U", 'F'}, + {"0SOS)&", 'F'}, + {"0SOS),", 'F'}, + {"0SOS);", 'F'}, + {"0SOS)B", 'F'}, + {"0SOS)C", 'F'}, + {"0SOS)E", 'F'}, + {"0SOS)F", 'F'}, + {"0SOS)K", 'F'}, + {"0SOS)O", 'F'}, + {"0SOS)U", 'F'}, + {"0SOS,(", 'F'}, + {"0SOS,F", 'F'}, + {"0SOS1(", 'F'}, + {"0SOS1F", 'F'}, + {"0SOS1N", 'F'}, + {"0SOS1S", 'F'}, + {"0SOS1U", 'F'}, + {"0SOS1V", 'F'}, + {"0SOS;", 'F'}, + {"0SOS;C", 'F'}, + {"0SOS;E", 'F'}, + {"0SOS;N", 'F'}, + {"0SOS;T", 'F'}, + {"0SOSA(", 'F'}, + {"0SOSAF", 'F'}, + {"0SOSAS", 'F'}, + {"0SOSAT", 'F'}, + {"0SOSAV", 'F'}, + {"0SOSB(", 'F'}, + {"0SOSB1", 'F'}, + {"0SOSBE", 'F'}, + {"0SOSBF", 'F'}, + {"0SOSBN", 'F'}, + {"0SOSBS", 'F'}, + {"0SOSBV", 'F'}, + {"0SOSC", 'F'}, + {"0SOSE(", 'F'}, + {"0SOSE1", 'F'}, + {"0SOSEF", 'F'}, + {"0SOSEK", 'F'}, + {"0SOSEN", 'F'}, + {"0SOSEO", 'F'}, + {"0SOSES", 'F'}, + {"0SOSEU", 'F'}, + {"0SOSEV", 'F'}, + {"0SOSF(", 'F'}, + {"0SOSK(", 'F'}, + {"0SOSK)", 'F'}, + {"0SOSK1", 'F'}, + {"0SOSKB", 'F'}, + {"0SOSKF", 'F'}, + {"0SOSKN", 'F'}, + {"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'}, + {"0SOSU;", 'F'}, + {"0SOSUC", 'F'}, + {"0SOSUE", 'F'}, + {"0SOSUF", 'F'}, + {"0SOSUK", 'F'}, + {"0SOSUO", 'F'}, + {"0SOSUS", 'F'}, + {"0SOSUT", 'F'}, + {"0SOSUV", 'F'}, + {"0SOSV(", 'F'}, + {"0SOSVF", 'F'}, + {"0SOSVO", 'F'}, + {"0SOSVS", 'F'}, + {"0SOSVU", 'F'}, + {"0SOU(E", 'F'}, + {"0SOUEK", 'F'}, + {"0SOUEN", 'F'}, + {"0SOV", 'F'}, + {"0SOV&(", 'F'}, + {"0SOV&1", 'F'}, + {"0SOV&E", 'F'}, + {"0SOV&F", 'F'}, + {"0SOV&K", 'F'}, + {"0SOV&N", 'F'}, + {"0SOV&S", 'F'}, + {"0SOV&U", 'F'}, + {"0SOV&V", 'F'}, + {"0SOV(E", 'F'}, + {"0SOV(U", 'F'}, + {"0SOV)&", 'F'}, + {"0SOV),", 'F'}, + {"0SOV);", 'F'}, + {"0SOV)B", 'F'}, + {"0SOV)C", 'F'}, + {"0SOV)E", 'F'}, + {"0SOV)F", 'F'}, + {"0SOV)K", 'F'}, + {"0SOV)O", 'F'}, + {"0SOV)U", 'F'}, + {"0SOV,(", 'F'}, + {"0SOV,F", 'F'}, + {"0SOV;", 'F'}, + {"0SOV;C", 'F'}, + {"0SOV;E", 'F'}, + {"0SOV;N", 'F'}, + {"0SOV;T", 'F'}, + {"0SOVA(", 'F'}, + {"0SOVAF", 'F'}, + {"0SOVAS", 'F'}, + {"0SOVAT", 'F'}, + {"0SOVAV", 'F'}, + {"0SOVB(", 'F'}, + {"0SOVB1", 'F'}, + {"0SOVBE", 'F'}, + {"0SOVBF", 'F'}, + {"0SOVBN", 'F'}, + {"0SOVBS", 'F'}, + {"0SOVBV", 'F'}, + {"0SOVC", 'F'}, + {"0SOVE(", 'F'}, + {"0SOVE1", 'F'}, + {"0SOVEF", 'F'}, + {"0SOVEK", 'F'}, + {"0SOVEN", 'F'}, + {"0SOVEO", 'F'}, + {"0SOVES", 'F'}, + {"0SOVEU", 'F'}, + {"0SOVEV", 'F'}, + {"0SOVF(", 'F'}, + {"0SOVK(", 'F'}, + {"0SOVK)", 'F'}, + {"0SOVK1", 'F'}, + {"0SOVKB", 'F'}, + {"0SOVKF", 'F'}, + {"0SOVKN", 'F'}, + {"0SOVKS", 'F'}, + {"0SOVKU", 'F'}, + {"0SOVKV", 'F'}, + {"0SOVO(", 'F'}, + {"0SOVOF", 'F'}, + {"0SOVOK", 'F'}, + {"0SOVOS", 'F'}, + {"0SOVOU", 'F'}, + {"0SOVS(", 'F'}, + {"0SOVS1", 'F'}, + {"0SOVSF", 'F'}, + {"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'}, + {"0SOVU;", 'F'}, + {"0SOVUC", 'F'}, + {"0SOVUE", 'F'}, + {"0SOVUF", 'F'}, + {"0SOVUK", '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'}, + {"0SU(E1", 'F'}, + {"0SU(EF", 'F'}, + {"0SU(EK", 'F'}, + {"0SU(EN", 'F'}, + {"0SU(ES", 'F'}, + {"0SU(EV", 'F'}, + {"0SU(F(", 'F'}, + {"0SU(N)", 'F'}, + {"0SU(NO", 'F'}, + {"0SU(S)", 'F'}, + {"0SU(SO", 'F'}, + {"0SU(V)", 'F'}, + {"0SU(VO", 'F'}, + {"0SU1,(", 'F'}, + {"0SU1,F", 'F'}, + {"0SU1C", 'F'}, + {"0SU1O(", 'F'}, + {"0SU1OF", 'F'}, + {"0SU1OS", 'F'}, + {"0SU1OV", 'F'}, + {"0SU;", 'F'}, + {"0SU;C", 'F'}, + {"0SUC", 'F'}, + {"0SUE", 'F'}, + {"0SUE(1", 'F'}, + {"0SUE(E", 'F'}, + {"0SUE(F", 'F'}, + {"0SUE(N", 'F'}, + {"0SUE(O", 'F'}, + {"0SUE(S", 'F'}, + {"0SUE(V", 'F'}, + {"0SUE1", 'F'}, + {"0SUE1&", 'F'}, + {"0SUE1(", 'F'}, + {"0SUE1)", 'F'}, + {"0SUE1,", 'F'}, + {"0SUE1;", 'F'}, + {"0SUE1B", 'F'}, + {"0SUE1C", 'F'}, + {"0SUE1F", 'F'}, + {"0SUE1K", 'F'}, + {"0SUE1N", 'F'}, + {"0SUE1O", 'F'}, + {"0SUE1S", 'F'}, + {"0SUE1U", 'F'}, + {"0SUE1V", 'F'}, + {"0SUE;", 'F'}, + {"0SUE;C", 'F'}, + {"0SUEC", 'F'}, + {"0SUEF", 'F'}, + {"0SUEF(", 'F'}, + {"0SUEF,", 'F'}, + {"0SUEF;", 'F'}, + {"0SUEFC", 'F'}, + {"0SUEK", 'F'}, + {"0SUEK(", 'F'}, + {"0SUEK1", 'F'}, + {"0SUEK;", 'F'}, + {"0SUEKC", 'F'}, + {"0SUEKF", 'F'}, + {"0SUEKN", 'F'}, + {"0SUEKO", 'F'}, + {"0SUEKS", 'F'}, + {"0SUEKV", 'F'}, + {"0SUEN", 'F'}, + {"0SUEN&", 'F'}, + {"0SUEN(", 'F'}, + {"0SUEN)", 'F'}, + {"0SUEN,", 'F'}, + {"0SUEN1", 'F'}, + {"0SUEN;", 'F'}, + {"0SUENB", 'F'}, + {"0SUENC", 'F'}, + {"0SUENF", 'F'}, + {"0SUENK", 'F'}, + {"0SUENO", 'F'}, + {"0SUENS", 'F'}, + {"0SUENU", 'F'}, + {"0SUEOK", 'F'}, + {"0SUEON", 'F'}, + {"0SUES", 'F'}, + {"0SUES&", 'F'}, + {"0SUES(", 'F'}, + {"0SUES)", 'F'}, + {"0SUES,", 'F'}, + {"0SUES1", 'F'}, + {"0SUES;", 'F'}, + {"0SUESB", 'F'}, + {"0SUESC", 'F'}, + {"0SUESF", 'F'}, + {"0SUESK", 'F'}, + {"0SUESO", 'F'}, + {"0SUESU", 'F'}, + {"0SUESV", 'F'}, + {"0SUEV", 'F'}, + {"0SUEV&", 'F'}, + {"0SUEV(", 'F'}, + {"0SUEV)", 'F'}, + {"0SUEV,", 'F'}, + {"0SUEV;", 'F'}, + {"0SUEVB", 'F'}, + {"0SUEVC", 'F'}, + {"0SUEVF", 'F'}, + {"0SUEVK", 'F'}, + {"0SUEVN", 'F'}, + {"0SUEVO", 'F'}, + {"0SUEVS", 'F'}, + {"0SUEVU", 'F'}, + {"0SUF()", 'F'}, + {"0SUF(1", 'F'}, + {"0SUF(F", 'F'}, + {"0SUF(N", 'F'}, + {"0SUF(S", 'F'}, + {"0SUF(V", 'F'}, + {"0SUK(E", 'F'}, + {"0SUO(E", 'F'}, + {"0SUON(", 'F'}, + {"0SUON1", 'F'}, + {"0SUONF", 'F'}, + {"0SUONS", 'F'}, + {"0SUS,(", 'F'}, + {"0SUS,F", 'F'}, + {"0SUSC", 'F'}, + {"0SUSO(", 'F'}, + {"0SUSO1", 'F'}, + {"0SUSOF", 'F'}, + {"0SUSON", 'F'}, + {"0SUSOS", 'F'}, + {"0SUSOV", 'F'}, + {"0SUTN(", 'F'}, + {"0SUTN1", 'F'}, + {"0SUTNF", 'F'}, + {"0SUTNN", 'F'}, + {"0SUTNS", 'F'}, + {"0SUTNV", 'F'}, + {"0SUV,(", 'F'}, + {"0SUV,F", 'F'}, + {"0SUVC", 'F'}, + {"0SUVO(", 'F'}, + {"0SUVOF", 'F'}, + {"0SUVOS", 'F'}, + {"0SVF()", 'F'}, + {"0SVF(1", 'F'}, + {"0SVF(F", 'F'}, + {"0SVF(N", 'F'}, + {"0SVF(S", 'F'}, + {"0SVF(V", 'F'}, + {"0SVO(1", 'F'}, + {"0SVO(F", 'F'}, + {"0SVO(N", 'F'}, + {"0SVO(S", 'F'}, + {"0SVO(V", 'F'}, + {"0SVOF(", 'F'}, + {"0SVOS(", 'F'}, + {"0SVOS1", 'F'}, + {"0SVOSF", 'F'}, + {"0SVOSU", 'F'}, + {"0SVOSV", 'F'}, + {"0SVS;", 'F'}, + {"0SVS;C", 'F'}, + {"0SVSC", 'F'}, + {"0SVSO(", 'F'}, + {"0SVSO1", 'F'}, + {"0SVSOF", 'F'}, + {"0SVSON", 'F'}, + {"0SVSOS", 'F'}, + {"0SVSOV", 'F'}, + {"0SVUE", 'F'}, + {"0SVUE;", 'F'}, + {"0SVUEC", 'F'}, + {"0SVUEK", 'F'}, + {"0T(1)F", 'F'}, + {"0T(1)O", 'F'}, + {"0T(1F(", 'F'}, + {"0T(1N)", 'F'}, + {"0T(1O(", 'F'}, + {"0T(1OF", 'F'}, + {"0T(1OS", 'F'}, + {"0T(1OV", 'F'}, + {"0T(1S)", 'F'}, + {"0T(1V)", 'F'}, + {"0T(1VO", 'F'}, + {"0T(F()", 'F'}, + {"0T(F(1", 'F'}, + {"0T(F(F", 'F'}, + {"0T(F(N", 'F'}, + {"0T(F(S", 'F'}, + {"0T(F(V", 'F'}, + {"0T(N(1", 'F'}, + {"0T(N(F", 'F'}, + {"0T(N(S", 'F'}, + {"0T(N(V", 'F'}, + {"0T(N)F", 'F'}, + {"0T(N)O", 'F'}, + {"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(SF(", 'F'}, + {"0T(SN)", 'F'}, + {"0T(SNO", 'F'}, + {"0T(SO(", 'F'}, + {"0T(SO1", 'F'}, + {"0T(SOF", 'F'}, + {"0T(SON", 'F'}, + {"0T(SOS", 'F'}, + {"0T(SOV", 'F'}, + {"0T(SV)", 'F'}, + {"0T(SVO", 'F'}, + {"0T(V)F", 'F'}, + {"0T(V)O", 'F'}, + {"0T(VF(", 'F'}, + {"0T(VO(", 'F'}, + {"0T(VOF", 'F'}, + {"0T(VOS", 'F'}, + {"0T(VS)", 'F'}, + {"0T(VSO", 'F'}, + {"0T(VV)", 'F'}, + {"0T1F(1", 'F'}, + {"0T1F(F", 'F'}, + {"0T1F(N", 'F'}, + {"0T1F(S", 'F'}, + {"0T1F(V", 'F'}, + {"0T1O(1", 'F'}, + {"0T1O(F", 'F'}, + {"0T1O(N", 'F'}, + {"0T1O(S", 'F'}, + {"0T1O(V", 'F'}, + {"0T1OF(", 'F'}, + {"0T1OSF", 'F'}, + {"0T1OVF", 'F'}, + {"0T1OVO", 'F'}, + {"0TF()F", 'F'}, + {"0TF()O", 'F'}, + {"0TF(1)", 'F'}, + {"0TF(1O", 'F'}, + {"0TF(F(", 'F'}, + {"0TF(N)", 'F'}, + {"0TF(NO", 'F'}, + {"0TF(S)", 'F'}, + {"0TF(SO", 'F'}, + {"0TF(V)", 'F'}, + {"0TF(VO", 'F'}, + {"0TN(1)", 'F'}, + {"0TN(1O", 'F'}, + {"0TN(F(", 'F'}, + {"0TN(S)", 'F'}, + {"0TN(SO", 'F'}, + {"0TN(V)", 'F'}, + {"0TN(VO", 'F'}, + {"0TN1;", 'F'}, + {"0TN1;C", 'F'}, + {"0TN1O(", 'F'}, + {"0TN1OF", 'F'}, + {"0TN1OS", 'F'}, + {"0TN1OV", 'F'}, + {"0TNF()", 'F'}, + {"0TNF(1", 'F'}, + {"0TNF(F", 'F'}, + {"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'}, + {"0TNO(S", 'F'}, + {"0TNO(V", 'F'}, + {"0TNOF(", 'F'}, + {"0TNOSF", 'F'}, + {"0TNOVF", 'F'}, + {"0TNOVO", 'F'}, + {"0TNS;", 'F'}, + {"0TNS;C", 'F'}, + {"0TNSO(", 'F'}, + {"0TNSO1", 'F'}, + {"0TNSOF", 'F'}, + {"0TNSON", 'F'}, + {"0TNSOS", 'F'}, + {"0TNSOV", 'F'}, + {"0TNV;", 'F'}, + {"0TNV;C", 'F'}, + {"0TNVO(", 'F'}, + {"0TNVOF", 'F'}, + {"0TNVOS", 'F'}, + {"0TSF(1", 'F'}, + {"0TSF(F", 'F'}, + {"0TSF(N", 'F'}, + {"0TSF(S", 'F'}, + {"0TSF(V", 'F'}, + {"0TSO(1", 'F'}, + {"0TSO(F", 'F'}, + {"0TSO(N", 'F'}, + {"0TSO(S", 'F'}, + {"0TSO(V", 'F'}, + {"0TSO1F", 'F'}, + {"0TSOF(", 'F'}, + {"0TSONF", 'F'}, + {"0TSOSF", 'F'}, + {"0TSOVF", 'F'}, + {"0TSOVO", 'F'}, + {"0TVF(1", 'F'}, + {"0TVF(F", 'F'}, + {"0TVF(N", 'F'}, + {"0TVF(S", 'F'}, + {"0TVF(V", 'F'}, + {"0TVO(1", 'F'}, + {"0TVO(F", 'F'}, + {"0TVO(N", 'F'}, + {"0TVO(S", 'F'}, + {"0TVO(V", 'F'}, + {"0TVOF(", 'F'}, + {"0TVOSF", 'F'}, + {"0U(E(1", 'F'}, + {"0U(E(F", 'F'}, + {"0U(E(K", 'F'}, + {"0U(E(N", 'F'}, + {"0U(E(S", 'F'}, + {"0U(E(V", 'F'}, + {"0U(E1)", 'F'}, + {"0U(E1O", 'F'}, + {"0U(EF(", 'F'}, + {"0U(EK(", 'F'}, + {"0U(EK1", 'F'}, + {"0U(EKF", 'F'}, + {"0U(EKN", 'F'}, + {"0U(EKO", 'F'}, + {"0U(EKS", 'F'}, + {"0U(EKV", 'F'}, + {"0U(EN)", 'F'}, + {"0U(ENK", 'F'}, + {"0U(ENO", 'F'}, + {"0U(EOK", 'F'}, + {"0U(ES)", 'F'}, + {"0U(ESO", 'F'}, + {"0U(EV)", 'F'}, + {"0U(EVO", 'F'}, + {"0UE(1)", 'F'}, + {"0UE(1,", 'F'}, + {"0UE(1O", 'F'}, + {"0UE(F(", 'F'}, + {"0UE(N)", 'F'}, + {"0UE(N,", 'F'}, + {"0UE(NO", 'F'}, + {"0UE(S)", 'F'}, + {"0UE(S,", 'F'}, + {"0UE(SO", 'F'}, + {"0UE(V)", 'F'}, + {"0UE(V,", 'F'}, + {"0UE(VO", 'F'}, + {"0UE1", 'F'}, + {"0UE1,(", 'F'}, + {"0UE1,F", 'F'}, + {"0UE1;", 'F'}, + {"0UE1;C", 'F'}, + {"0UE1C", 'F'}, + {"0UE1K(", 'F'}, + {"0UE1K1", 'F'}, + {"0UE1KF", 'F'}, + {"0UE1KN", 'F'}, + {"0UE1KS", 'F'}, + {"0UE1KV", 'F'}, + {"0UE1O(", 'F'}, + {"0UE1OF", 'F'}, + {"0UE1OS", 'F'}, + {"0UE1OV", 'F'}, + {"0UEF()", 'F'}, + {"0UEF(1", 'F'}, + {"0UEF(F", 'F'}, + {"0UEF(N", 'F'}, + {"0UEF(S", 'F'}, + {"0UEF(V", 'F'}, + {"0UEK(1", 'F'}, + {"0UEK(F", 'F'}, + {"0UEK(N", 'F'}, + {"0UEK(S", 'F'}, + {"0UEK(V", 'F'}, + {"0UEK1", 'F'}, + {"0UEK1,", 'F'}, + {"0UEK1;", 'F'}, + {"0UEK1C", 'F'}, + {"0UEK1K", 'F'}, + {"0UEK1O", 'F'}, + {"0UEKF(", 'F'}, + {"0UEKN", 'F'}, + {"0UEKN(", 'F'}, + {"0UEKN,", 'F'}, + {"0UEKN;", 'F'}, + {"0UEKNC", 'F'}, + {"0UEKNK", 'F'}, + {"0UEKS", 'F'}, + {"0UEKS,", 'F'}, + {"0UEKS;", 'F'}, + {"0UEKSC", 'F'}, + {"0UEKSK", 'F'}, + {"0UEKSO", 'F'}, + {"0UEKV", 'F'}, + {"0UEKV,", 'F'}, + {"0UEKV;", 'F'}, + {"0UEKVC", 'F'}, + {"0UEKVK", 'F'}, + {"0UEKVO", 'F'}, + {"0UEN()", 'F'}, + {"0UEN,(", 'F'}, + {"0UEN,F", 'F'}, + {"0UEN;", 'F'}, + {"0UEN;C", 'F'}, + {"0UENC", 'F'}, + {"0UENK(", 'F'}, + {"0UENK1", 'F'}, + {"0UENKF", 'F'}, + {"0UENKN", 'F'}, + {"0UENKS", 'F'}, + {"0UENKV", 'F'}, + {"0UENO(", 'F'}, + {"0UENOF", 'F'}, + {"0UENOS", 'F'}, + {"0UENOV", 'F'}, + {"0UES", 'F'}, + {"0UES,(", 'F'}, + {"0UES,F", 'F'}, + {"0UES;", 'F'}, + {"0UES;C", 'F'}, + {"0UESC", 'F'}, + {"0UESK(", 'F'}, + {"0UESK1", 'F'}, + {"0UESKF", 'F'}, + {"0UESKN", 'F'}, + {"0UESKS", 'F'}, + {"0UESKV", 'F'}, + {"0UESO(", 'F'}, + {"0UESO1", 'F'}, + {"0UESOF", 'F'}, + {"0UESON", 'F'}, + {"0UESOS", 'F'}, + {"0UESOV", 'F'}, + {"0UEV", 'F'}, + {"0UEV,(", 'F'}, + {"0UEV,F", 'F'}, + {"0UEV;", 'F'}, + {"0UEV;C", 'F'}, + {"0UEVC", 'F'}, + {"0UEVK(", 'F'}, + {"0UEVK1", 'F'}, + {"0UEVKF", 'F'}, + {"0UEVKN", 'F'}, + {"0UEVKS", 'F'}, + {"0UEVKV", 'F'}, + {"0UEVO(", 'F'}, + {"0UEVOF", 'F'}, + {"0UEVOS", 'F'}, + {"0UF(1O", 'F'}, + {"0UF(F(", 'F'}, + {"0UF(NO", 'F'}, + {"0UF(SO", 'F'}, + {"0UF(VO", 'F'}, + {"0V&(1&", 'F'}, + {"0V&(1)", 'F'}, + {"0V&(1,", 'F'}, + {"0V&(1O", 'F'}, + {"0V&(E(", 'F'}, + {"0V&(E1", 'F'}, + {"0V&(EF", 'F'}, + {"0V&(EK", 'F'}, + {"0V&(EN", 'F'}, + {"0V&(EO", 'F'}, + {"0V&(ES", 'F'}, + {"0V&(EV", 'F'}, + {"0V&(F(", 'F'}, + {"0V&(N&", 'F'}, + {"0V&(N)", 'F'}, + {"0V&(N,", 'F'}, + {"0V&(NO", 'F'}, + {"0V&(S&", 'F'}, + {"0V&(S)", 'F'}, + {"0V&(S,", 'F'}, + {"0V&(SO", 'F'}, + {"0V&(V&", 'F'}, + {"0V&(V)", 'F'}, + {"0V&(V,", 'F'}, + {"0V&(VO", 'F'}, + {"0V&1", 'F'}, + {"0V&1&(", 'F'}, + {"0V&1&1", 'F'}, + {"0V&1&F", 'F'}, + {"0V&1&N", 'F'}, + {"0V&1&S", 'F'}, + {"0V&1&V", 'F'}, + {"0V&1)&", 'F'}, + {"0V&1)C", 'F'}, + {"0V&1)O", 'F'}, + {"0V&1)U", 'F'}, + {"0V&1;", 'F'}, + {"0V&1;C", 'F'}, + {"0V&1;E", 'F'}, + {"0V&1;T", 'F'}, + {"0V&1B(", 'F'}, + {"0V&1B1", 'F'}, + {"0V&1BF", 'F'}, + {"0V&1BN", 'F'}, + {"0V&1BS", 'F'}, + {"0V&1BV", 'F'}, + {"0V&1C", 'F'}, + {"0V&1EK", 'F'}, + {"0V&1EN", 'F'}, + {"0V&1F(", 'F'}, + {"0V&1K(", 'F'}, + {"0V&1K1", 'F'}, + {"0V&1KF", 'F'}, + {"0V&1KN", 'F'}, + {"0V&1KS", 'F'}, + {"0V&1KV", 'F'}, + {"0V&1O(", 'F'}, + {"0V&1OF", 'F'}, + {"0V&1OS", 'F'}, + {"0V&1OV", 'F'}, + {"0V&1TN", 'F'}, + {"0V&1U", 'F'}, + {"0V&1U(", 'F'}, + {"0V&1U;", 'F'}, + {"0V&1UC", 'F'}, + {"0V&1UE", 'F'}, + {"0V&E(1", 'F'}, + {"0V&E(F", 'F'}, + {"0V&E(N", 'F'}, + {"0V&E(O", 'F'}, + {"0V&E(S", 'F'}, + {"0V&E(V", 'F'}, + {"0V&E1", 'F'}, + {"0V&E1;", 'F'}, + {"0V&E1C", 'F'}, + {"0V&E1K", 'F'}, + {"0V&E1O", 'F'}, + {"0V&EF(", 'F'}, + {"0V&EK(", 'F'}, + {"0V&EK1", 'F'}, + {"0V&EKF", 'F'}, + {"0V&EKN", 'F'}, + {"0V&EKS", 'F'}, + {"0V&EKV", 'F'}, + {"0V&EN", 'F'}, + {"0V&EN;", 'F'}, + {"0V&ENC", 'F'}, + {"0V&ENK", 'F'}, + {"0V&ENO", 'F'}, + {"0V&ES", 'F'}, + {"0V&ES;", 'F'}, + {"0V&ESC", 'F'}, + {"0V&ESK", 'F'}, + {"0V&ESO", 'F'}, + {"0V&EV", 'F'}, + {"0V&EV;", 'F'}, + {"0V&EVC", 'F'}, + {"0V&EVK", 'F'}, + {"0V&EVO", 'F'}, + {"0V&F()", 'F'}, + {"0V&F(1", 'F'}, + {"0V&F(E", 'F'}, + {"0V&F(F", 'F'}, + {"0V&F(N", 'F'}, + {"0V&F(S", 'F'}, + {"0V&F(V", 'F'}, + {"0V&K&(", 'F'}, + {"0V&K&1", 'F'}, + {"0V&K&F", 'F'}, + {"0V&K&N", 'F'}, + {"0V&K&S", 'F'}, + {"0V&K&V", 'F'}, + {"0V&K(1", 'F'}, + {"0V&K(F", 'F'}, + {"0V&K(N", 'F'}, + {"0V&K(S", 'F'}, + {"0V&K(V", 'F'}, + {"0V&K1O", 'F'}, + {"0V&KC", 'F'}, + {"0V&KF(", 'F'}, + {"0V&KNK", 'F'}, + {"0V&KO(", 'F'}, + {"0V&KO1", 'F'}, + {"0V&KOF", 'F'}, + {"0V&KOK", 'F'}, + {"0V&KON", 'F'}, + {"0V&KOS", 'F'}, + {"0V&KOV", 'F'}, + {"0V&KSO", 'F'}, + {"0V&KVO", 'F'}, + {"0V&N", 'F'}, + {"0V&N&(", 'F'}, + {"0V&N&1", 'F'}, + {"0V&N&F", 'F'}, + {"0V&N&N", 'F'}, + {"0V&N&S", 'F'}, + {"0V&N&V", 'F'}, + {"0V&N)&", 'F'}, + {"0V&N)C", 'F'}, + {"0V&N)O", 'F'}, + {"0V&N)U", 'F'}, + {"0V&N;", 'F'}, + {"0V&N;C", 'F'}, + {"0V&N;E", 'F'}, + {"0V&N;T", 'F'}, + {"0V&NB(", 'F'}, + {"0V&NB1", 'F'}, + {"0V&NBF", 'F'}, + {"0V&NBN", 'F'}, + {"0V&NBS", 'F'}, + {"0V&NBV", 'F'}, + {"0V&NC", 'F'}, + {"0V&NEN", 'F'}, + {"0V&NF(", 'F'}, + {"0V&NK(", 'F'}, + {"0V&NK1", 'F'}, + {"0V&NKF", 'F'}, + {"0V&NKN", 'F'}, + {"0V&NKS", 'F'}, + {"0V&NKV", 'F'}, + {"0V&NO(", 'F'}, + {"0V&NOF", 'F'}, + {"0V&NOS", 'F'}, + {"0V&NOV", 'F'}, + {"0V&NTN", 'F'}, + {"0V&NU", 'F'}, + {"0V&NU(", 'F'}, + {"0V&NU;", 'F'}, + {"0V&NUC", 'F'}, + {"0V&NUE", 'F'}, + {"0V&S", 'F'}, + {"0V&S&(", 'F'}, + {"0V&S&1", 'F'}, + {"0V&S&F", 'F'}, + {"0V&S&N", 'F'}, + {"0V&S&S", 'F'}, + {"0V&S&V", 'F'}, + {"0V&S)&", 'F'}, + {"0V&S)C", 'F'}, + {"0V&S)O", 'F'}, + {"0V&S)U", 'F'}, + {"0V&S1", 'F'}, + {"0V&S1;", 'F'}, + {"0V&S1C", 'F'}, + {"0V&S;", 'F'}, + {"0V&S;C", 'F'}, + {"0V&S;E", 'F'}, + {"0V&S;T", 'F'}, + {"0V&SB(", 'F'}, + {"0V&SB1", 'F'}, + {"0V&SBF", 'F'}, + {"0V&SBN", 'F'}, + {"0V&SBS", 'F'}, + {"0V&SBV", 'F'}, + {"0V&SC", 'F'}, + {"0V&SEK", 'F'}, + {"0V&SEN", 'F'}, + {"0V&SF(", 'F'}, + {"0V&SK(", 'F'}, + {"0V&SK1", 'F'}, + {"0V&SKF", 'F'}, + {"0V&SKN", 'F'}, + {"0V&SKS", 'F'}, + {"0V&SKV", 'F'}, + {"0V&SO(", 'F'}, + {"0V&SO1", 'F'}, + {"0V&SOF", 'F'}, + {"0V&SON", 'F'}, + {"0V&SOS", 'F'}, + {"0V&SOV", 'F'}, + {"0V&STN", 'F'}, + {"0V&SU", 'F'}, + {"0V&SU(", 'F'}, + {"0V&SU;", 'F'}, + {"0V&SUC", 'F'}, + {"0V&SUE", 'F'}, + {"0V&SV", 'F'}, + {"0V&SV;", 'F'}, + {"0V&SVC", 'F'}, + {"0V&SVO", 'F'}, + {"0V&V", 'F'}, + {"0V&V&(", 'F'}, + {"0V&V&1", 'F'}, + {"0V&V&F", 'F'}, + {"0V&V&N", 'F'}, + {"0V&V&S", 'F'}, + {"0V&V&V", 'F'}, + {"0V&V)&", 'F'}, + {"0V&V)C", 'F'}, + {"0V&V)O", 'F'}, + {"0V&V)U", 'F'}, + {"0V&V;", 'F'}, + {"0V&V;C", 'F'}, + {"0V&V;E", 'F'}, + {"0V&V;T", 'F'}, + {"0V&VB(", 'F'}, + {"0V&VB1", 'F'}, + {"0V&VBF", 'F'}, + {"0V&VBN", 'F'}, + {"0V&VBS", 'F'}, + {"0V&VBV", 'F'}, + {"0V&VC", 'F'}, + {"0V&VEK", 'F'}, + {"0V&VEN", 'F'}, + {"0V&VF(", 'F'}, + {"0V&VK(", 'F'}, + {"0V&VK1", 'F'}, + {"0V&VKF", 'F'}, + {"0V&VKN", 'F'}, + {"0V&VKS", 'F'}, + {"0V&VKV", 'F'}, + {"0V&VO(", 'F'}, + {"0V&VOF", 'F'}, + {"0V&VOS", 'F'}, + {"0V&VS", 'F'}, + {"0V&VS;", 'F'}, + {"0V&VSC", 'F'}, + {"0V&VSO", 'F'}, + {"0V&VTN", 'F'}, + {"0V&VU", 'F'}, + {"0V&VU(", 'F'}, + {"0V&VU;", 'F'}, + {"0V&VUC", 'F'}, + {"0V&VUE", 'F'}, + {"0V(EF(", 'F'}, + {"0V(EKF", 'F'}, + {"0V(EKN", 'F'}, + {"0V(ENK", 'F'}, + {"0V(U(E", 'F'}, + {"0V)&(1", 'F'}, + {"0V)&(E", 'F'}, + {"0V)&(F", 'F'}, + {"0V)&(N", 'F'}, + {"0V)&(S", 'F'}, + {"0V)&(V", 'F'}, + {"0V)&1", 'F'}, + {"0V)&1&", 'F'}, + {"0V)&1)", 'F'}, + {"0V)&1;", 'F'}, + {"0V)&1B", 'F'}, + {"0V)&1C", 'F'}, + {"0V)&1F", 'F'}, + {"0V)&1O", 'F'}, + {"0V)&1U", 'F'}, + {"0V)&F(", 'F'}, + {"0V)&N", 'F'}, + {"0V)&N&", 'F'}, + {"0V)&N)", 'F'}, + {"0V)&N;", 'F'}, + {"0V)&NB", 'F'}, + {"0V)&NC", 'F'}, + {"0V)&NF", 'F'}, + {"0V)&NO", 'F'}, + {"0V)&NU", 'F'}, + {"0V)&S", 'F'}, + {"0V)&S&", 'F'}, + {"0V)&S)", 'F'}, + {"0V)&S;", 'F'}, + {"0V)&SB", 'F'}, + {"0V)&SC", 'F'}, + {"0V)&SF", 'F'}, + {"0V)&SO", 'F'}, + {"0V)&SU", 'F'}, + {"0V)&V", 'F'}, + {"0V)&V&", 'F'}, + {"0V)&V)", 'F'}, + {"0V)&V;", 'F'}, + {"0V)&VB", 'F'}, + {"0V)&VC", 'F'}, + {"0V)&VF", 'F'}, + {"0V)&VO", 'F'}, + {"0V)&VU", 'F'}, + {"0V),(1", 'F'}, + {"0V),(F", 'F'}, + {"0V),(N", 'F'}, + {"0V),(S", 'F'}, + {"0V),(V", 'F'}, + {"0V);E(", 'F'}, + {"0V);E1", 'F'}, + {"0V);EF", 'F'}, + {"0V);EK", 'F'}, + {"0V);EN", 'F'}, + {"0V);EO", 'F'}, + {"0V);ES", 'F'}, + {"0V);EV", 'F'}, + {"0V);T(", 'F'}, + {"0V);T1", 'F'}, + {"0V);TF", 'F'}, + {"0V);TK", 'F'}, + {"0V);TN", 'F'}, + {"0V);TO", 'F'}, + {"0V);TS", 'F'}, + {"0V);TV", 'F'}, + {"0V)B(1", 'F'}, + {"0V)B(F", 'F'}, + {"0V)B(N", 'F'}, + {"0V)B(S", 'F'}, + {"0V)B(V", 'F'}, + {"0V)B1", 'F'}, + {"0V)B1&", 'F'}, + {"0V)B1;", 'F'}, + {"0V)B1C", 'F'}, + {"0V)B1K", 'F'}, + {"0V)B1N", 'F'}, + {"0V)B1O", 'F'}, + {"0V)B1U", 'F'}, + {"0V)BF(", 'F'}, + {"0V)BN", 'F'}, + {"0V)BN&", 'F'}, + {"0V)BN;", 'F'}, + {"0V)BNC", 'F'}, + {"0V)BNK", 'F'}, + {"0V)BNO", 'F'}, + {"0V)BNU", 'F'}, + {"0V)BS", 'F'}, + {"0V)BS&", 'F'}, + {"0V)BS;", 'F'}, + {"0V)BSC", 'F'}, + {"0V)BSK", 'F'}, + {"0V)BSO", 'F'}, + {"0V)BSU", 'F'}, + {"0V)BV", 'F'}, + {"0V)BV&", 'F'}, + {"0V)BV;", 'F'}, + {"0V)BVC", 'F'}, + {"0V)BVK", 'F'}, + {"0V)BVO", 'F'}, + {"0V)BVU", 'F'}, + {"0V)C", 'F'}, + {"0V)E(1", 'F'}, + {"0V)E(F", 'F'}, + {"0V)E(N", 'F'}, + {"0V)E(S", 'F'}, + {"0V)E(V", 'F'}, + {"0V)E1C", 'F'}, + {"0V)E1O", 'F'}, + {"0V)EF(", 'F'}, + {"0V)EK(", 'F'}, + {"0V)EK1", 'F'}, + {"0V)EKF", 'F'}, + {"0V)EKN", 'F'}, + {"0V)EKS", 'F'}, + {"0V)EKV", 'F'}, + {"0V)ENC", 'F'}, + {"0V)ENO", 'F'}, + {"0V)ESC", 'F'}, + {"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'}, + {"0V)K(S", 'F'}, + {"0V)K(V", 'F'}, + {"0V)K1&", 'F'}, + {"0V)K1;", 'F'}, + {"0V)K1B", 'F'}, + {"0V)K1E", 'F'}, + {"0V)K1O", 'F'}, + {"0V)K1U", 'F'}, + {"0V)KB(", 'F'}, + {"0V)KB1", 'F'}, + {"0V)KBF", 'F'}, + {"0V)KBN", 'F'}, + {"0V)KBS", 'F'}, + {"0V)KBV", 'F'}, + {"0V)KF(", 'F'}, + {"0V)KN&", 'F'}, + {"0V)KN;", 'F'}, + {"0V)KNB", 'F'}, + {"0V)KNC", 'F'}, + {"0V)KNE", 'F'}, + {"0V)KNK", 'F'}, + {"0V)KNU", 'F'}, + {"0V)KS&", 'F'}, + {"0V)KS;", 'F'}, + {"0V)KSB", 'F'}, + {"0V)KSE", 'F'}, + {"0V)KSO", 'F'}, + {"0V)KSU", 'F'}, + {"0V)KUE", 'F'}, + {"0V)KV&", 'F'}, + {"0V)KV;", 'F'}, + {"0V)KVB", 'F'}, + {"0V)KVE", 'F'}, + {"0V)KVO", 'F'}, + {"0V)KVU", 'F'}, + {"0V)O(1", 'F'}, + {"0V)O(E", 'F'}, + {"0V)O(F", 'F'}, + {"0V)O(N", 'F'}, + {"0V)O(S", 'F'}, + {"0V)O(V", 'F'}, + {"0V)O1", 'F'}, + {"0V)O1&", 'F'}, + {"0V)O1)", 'F'}, + {"0V)O1;", 'F'}, + {"0V)O1B", 'F'}, + {"0V)O1C", 'F'}, + {"0V)O1K", 'F'}, + {"0V)O1U", 'F'}, + {"0V)OF(", 'F'}, + {"0V)ON", 'F'}, + {"0V)ON&", 'F'}, + {"0V)ON)", 'F'}, + {"0V)ON;", 'F'}, + {"0V)ONB", 'F'}, + {"0V)ONC", 'F'}, + {"0V)ONK", 'F'}, + {"0V)ONU", 'F'}, + {"0V)OS", 'F'}, + {"0V)OS&", 'F'}, + {"0V)OS)", 'F'}, + {"0V)OS;", 'F'}, + {"0V)OSB", 'F'}, + {"0V)OSC", 'F'}, + {"0V)OSK", 'F'}, + {"0V)OSU", 'F'}, + {"0V)OV", 'F'}, + {"0V)OV&", 'F'}, + {"0V)OV)", 'F'}, + {"0V)OV;", 'F'}, + {"0V)OVB", 'F'}, + {"0V)OVC", 'F'}, + {"0V)OVK", 'F'}, + {"0V)OVO", 'F'}, + {"0V)OVU", 'F'}, + {"0V)U(E", 'F'}, + {"0V)UE(", 'F'}, + {"0V)UE1", 'F'}, + {"0V)UEF", 'F'}, + {"0V)UEK", 'F'}, + {"0V)UEN", 'F'}, + {"0V)UES", 'F'}, + {"0V)UEV", 'F'}, + {"0V,(1)", 'F'}, + {"0V,(1O", 'F'}, + {"0V,(E(", 'F'}, + {"0V,(E1", 'F'}, + {"0V,(EF", 'F'}, + {"0V,(EK", 'F'}, + {"0V,(EN", 'F'}, + {"0V,(ES", 'F'}, + {"0V,(EV", 'F'}, + {"0V,(F(", 'F'}, + {"0V,(N)", 'F'}, + {"0V,(NO", 'F'}, + {"0V,(S)", 'F'}, + {"0V,(SO", 'F'}, + {"0V,(V)", 'F'}, + {"0V,(VO", 'F'}, + {"0V,F()", 'F'}, + {"0V,F(1", 'F'}, + {"0V,F(F", 'F'}, + {"0V,F(N", 'F'}, + {"0V,F(S", 'F'}, + {"0V,F(V", 'F'}, + {"0V;E(1", 'F'}, + {"0V;E(E", 'F'}, + {"0V;E(F", 'F'}, + {"0V;E(N", 'F'}, + {"0V;E(S", 'F'}, + {"0V;E(V", 'F'}, + {"0V;E1,", 'F'}, + {"0V;E1;", 'F'}, + {"0V;E1C", 'F'}, + {"0V;E1K", 'F'}, + {"0V;E1O", 'F'}, + {"0V;E1T", 'F'}, + {"0V;EF(", 'F'}, + {"0V;EK(", 'F'}, + {"0V;EK1", 'F'}, + {"0V;EKF", 'F'}, + {"0V;EKN", 'F'}, + {"0V;EKO", 'F'}, + {"0V;EKS", 'F'}, + {"0V;EKV", 'F'}, + {"0V;EN,", 'F'}, + {"0V;EN;", 'F'}, + {"0V;ENC", 'F'}, + {"0V;ENE", 'F'}, + {"0V;ENK", 'F'}, + {"0V;ENO", 'F'}, + {"0V;ENT", 'F'}, + {"0V;ES,", 'F'}, + {"0V;ES;", 'F'}, + {"0V;ESC", 'F'}, + {"0V;ESK", 'F'}, + {"0V;ESO", 'F'}, + {"0V;EST", 'F'}, + {"0V;EV,", 'F'}, + {"0V;EV;", 'F'}, + {"0V;EVC", 'F'}, + {"0V;EVK", 'F'}, + {"0V;EVO", 'F'}, + {"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'}, + {"0V;T1F", 'F'}, + {"0V;T1K", 'F'}, + {"0V;T1O", 'F'}, + {"0V;T1T", 'F'}, + {"0V;T;", 'F'}, + {"0V;T;C", 'F'}, + {"0V;TF(", 'F'}, + {"0V;TK(", 'F'}, + {"0V;TK1", 'F'}, + {"0V;TKF", 'F'}, + {"0V;TKK", 'F'}, + {"0V;TKN", 'F'}, + {"0V;TKO", 'F'}, + {"0V;TKS", 'F'}, + {"0V;TKV", 'F'}, + {"0V;TN(", 'F'}, + {"0V;TN,", 'F'}, + {"0V;TN1", 'F'}, + {"0V;TN;", 'F'}, + {"0V;TNC", 'F'}, + {"0V;TNE", 'F'}, + {"0V;TNF", 'F'}, + {"0V;TNK", 'F'}, + {"0V;TNN", 'F'}, + {"0V;TNO", 'F'}, + {"0V;TNS", 'F'}, + {"0V;TNT", 'F'}, + {"0V;TNV", 'F'}, + {"0V;TO(", 'F'}, + {"0V;TS(", 'F'}, + {"0V;TS,", 'F'}, + {"0V;TS;", 'F'}, + {"0V;TSC", 'F'}, + {"0V;TSF", 'F'}, + {"0V;TSK", 'F'}, + {"0V;TSO", 'F'}, + {"0V;TST", 'F'}, + {"0V;TTN", 'F'}, + {"0V;TV(", 'F'}, + {"0V;TV,", 'F'}, + {"0V;TV;", 'F'}, + {"0V;TVC", 'F'}, + {"0V;TVF", 'F'}, + {"0V;TVK", 'F'}, + {"0V;TVO", 'F'}, + {"0V;TVT", 'F'}, + {"0VA(F(", 'F'}, + {"0VA(N)", 'F'}, + {"0VA(NO", 'F'}, + {"0VA(S)", 'F'}, + {"0VA(SO", 'F'}, + {"0VA(V)", 'F'}, + {"0VA(VO", 'F'}, + {"0VAF()", 'F'}, + {"0VAF(1", 'F'}, + {"0VAF(F", 'F'}, + {"0VAF(N", 'F'}, + {"0VAF(S", 'F'}, + {"0VAF(V", 'F'}, + {"0VASO(", 'F'}, + {"0VASO1", 'F'}, + {"0VASOF", 'F'}, + {"0VASON", 'F'}, + {"0VASOS", 'F'}, + {"0VASOV", 'F'}, + {"0VASUE", 'F'}, + {"0VATO(", 'F'}, + {"0VATO1", 'F'}, + {"0VATOF", 'F'}, + {"0VATON", 'F'}, + {"0VATOS", 'F'}, + {"0VATOV", 'F'}, + {"0VATUE", 'F'}, + {"0VAVO(", 'F'}, + {"0VAVOF", 'F'}, + {"0VAVOS", 'F'}, + {"0VAVUE", 'F'}, + {"0VB(1)", 'F'}, + {"0VB(1O", 'F'}, + {"0VB(F(", 'F'}, + {"0VB(NO", 'F'}, + {"0VB(S)", 'F'}, + {"0VB(SO", 'F'}, + {"0VB(V)", 'F'}, + {"0VB(VO", 'F'}, + {"0VB1", 'F'}, + {"0VB1&(", 'F'}, + {"0VB1&1", 'F'}, + {"0VB1&F", 'F'}, + {"0VB1&N", 'F'}, + {"0VB1&S", 'F'}, + {"0VB1&V", 'F'}, + {"0VB1,(", 'F'}, + {"0VB1,F", 'F'}, + {"0VB1;", 'F'}, + {"0VB1;C", 'F'}, + {"0VB1B(", 'F'}, + {"0VB1B1", 'F'}, + {"0VB1BF", 'F'}, + {"0VB1BN", 'F'}, + {"0VB1BS", 'F'}, + {"0VB1BV", 'F'}, + {"0VB1C", 'F'}, + {"0VB1K(", 'F'}, + {"0VB1K1", 'F'}, + {"0VB1KF", 'F'}, + {"0VB1KN", 'F'}, + {"0VB1KS", 'F'}, + {"0VB1KV", 'F'}, + {"0VB1O(", 'F'}, + {"0VB1OF", 'F'}, + {"0VB1OS", 'F'}, + {"0VB1OV", 'F'}, + {"0VB1U(", 'F'}, + {"0VB1UE", 'F'}, + {"0VBE(1", 'F'}, + {"0VBE(F", 'F'}, + {"0VBE(N", 'F'}, + {"0VBE(S", 'F'}, + {"0VBE(V", 'F'}, + {"0VBEK(", 'F'}, + {"0VBF()", 'F'}, + {"0VBF(1", 'F'}, + {"0VBF(F", 'F'}, + {"0VBF(N", 'F'}, + {"0VBF(S", 'F'}, + {"0VBF(V", 'F'}, + {"0VBN", 'F'}, + {"0VBN&(", 'F'}, + {"0VBN&1", 'F'}, + {"0VBN&F", 'F'}, + {"0VBN&N", 'F'}, + {"0VBN&S", 'F'}, + {"0VBN&V", 'F'}, + {"0VBN,(", 'F'}, + {"0VBN,F", 'F'}, + {"0VBN;", 'F'}, + {"0VBN;C", 'F'}, + {"0VBNB(", 'F'}, + {"0VBNB1", 'F'}, + {"0VBNBF", 'F'}, + {"0VBNBN", 'F'}, + {"0VBNBS", 'F'}, + {"0VBNBV", 'F'}, + {"0VBNC", 'F'}, + {"0VBNK(", 'F'}, + {"0VBNK1", 'F'}, + {"0VBNKF", 'F'}, + {"0VBNKN", 'F'}, + {"0VBNKS", 'F'}, + {"0VBNKV", 'F'}, + {"0VBNO(", 'F'}, + {"0VBNOF", 'F'}, + {"0VBNOS", 'F'}, + {"0VBNOV", 'F'}, + {"0VBNU(", 'F'}, + {"0VBNUE", 'F'}, + {"0VBS", 'F'}, + {"0VBS&(", 'F'}, + {"0VBS&1", 'F'}, + {"0VBS&F", 'F'}, + {"0VBS&N", 'F'}, + {"0VBS&S", 'F'}, + {"0VBS&V", 'F'}, + {"0VBS,(", 'F'}, + {"0VBS,F", 'F'}, + {"0VBS;", 'F'}, + {"0VBS;C", 'F'}, + {"0VBSB(", 'F'}, + {"0VBSB1", 'F'}, + {"0VBSBF", 'F'}, + {"0VBSBN", 'F'}, + {"0VBSBS", 'F'}, + {"0VBSBV", 'F'}, + {"0VBSC", 'F'}, + {"0VBSK(", 'F'}, + {"0VBSK1", 'F'}, + {"0VBSKF", 'F'}, + {"0VBSKN", 'F'}, + {"0VBSKS", 'F'}, + {"0VBSKV", 'F'}, + {"0VBSO(", 'F'}, + {"0VBSO1", 'F'}, + {"0VBSOF", 'F'}, + {"0VBSON", 'F'}, + {"0VBSOS", 'F'}, + {"0VBSOV", 'F'}, + {"0VBSU(", 'F'}, + {"0VBSUE", 'F'}, + {"0VBV", 'F'}, + {"0VBV&(", 'F'}, + {"0VBV&1", 'F'}, + {"0VBV&F", 'F'}, + {"0VBV&N", 'F'}, + {"0VBV&S", 'F'}, + {"0VBV&V", 'F'}, + {"0VBV,(", 'F'}, + {"0VBV,F", 'F'}, + {"0VBV;", 'F'}, + {"0VBV;C", 'F'}, + {"0VBVB(", 'F'}, + {"0VBVB1", 'F'}, + {"0VBVBF", 'F'}, + {"0VBVBN", 'F'}, + {"0VBVBS", 'F'}, + {"0VBVBV", 'F'}, + {"0VBVC", 'F'}, + {"0VBVK(", 'F'}, + {"0VBVK1", 'F'}, + {"0VBVKF", 'F'}, + {"0VBVKN", 'F'}, + {"0VBVKS", 'F'}, + {"0VBVKV", 'F'}, + {"0VBVO(", 'F'}, + {"0VBVOF", 'F'}, + {"0VBVOS", 'F'}, + {"0VBVU(", 'F'}, + {"0VBVUE", 'F'}, + {"0VC", 'F'}, + {"0VE(1)", 'F'}, + {"0VE(1O", 'F'}, + {"0VE(F(", 'F'}, + {"0VE(N)", 'F'}, + {"0VE(NO", 'F'}, + {"0VE(S)", 'F'}, + {"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'}, + {"0VEF(F", 'F'}, + {"0VEF(N", 'F'}, + {"0VEF(S", 'F'}, + {"0VEF(V", 'F'}, + {"0VEK(1", 'F'}, + {"0VEK(E", 'F'}, + {"0VEK(F", 'F'}, + {"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'}, + {"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'}, + {"0VESOF", 'F'}, + {"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'}, + {"0VEU(N", 'F'}, + {"0VEU(S", 'F'}, + {"0VEU(V", 'F'}, + {"0VEU1,", 'F'}, + {"0VEU1C", 'F'}, + {"0VEU1O", 'F'}, + {"0VEUEF", 'F'}, + {"0VEUEK", 'F'}, + {"0VEUF(", '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'}, + {"0VF()K", 'F'}, + {"0VF()N", 'F'}, + {"0VF()O", 'F'}, + {"0VF()S", 'F'}, + {"0VF()U", 'F'}, + {"0VF()V", 'F'}, + {"0VF(1)", 'F'}, + {"0VF(1N", 'F'}, + {"0VF(1O", 'F'}, + {"0VF(E(", 'F'}, + {"0VF(E1", 'F'}, + {"0VF(EF", 'F'}, + {"0VF(EK", 'F'}, + {"0VF(EN", 'F'}, + {"0VF(ES", 'F'}, + {"0VF(EV", 'F'}, + {"0VF(F(", 'F'}, + {"0VF(N)", 'F'}, + {"0VF(N,", 'F'}, + {"0VF(NO", 'F'}, + {"0VF(S)", 'F'}, + {"0VF(SO", 'F'}, + {"0VF(V)", 'F'}, + {"0VF(VO", 'F'}, + {"0VK(1)", 'F'}, + {"0VK(1O", 'F'}, + {"0VK(F(", 'F'}, + {"0VK(N)", 'F'}, + {"0VK(NO", 'F'}, + {"0VK(S)", 'F'}, + {"0VK(SO", 'F'}, + {"0VK(V)", 'F'}, + {"0VK(VO", 'F'}, + {"0VK)&(", 'F'}, + {"0VK)&1", 'F'}, + {"0VK)&F", 'F'}, + {"0VK)&N", 'F'}, + {"0VK)&S", 'F'}, + {"0VK)&V", 'F'}, + {"0VK);E", 'F'}, + {"0VK);T", 'F'}, + {"0VK)B(", 'F'}, + {"0VK)B1", 'F'}, + {"0VK)BF", 'F'}, + {"0VK)BN", 'F'}, + {"0VK)BS", 'F'}, + {"0VK)BV", 'F'}, + {"0VK)E(", 'F'}, + {"0VK)E1", 'F'}, + {"0VK)EF", 'F'}, + {"0VK)EK", 'F'}, + {"0VK)EN", 'F'}, + {"0VK)ES", 'F'}, + {"0VK)EV", 'F'}, + {"0VK)F(", 'F'}, + {"0VK)O(", 'F'}, + {"0VK)OF", 'F'}, + {"0VK)UE", 'F'}, + {"0VK1", 'F'}, + {"0VK1&(", 'F'}, + {"0VK1&1", 'F'}, + {"0VK1&F", 'F'}, + {"0VK1&N", 'F'}, + {"0VK1&S", 'F'}, + {"0VK1&V", 'F'}, + {"0VK1;", 'F'}, + {"0VK1;C", 'F'}, + {"0VK1;E", 'F'}, + {"0VK1;T", 'F'}, + {"0VK1B(", 'F'}, + {"0VK1B1", 'F'}, + {"0VK1BF", 'F'}, + {"0VK1BN", 'F'}, + {"0VK1BS", 'F'}, + {"0VK1BV", 'F'}, + {"0VK1C", 'F'}, + {"0VK1E(", 'F'}, + {"0VK1E1", 'F'}, + {"0VK1EF", 'F'}, + {"0VK1EK", 'F'}, + {"0VK1EN", 'F'}, + {"0VK1ES", 'F'}, + {"0VK1EV", 'F'}, + {"0VK1O(", 'F'}, + {"0VK1OF", 'F'}, + {"0VK1OS", 'F'}, + {"0VK1OV", 'F'}, + {"0VK1U(", 'F'}, + {"0VK1UE", 'F'}, + {"0VKF()", 'F'}, + {"0VKF(1", 'F'}, + {"0VKF(F", 'F'}, + {"0VKF(N", 'F'}, + {"0VKF(S", 'F'}, + {"0VKF(V", 'F'}, + {"0VKN", 'F'}, + {"0VKN&(", 'F'}, + {"0VKN&1", 'F'}, + {"0VKN&F", 'F'}, + {"0VKN&N", 'F'}, + {"0VKN&S", 'F'}, + {"0VKN&V", 'F'}, + {"0VKN;", 'F'}, + {"0VKN;C", 'F'}, + {"0VKN;E", 'F'}, + {"0VKN;T", 'F'}, + {"0VKNB(", 'F'}, + {"0VKNB1", 'F'}, + {"0VKNBF", 'F'}, + {"0VKNBN", 'F'}, + {"0VKNBS", 'F'}, + {"0VKNBV", 'F'}, + {"0VKNC", 'F'}, + {"0VKNE(", 'F'}, + {"0VKNE1", 'F'}, + {"0VKNEF", 'F'}, + {"0VKNEN", 'F'}, + {"0VKNES", 'F'}, + {"0VKNEV", 'F'}, + {"0VKNU(", 'F'}, + {"0VKNUE", 'F'}, + {"0VKS", 'F'}, + {"0VKS&(", 'F'}, + {"0VKS&1", 'F'}, + {"0VKS&F", 'F'}, + {"0VKS&N", 'F'}, + {"0VKS&S", 'F'}, + {"0VKS&V", 'F'}, + {"0VKS;", 'F'}, + {"0VKS;C", 'F'}, + {"0VKS;E", 'F'}, + {"0VKS;T", 'F'}, + {"0VKSB(", 'F'}, + {"0VKSB1", 'F'}, + {"0VKSBF", 'F'}, + {"0VKSBN", 'F'}, + {"0VKSBS", 'F'}, + {"0VKSBV", 'F'}, + {"0VKSC", 'F'}, + {"0VKSE(", 'F'}, + {"0VKSE1", 'F'}, + {"0VKSEF", 'F'}, + {"0VKSEK", 'F'}, + {"0VKSEN", 'F'}, + {"0VKSES", 'F'}, + {"0VKSEV", 'F'}, + {"0VKSO(", 'F'}, + {"0VKSO1", 'F'}, + {"0VKSOF", 'F'}, + {"0VKSON", 'F'}, + {"0VKSOS", 'F'}, + {"0VKSOV", 'F'}, + {"0VKSU(", 'F'}, + {"0VKSUE", 'F'}, + {"0VKUE(", 'F'}, + {"0VKUE1", 'F'}, + {"0VKUEF", 'F'}, + {"0VKUEK", 'F'}, + {"0VKUEN", 'F'}, + {"0VKUES", 'F'}, + {"0VKUEV", 'F'}, + {"0VKV", 'F'}, + {"0VKV&(", 'F'}, + {"0VKV&1", 'F'}, + {"0VKV&F", 'F'}, + {"0VKV&N", 'F'}, + {"0VKV&S", 'F'}, + {"0VKV&V", 'F'}, + {"0VKV;", 'F'}, + {"0VKV;C", 'F'}, + {"0VKV;E", 'F'}, + {"0VKV;T", 'F'}, + {"0VKVB(", 'F'}, + {"0VKVB1", 'F'}, + {"0VKVBF", 'F'}, + {"0VKVBN", 'F'}, + {"0VKVBS", 'F'}, + {"0VKVBV", 'F'}, + {"0VKVC", 'F'}, + {"0VKVE(", 'F'}, + {"0VKVE1", 'F'}, + {"0VKVEF", 'F'}, + {"0VKVEK", 'F'}, + {"0VKVEN", 'F'}, + {"0VKVES", 'F'}, + {"0VKVEV", 'F'}, + {"0VKVO(", 'F'}, + {"0VKVOF", 'F'}, + {"0VKVOS", 'F'}, + {"0VKVU(", 'F'}, + {"0VKVUE", 'F'}, + {"0VO(1&", 'F'}, + {"0VO(1)", 'F'}, + {"0VO(1,", 'F'}, + {"0VO(1O", 'F'}, + {"0VO(E(", 'F'}, + {"0VO(E1", 'F'}, + {"0VO(EE", 'F'}, + {"0VO(EF", 'F'}, + {"0VO(EK", 'F'}, + {"0VO(EN", 'F'}, + {"0VO(EO", 'F'}, + {"0VO(ES", 'F'}, + {"0VO(EV", 'F'}, + {"0VO(F(", 'F'}, + {"0VO(N&", 'F'}, + {"0VO(N)", 'F'}, + {"0VO(N,", 'F'}, + {"0VO(NO", 'F'}, + {"0VO(S&", 'F'}, + {"0VO(S)", 'F'}, + {"0VO(S,", 'F'}, + {"0VO(SO", 'F'}, + {"0VO(V&", 'F'}, + {"0VO(V)", 'F'}, + {"0VO(V,", 'F'}, + {"0VO(VO", 'F'}, + {"0VOF()", 'F'}, + {"0VOF(1", 'F'}, + {"0VOF(E", 'F'}, + {"0VOF(F", 'F'}, + {"0VOF(N", 'F'}, + {"0VOF(S", 'F'}, + {"0VOF(V", 'F'}, + {"0VOK&(", 'F'}, + {"0VOK&1", 'F'}, + {"0VOK&F", 'F'}, + {"0VOK&N", 'F'}, + {"0VOK&S", 'F'}, + {"0VOK&V", 'F'}, + {"0VOK(1", 'F'}, + {"0VOK(F", 'F'}, + {"0VOK(N", 'F'}, + {"0VOK(S", 'F'}, + {"0VOK(V", 'F'}, + {"0VOK1C", 'F'}, + {"0VOK1O", 'F'}, + {"0VOKF(", 'F'}, + {"0VOKNC", 'F'}, + {"0VOKO(", 'F'}, + {"0VOKO1", 'F'}, + {"0VOKOF", 'F'}, + {"0VOKON", 'F'}, + {"0VOKOS", 'F'}, + {"0VOKOV", 'F'}, + {"0VOKSC", 'F'}, + {"0VOKSO", 'F'}, + {"0VOKVC", 'F'}, + {"0VOKVO", 'F'}, + {"0VOS", 'F'}, + {"0VOS&(", 'F'}, + {"0VOS&1", 'F'}, + {"0VOS&E", 'F'}, + {"0VOS&F", 'F'}, + {"0VOS&K", 'F'}, + {"0VOS&N", 'F'}, + {"0VOS&S", 'F'}, + {"0VOS&U", 'F'}, + {"0VOS&V", 'F'}, + {"0VOS(E", 'F'}, + {"0VOS(U", 'F'}, + {"0VOS)&", 'F'}, + {"0VOS),", 'F'}, + {"0VOS);", 'F'}, + {"0VOS)B", 'F'}, + {"0VOS)C", 'F'}, + {"0VOS)E", 'F'}, + {"0VOS)F", 'F'}, + {"0VOS)K", 'F'}, + {"0VOS)O", 'F'}, + {"0VOS)U", 'F'}, + {"0VOS,(", 'F'}, + {"0VOS,F", 'F'}, + {"0VOS1(", 'F'}, + {"0VOS1F", 'F'}, + {"0VOS1N", 'F'}, + {"0VOS1S", 'F'}, + {"0VOS1U", 'F'}, + {"0VOS1V", 'F'}, + {"0VOS;", 'F'}, + {"0VOS;C", 'F'}, + {"0VOS;E", 'F'}, + {"0VOS;N", 'F'}, + {"0VOS;T", 'F'}, + {"0VOSA(", 'F'}, + {"0VOSAF", 'F'}, + {"0VOSAS", 'F'}, + {"0VOSAT", 'F'}, + {"0VOSAV", 'F'}, + {"0VOSB(", 'F'}, + {"0VOSB1", 'F'}, + {"0VOSBE", 'F'}, + {"0VOSBF", 'F'}, + {"0VOSBN", 'F'}, + {"0VOSBS", 'F'}, + {"0VOSBV", 'F'}, + {"0VOSC", 'F'}, + {"0VOSE(", 'F'}, + {"0VOSE1", 'F'}, + {"0VOSEF", 'F'}, + {"0VOSEK", 'F'}, + {"0VOSEN", 'F'}, + {"0VOSEO", 'F'}, + {"0VOSES", 'F'}, + {"0VOSEU", 'F'}, + {"0VOSEV", 'F'}, + {"0VOSF(", 'F'}, + {"0VOSK(", 'F'}, + {"0VOSK)", 'F'}, + {"0VOSK1", 'F'}, + {"0VOSKB", 'F'}, + {"0VOSKF", 'F'}, + {"0VOSKN", 'F'}, + {"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'}, + {"0VOSU;", 'F'}, + {"0VOSUC", 'F'}, + {"0VOSUE", 'F'}, + {"0VOSUF", 'F'}, + {"0VOSUK", 'F'}, + {"0VOSUO", 'F'}, + {"0VOSUS", 'F'}, + {"0VOSUT", 'F'}, + {"0VOSUV", 'F'}, + {"0VOSV(", 'F'}, + {"0VOSVF", 'F'}, + {"0VOSVO", 'F'}, + {"0VOSVS", 'F'}, + {"0VOSVU", 'F'}, + {"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'}, + {"0VU(E(", 'F'}, + {"0VU(E1", 'F'}, + {"0VU(EF", 'F'}, + {"0VU(EK", 'F'}, + {"0VU(EN", 'F'}, + {"0VU(ES", 'F'}, + {"0VU(EV", 'F'}, + {"0VU(F(", 'F'}, + {"0VU(N)", 'F'}, + {"0VU(NO", 'F'}, + {"0VU(S)", 'F'}, + {"0VU(SO", 'F'}, + {"0VU(V)", 'F'}, + {"0VU(VO", 'F'}, + {"0VU1,(", 'F'}, + {"0VU1,F", 'F'}, + {"0VU1C", 'F'}, + {"0VU1O(", 'F'}, + {"0VU1OF", 'F'}, + {"0VU1OS", 'F'}, + {"0VU1OV", 'F'}, + {"0VU;", 'F'}, + {"0VU;C", 'F'}, + {"0VUC", 'F'}, + {"0VUE", 'F'}, + {"0VUE(1", 'F'}, + {"0VUE(E", 'F'}, + {"0VUE(F", 'F'}, + {"0VUE(N", 'F'}, + {"0VUE(O", 'F'}, + {"0VUE(S", 'F'}, + {"0VUE(V", 'F'}, + {"0VUE1", 'F'}, + {"0VUE1&", 'F'}, + {"0VUE1(", 'F'}, + {"0VUE1)", 'F'}, + {"0VUE1,", 'F'}, + {"0VUE1;", 'F'}, + {"0VUE1B", 'F'}, + {"0VUE1C", 'F'}, + {"0VUE1F", 'F'}, + {"0VUE1K", 'F'}, + {"0VUE1N", 'F'}, + {"0VUE1O", 'F'}, + {"0VUE1S", 'F'}, + {"0VUE1U", 'F'}, + {"0VUE1V", 'F'}, + {"0VUE;", 'F'}, + {"0VUE;C", 'F'}, + {"0VUEC", 'F'}, + {"0VUEF", 'F'}, + {"0VUEF(", 'F'}, + {"0VUEF,", 'F'}, + {"0VUEF;", 'F'}, + {"0VUEFC", 'F'}, + {"0VUEK", 'F'}, + {"0VUEK(", 'F'}, + {"0VUEK1", 'F'}, + {"0VUEK;", 'F'}, + {"0VUEKC", 'F'}, + {"0VUEKF", 'F'}, + {"0VUEKN", 'F'}, + {"0VUEKO", 'F'}, + {"0VUEKS", 'F'}, + {"0VUEKV", 'F'}, + {"0VUEN", 'F'}, + {"0VUEN&", 'F'}, + {"0VUEN(", 'F'}, + {"0VUEN)", 'F'}, + {"0VUEN,", 'F'}, + {"0VUEN1", 'F'}, + {"0VUEN;", 'F'}, + {"0VUENB", 'F'}, + {"0VUENC", 'F'}, + {"0VUENF", 'F'}, + {"0VUENK", 'F'}, + {"0VUENO", 'F'}, + {"0VUENS", 'F'}, + {"0VUENU", 'F'}, + {"0VUEOK", 'F'}, + {"0VUEON", 'F'}, + {"0VUES", 'F'}, + {"0VUES&", 'F'}, + {"0VUES(", 'F'}, + {"0VUES)", 'F'}, + {"0VUES,", 'F'}, + {"0VUES1", 'F'}, + {"0VUES;", 'F'}, + {"0VUESB", 'F'}, + {"0VUESC", 'F'}, + {"0VUESF", 'F'}, + {"0VUESK", 'F'}, + {"0VUESO", 'F'}, + {"0VUESU", 'F'}, + {"0VUESV", 'F'}, + {"0VUEV", 'F'}, + {"0VUEV&", 'F'}, + {"0VUEV(", 'F'}, + {"0VUEV)", 'F'}, + {"0VUEV,", 'F'}, + {"0VUEV;", 'F'}, + {"0VUEVB", 'F'}, + {"0VUEVC", 'F'}, + {"0VUEVF", 'F'}, + {"0VUEVK", 'F'}, + {"0VUEVN", 'F'}, + {"0VUEVO", 'F'}, + {"0VUEVS", 'F'}, + {"0VUEVU", 'F'}, + {"0VUF()", 'F'}, + {"0VUF(1", 'F'}, + {"0VUF(F", 'F'}, + {"0VUF(N", 'F'}, + {"0VUF(S", 'F'}, + {"0VUF(V", 'F'}, + {"0VUK(E", 'F'}, + {"0VUO(E", 'F'}, + {"0VUON(", 'F'}, + {"0VUON1", 'F'}, + {"0VUONF", 'F'}, + {"0VUONS", 'F'}, + {"0VUS,(", 'F'}, + {"0VUS,F", 'F'}, + {"0VUSC", 'F'}, + {"0VUSO(", 'F'}, + {"0VUSO1", 'F'}, + {"0VUSOF", 'F'}, + {"0VUSON", 'F'}, + {"0VUSOS", 'F'}, + {"0VUSOV", 'F'}, + {"0VUTN(", 'F'}, + {"0VUTN1", 'F'}, + {"0VUTNF", 'F'}, + {"0VUTNN", 'F'}, + {"0VUTNS", 'F'}, + {"0VUTNV", 'F'}, + {"0VUV,(", 'F'}, + {"0VUV,F", 'F'}, + {"0VUVC", 'F'}, + {"0VUVO(", 'F'}, + {"0VUVOF", 'F'}, + {"0VUVOS", 'F'}, + {"0X", 'F'}, + {"::", 'o'}, + {":=", 'o'}, + {"<<", 'o'}, + {"<=", 'o'}, + {"<>", 'o'}, + {"<@", 'o'}, + {">=", 'o'}, + {">>", 'o'}, + {"@>", 'o'}, + {"ABORT", 'k'}, + {"ABS", 'f'}, + {"ACCESSIBLE", 'k'}, + {"ACOS", 'f'}, + {"ADDDATE", 'f'}, + {"ADDTIME", 'f'}, + {"AES_DECRYPT", 'f'}, + {"AES_ENCRYPT", 'f'}, + {"AGAINST", 'k'}, + {"AGE", 'f'}, + {"ALL_USERS", 'k'}, + {"ALTER", 'k'}, + {"ALTER DOMAIN", 'k'}, + {"ALTER TABLE", 'k'}, + {"ANALYZE", 'k'}, + {"AND", '&'}, + {"ANY", 'f'}, + {"ANYARRAY", 't'}, + {"ANYELEMENT", 't'}, + {"ANYNONARRY", 't'}, + {"APPLOCK_MODE", 'f'}, + {"APPLOCK_TEST", 'f'}, + {"APP_NAME", 'f'}, + {"ARRAY_AGG", 'f'}, + {"ARRAY_CAT", 'f'}, + {"ARRAY_DIM", 'f'}, + {"ARRAY_FILL", 'f'}, + {"ARRAY_LENGTH", 'f'}, + {"ARRAY_LOWER", 'f'}, + {"ARRAY_NDIMS", 'f'}, + {"ARRAY_PREPEND", 'f'}, + {"ARRAY_TO_JSON", 'f'}, + {"ARRAY_TO_STRING", 'f'}, + {"ARRAY_UPPER", 'f'}, + {"AS", 'k'}, + {"ASC", 'k'}, + {"ASCII", 'f'}, + {"ASENSITIVE", 'k'}, + {"ASIN", 'f'}, + {"ASSEMBLYPROPERTY", 'f'}, + {"ASYMKEY_ID", 'f'}, + {"AT TIME", 'n'}, + {"AT TIME ZONE", 'k'}, + {"ATAN", 'f'}, + {"ATAN2", 'f'}, + {"AUTOINCREMENT", 'k'}, + {"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'}, + {"BIGSERIAL", 't'}, + {"BIN", 'f'}, + {"BINARY", 't'}, + {"BINARY_DOUBLE_INFINITY", '1'}, + {"BINARY_DOUBLE_NAN", '1'}, + {"BINARY_FLOAT_INFINITY", '1'}, + {"BINARY_FLOAT_NAN", '1'}, + {"BINBINARY", 'f'}, + {"BIT_AND", 'f'}, + {"BIT_COUNT", 'f'}, + {"BIT_LENGTH", 'f'}, + {"BIT_OR", 'f'}, + {"BIT_XOR", 'f'}, + {"BLOB", 'k'}, + {"BOOLEAN", 't'}, + {"BOOL_AND", 'f'}, + {"BOOL_OR", 'f'}, + {"BOTH", 'k'}, + {"BTRIM", 'f'}, + {"BY", 'n'}, + {"BYTEA", 't'}, + {"CALL", 'T'}, + {"CASCADE", 'k'}, + {"CASE", 'E'}, + {"CAST", 'f'}, + {"CBOOL", 'f'}, + {"CBRT", 'f'}, + {"CBYTE", 'f'}, + {"CCUR", 'f'}, + {"CDATE", 'f'}, + {"CDBL", 'f'}, + {"CEIL", 'f'}, + {"CEILING", 'f'}, + {"CERTENCODED", 'f'}, + {"CERTPRIVATEKEY", 'f'}, + {"CERT_ID", 'f'}, + {"CERT_PROPERTY", 'f'}, + {"CHANGE", 'k'}, + {"CHANGES", 'f'}, + {"CHAR", 'f'}, + {"CHARACTER", 't'}, + {"CHARACTER VARYING", 't'}, + {"CHARACTER_LENGTH", 'f'}, + {"CHARINDEX", 'f'}, + {"CHARSET", 'f'}, + {"CHAR_LENGTH", 'f'}, + {"CHDIR", 'f'}, + {"CHDRIVE", 'f'}, + {"CHECK", 'n'}, + {"CHECKSUM_AGG", 'f'}, + {"CHOOSE", 'f'}, + {"CHR", 'f'}, + {"CINT", 'f'}, + {"CLNG", 'f'}, + {"CLOCK_TIMESTAMP", 'f'}, + {"COALESCE", 'f'}, + {"COERCIBILITY", 'f'}, + {"COLLATE", 'A'}, + {"COLLATION", 'f'}, + {"COLLATIONPROPERTY", 'f'}, + {"COLUMN", 'k'}, + {"COLUMNPROPERTY", 'f'}, + {"COLUMNS_UPDATED", 'f'}, + {"COL_LENGTH", 'f'}, + {"COL_NAME", 'f'}, + {"COMPRESS", 'f'}, + {"CONCAT", 'f'}, + {"CONCAT_WS", 'f'}, + {"CONDITION", 'k'}, + {"CONNECTION_ID", 'f'}, + {"CONSTRAINT", 'k'}, + {"CONTINUE", 'k'}, + {"CONV", 'f'}, + {"CONVERT", 'f'}, + {"CONVERT_FROM", 'f'}, + {"CONVERT_TO", 'f'}, + {"CONVERT_TZ", 'f'}, + {"COS", 'f'}, + {"COT", 'f'}, + {"COUNT", 'f'}, + {"COUNT_BIG", 'k'}, + {"CRC32", 'f'}, + {"CREATE", 'E'}, + {"CREATE OR", 'n'}, + {"CREATE OR REPLACE", 'T'}, + {"CROSS", 'n'}, + {"CROSS JOIN", 'k'}, + {"CSNG", 'f'}, + {"CSTRING", 't'}, + {"CTXSYS.DRITHSX.SN", 'f'}, + {"CUME_DIST", 'f'}, + {"CURDATE", 'f'}, + {"CURDIR", 'f'}, + {"CURRENT DATE", 'v'}, + {"CURRENT DEGREE", 'v'}, + {"CURRENT FUNCTION", 'v'}, + {"CURRENT FUNCTION PATH", 'v'}, + {"CURRENT PATH", 'v'}, + {"CURRENT SCHEMA", 'v'}, + {"CURRENT SERVER", 'v'}, + {"CURRENT TIME", 'v'}, + {"CURRENT TIMEZONE", 'v'}, + {"CURRENTUSER", 'f'}, + {"CURRENT_DATABASE", 'f'}, + {"CURRENT_DATE", 'v'}, + {"CURRENT_PATH", 'v'}, + {"CURRENT_QUERY", 'f'}, + {"CURRENT_SCHEMA", 'f'}, + {"CURRENT_SCHEMAS", 'f'}, + {"CURRENT_SERVER", 'v'}, + {"CURRENT_SETTING", 'f'}, + {"CURRENT_TIME", 'v'}, + {"CURRENT_TIMESTAMP", 'v'}, + {"CURRENT_TIMEZONE", 'v'}, + {"CURRENT_USER", 'v'}, + {"CURRVAL", 'f'}, + {"CURSOR", 'k'}, + {"CURSOR_STATUS", 'f'}, + {"CURTIME", 'f'}, + {"CVAR", 'f'}, + {"DATABASE", 'n'}, + {"DATABASEPROPERTYEX", 'f'}, + {"DATABASES", 'k'}, + {"DATABASE_PRINCIPAL_ID", 'f'}, + {"DATALENGTH", 'f'}, + {"DATE", 'f'}, + {"DATEADD", 'f'}, + {"DATEDIFF", 'f'}, + {"DATEFROMPARTS", 'f'}, + {"DATENAME", 'f'}, + {"DATEPART", 'f'}, + {"DATESERIAL", 'f'}, + {"DATETIME2FROMPARTS", 'f'}, + {"DATETIMEFROMPARTS", 'f'}, + {"DATETIMEOFFSETFROMPARTS", 'f'}, + {"DATEVALUE", 'f'}, + {"DATE_ADD", 'f'}, + {"DATE_FORMAT", 'f'}, + {"DATE_PART", 'f'}, + {"DATE_SUB", 'f'}, + {"DATE_TRUNC", 'f'}, + {"DAVG", 'f'}, + {"DAY", 'f'}, + {"DAYNAME", 'f'}, + {"DAYOFMONTH", 'f'}, + {"DAYOFWEEK", 'f'}, + {"DAYOFYEAR", 'f'}, + {"DAY_HOUR", 'k'}, + {"DAY_MICROSECOND", 'k'}, + {"DAY_MINUTE", 'k'}, + {"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'}, + {"DEC", 'k'}, + {"DECIMAL", 't'}, + {"DECLARE", 'T'}, + {"DECODE", 'f'}, + {"DECRYPTBYASMKEY", 'f'}, + {"DECRYPTBYCERT", 'f'}, + {"DECRYPTBYKEY", 'f'}, + {"DECRYPTBYKEYAUTOCERT", 'f'}, + {"DECRYPTBYPASSPHRASE", 'f'}, + {"DEFAULT", 'k'}, + {"DEGREES", 'f'}, + {"DELAY", 'k'}, + {"DELAYED", 'k'}, + {"DELETE", 'T'}, + {"DENSE_RANK", 'f'}, + {"DESC", 'k'}, + {"DESCRIBE", 'k'}, + {"DES_DECRYPT", 'f'}, + {"DES_ENCRYPT", 'f'}, + {"DETERMINISTIC", 'k'}, + {"DFIRST", 'f'}, + {"DIFFERENCE", 'f'}, + {"DISTINCT", 'k'}, + {"DISTINCTROW", 'k'}, + {"DIV", 'o'}, + {"DLAST", 'f'}, + {"DLOOKUP", 'f'}, + {"DMAX", 'f'}, + {"DMIN", 'f'}, + {"DO", 'n'}, + {"DOUBLE", 't'}, + {"DOUBLE PRECISION", 't'}, + {"DROP", 'T'}, + {"DSUM", 'f'}, + {"DUAL", 'n'}, + {"EACH", 'k'}, + {"ELSE", 'k'}, + {"ELSEIF", 'k'}, + {"ELT", 'f'}, + {"ENCLOSED", 'k'}, + {"ENCODE", 'f'}, + {"ENCRYPT", 'f'}, + {"ENCRYPTBYASMKEY", 'f'}, + {"ENCRYPTBYCERT", 'f'}, + {"ENCRYPTBYKEY", 'f'}, + {"ENCRYPTBYPASSPHRASE", 'f'}, + {"ENUM_FIRST", 'f'}, + {"ENUM_LAST", 'f'}, + {"ENUM_RANGE", 'f'}, + {"EOMONTH", 'f'}, + {"EQV", 'o'}, + {"ESCAPED", 'k'}, + {"EVENTDATA", 'f'}, + {"EXCEPT", 'U'}, + {"EXEC", 'T'}, + {"EXECUTE", 'T'}, + {"EXECUTE AS", 'E'}, + {"EXECUTE AS LOGIN", 'E'}, + {"EXISTS", 'f'}, + {"EXIT", 'k'}, + {"EXP", 'f'}, + {"EXPLAIN", 'k'}, + {"EXPORT_SET", 'f'}, + {"EXTRACT", 'f'}, + {"EXTRACTVALUE", 'f'}, + {"EXTRACT_VALUE", 'f'}, + {"FALSE", '1'}, + {"FETCH", 'k'}, + {"FIELD", 'f'}, + {"FILEDATETIME", 'f'}, + {"FILEGROUPPROPERTY", 'f'}, + {"FILEGROUP_ID", 'f'}, + {"FILEGROUP_NAME", 'f'}, + {"FILELEN", 'f'}, + {"FILEPROPERTY", 'f'}, + {"FILETOBLOB", 'f'}, + {"FILETOCLOB", 'f'}, + {"FILE_ID", 'f'}, + {"FILE_IDEX", 'f'}, + {"FILE_NAME", 'f'}, + {"FIND_IN_SET", 'f'}, + {"FIRST_VALUE", 'f'}, + {"FLOAT", 't'}, + {"FLOAT4", 't'}, + {"FLOAT8", 't'}, + {"FLOOR", 'f'}, + {"FN_VIRTUALFILESTATS", 'f'}, + {"FOR", 'n'}, + {"FOR UPDATE", 'k'}, + {"FOR UPDATE NOWAIT", 'k'}, + {"FOR UPDATE OF", 'k'}, + {"FOR UPDATE SKIP", 'k'}, + {"FOR UPDATE SKIP LOCKED", 'k'}, + {"FOR UPDATE WAIT", 'k'}, + {"FORCE", 'k'}, + {"FOREIGN", 'k'}, + {"FORMAT", 'f'}, + {"FOUND_ROWS", 'f'}, + {"FROM", 'k'}, + {"FROM_BASE64", 'f'}, + {"FROM_DAYS", 'f'}, + {"FROM_UNIXTIME", 'f'}, + {"FULL JOIN", 'k'}, + {"FULL OUTER", 'k'}, + {"FULL OUTER JOIN", 'k'}, + {"FULLTEXT", 'k'}, + {"FULLTEXTCATALOGPROPERTY", 'f'}, + {"FULLTEXTSERVICEPROPERTY", 'f'}, + {"FUNCTION", 'k'}, + {"GENERATE_SERIES", 'f'}, + {"GENERATE_SUBSCRIPTS", 'f'}, + {"GETATTR", 'f'}, + {"GETDATE", 'f'}, + {"GETUTCDATE", 'f'}, + {"GET_BIT", 'f'}, + {"GET_BYTE", 'f'}, + {"GET_FORMAT", 'f'}, + {"GET_LOCK", 'f'}, + {"GO", 'T'}, + {"GOTO", 'T'}, + {"GRANT", 'k'}, + {"GREATEST", 'f'}, + {"GROUP", 'n'}, + {"GROUP BY", 'B'}, + {"GROUPING", 'f'}, + {"GROUPING_ID", 'f'}, + {"GROUP_CONCAT", 'f'}, + {"HANDLER", 'T'}, + {"HASHBYTES", 'f'}, + {"HAS_PERMS_BY_NAME", 'f'}, + {"HAVING", 'B'}, + {"HEX", 'f'}, + {"HIGH_PRIORITY", 'k'}, + {"HOST_NAME", 'f'}, + {"HOUR", 'f'}, + {"HOUR_MICROSECOND", 'k'}, + {"HOUR_MINUTE", 'k'}, + {"HOUR_SECOND", 'k'}, + {"IDENTIFY", 'f'}, + {"IDENT_CURRENT", 'f'}, + {"IDENT_INCR", 'f'}, + {"IDENT_SEED", 'f'}, + {"IF", 'f'}, + {"IF EXISTS", 'f'}, + {"IF NOT", 'f'}, + {"IF NOT EXISTS", 'f'}, + {"IFF", 'f'}, + {"IFNULL", 'f'}, + {"IGNORE", 'k'}, + {"IIF", 'f'}, + {"IN", 'k'}, + {"IN BOOLEAN", 'n'}, + {"IN BOOLEAN MODE", 'k'}, + {"INDEX", 'k'}, + {"INDEXKEY_PROPERTY", 'f'}, + {"INDEXPROPERTY", 'f'}, + {"INDEX_COL", 'f'}, + {"INET_ATON", 'f'}, + {"INET_NTOA", 'f'}, + {"INFILE", 'k'}, + {"INITCAP", 'f'}, + {"INNER", 'k'}, + {"INNER JOIN", 'k'}, + {"INOUT", 'k'}, + {"INSENSITIVE", 'k'}, + {"INSERT", 'E'}, + {"INSERT DELAYED", 'E'}, + {"INSERT DELAYED INTO", 'T'}, + {"INSERT HIGH_PRIORITY", 'E'}, + {"INSERT HIGH_PRIORITY INTO", 'T'}, + {"INSERT IGNORE", 'E'}, + {"INSERT IGNORE INTO", 'T'}, + {"INSERT INTO", 'T'}, + {"INSERT LOW_PRIORITY", 'E'}, + {"INSERT LOW_PRIORITY INTO", 'T'}, + {"INSTR", 'f'}, + {"INSTRREV", 'f'}, + {"INT", 't'}, + {"INT1", 't'}, + {"INT2", 't'}, + {"INT3", 't'}, + {"INT4", 't'}, + {"INT8", 't'}, + {"INTEGER", 't'}, + {"INTERSECT", 'U'}, + {"INTERSECT ALL", 'U'}, + {"INTERVAL", 'k'}, + {"INTO", 'k'}, + {"INTO DUMPFILE", 'k'}, + {"INTO OUTFILE", 'k'}, + {"IS", 'o'}, + {"IS DISTINCT", 'n'}, + {"IS DISTINCT FROM", 'o'}, + {"IS NOT", 'o'}, + {"IS NOT DISTINCT", 'n'}, + {"IS NOT DISTINCT FROM", 'o'}, + {"ISDATE", 'f'}, + {"ISEMPTY", 'f'}, + {"ISFINITE", 'f'}, + {"ISNULL", 'f'}, + {"ISNUMERIC", 'f'}, + {"IS_FREE_LOCK", 'f'}, + {"IS_MEMBER", 'f'}, + {"IS_OBJECTSIGNED", 'f'}, + {"IS_ROLEMEMBER", 'f'}, + {"IS_SRVROLEMEMBER", 'f'}, + {"IS_USED_LOCK", 'f'}, + {"ITERATE", 'k'}, + {"JOIN", 'k'}, + {"JSON_KEYS", 'f'}, + {"JULIANDAY", 'f'}, + {"JUSTIFY_DAYS", 'f'}, + {"JUSTIFY_HOURS", 'f'}, + {"JUSTIFY_INTERVAL", 'f'}, + {"KEYS", 'k'}, + {"KEY_GUID", 'f'}, + {"KEY_ID", 'f'}, + {"KILL", 'k'}, + {"LAG", 'f'}, + {"LASTVAL", 'f'}, + {"LAST_INSERT_ID", 'f'}, + {"LAST_INSERT_ROWID", 'f'}, + {"LAST_VALUE", 'f'}, + {"LCASE", 'f'}, + {"LEAD", 'f'}, + {"LEADING", 'k'}, + {"LEAST", 'f'}, + {"LEAVE", 'k'}, + {"LEFT", 'f'}, + {"LEFT JOIN", 'k'}, + {"LEFT OUTER", 'k'}, + {"LEFT OUTER JOIN", 'k'}, + {"LENGTH", 'f'}, + {"LIKE", 'o'}, + {"LIMIT", 'B'}, + {"LINEAR", 'k'}, + {"LINES", 'k'}, + {"LN", 'f'}, + {"LOAD", 'k'}, + {"LOAD DATA", 'T'}, + {"LOAD XML", 'T'}, + {"LOAD_EXTENSION", 'f'}, + {"LOAD_FILE", 'f'}, + {"LOCALTIME", 'v'}, + {"LOCALTIMESTAMP", 'v'}, + {"LOCATE", 'f'}, + {"LOCK", 'n'}, + {"LOCK IN", 'n'}, + {"LOCK IN SHARE", 'n'}, + {"LOCK IN SHARE MODE", 'k'}, + {"LOCK TABLE", 'k'}, + {"LOCK TABLES", 'k'}, + {"LOG", 'f'}, + {"LOG10", 'f'}, + {"LOG2", 'f'}, + {"LONGBLOB", 'k'}, + {"LONGTEXT", 'k'}, + {"LOOP", 'k'}, + {"LOWER", 'f'}, + {"LOWER_INC", 'f'}, + {"LOWER_INF", 'f'}, + {"LOW_PRIORITY", 'k'}, + {"LPAD", 'f'}, + {"LTRIM", 'f'}, + {"MAKEDATE", 'f'}, + {"MAKE_SET", 'f'}, + {"MASKLEN", 'f'}, + {"MASTER_BIND", 'k'}, + {"MASTER_POS_WAIT", 'f'}, + {"MASTER_SSL_VERIFY_SERVER_CERT", 'k'}, + {"MATCH", 'k'}, + {"MAX", 'f'}, + {"MAXVALUE", 'k'}, + {"MD5", 'f'}, + {"MEDIUMBLOB", 'k'}, + {"MEDIUMINT", 'k'}, + {"MEDIUMTEXT", 'k'}, + {"MERGE", 'k'}, + {"MICROSECOND", 'f'}, + {"MID", 'f'}, + {"MIDDLEINT", 'k'}, + {"MIN", 'f'}, + {"MINUTE", 'f'}, + {"MINUTE_MICROSECOND", 'k'}, + {"MINUTE_SECOND", 'k'}, + {"MKDIR", 'f'}, + {"MOD", 'o'}, + {"MODE", 'n'}, + {"MODIFIES", 'k'}, + {"MONEY", 't'}, + {"MONTH", 'f'}, + {"MONTHNAME", 'f'}, + {"NAME_CONST", 'f'}, + {"NATURAL", 'n'}, + {"NATURAL FULL", 'k'}, + {"NATURAL FULL OUTER JOIN", 'k'}, + {"NATURAL INNER", 'k'}, + {"NATURAL JOIN", 'k'}, + {"NATURAL LEFT", 'k'}, + {"NATURAL LEFT OUTER", 'k'}, + {"NATURAL LEFT OUTER JOIN", 'k'}, + {"NATURAL OUTER", 'k'}, + {"NATURAL RIGHT", 'k'}, + {"NATURAL RIGHT OUTER JOIN", 'k'}, + {"NETMASK", 'f'}, + {"NEXT VALUE", 'n'}, + {"NEXT VALUE FOR", 'k'}, + {"NEXTVAL", 'f'}, + {"NOT", 'o'}, + {"NOT BETWEEN", 'o'}, + {"NOT IN", 'k'}, + {"NOT LIKE", 'o'}, + {"NOT REGEXP", 'o'}, + {"NOT RLIKE", 'o'}, + {"NOT SIMILAR", 'o'}, + {"NOT SIMILAR TO", 'o'}, + {"NOTNULL", 'k'}, + {"NOW", 'f'}, + {"NOWAIT", 'k'}, + {"NO_WRITE_TO_BINLOG", 'k'}, + {"NTH_VALUE", 'f'}, + {"NTILE", 'f'}, + {"NULL", 'v'}, + {"NULLIF", 'f'}, + {"NUMERIC", 't'}, + {"NZ", 'f'}, + {"OBJECTPROPERTY", 'f'}, + {"OBJECTPROPERTYEX", 'f'}, + {"OBJECT_DEFINITION", 'f'}, + {"OBJECT_ID", 'f'}, + {"OBJECT_NAME", 'f'}, + {"OBJECT_SCHEMA_NAME", 'f'}, + {"OCT", 'f'}, + {"OCTET_LENGTH", 'f'}, + {"OFFSET", 'k'}, + {"OID", 't'}, + {"OLD_PASSWORD", 'f'}, + {"ONE_SHOT", 'k'}, + {"OPEN", 'k'}, + {"OPENDATASOURCE", 'f'}, + {"OPENQUERY", 'f'}, + {"OPENROWSET", 'f'}, + {"OPENXML", 'f'}, + {"OPTIMIZE", 'k'}, + {"OPTION", 'k'}, + {"OPTIONALLY", 'k'}, + {"OR", '&'}, + {"ORD", 'f'}, + {"ORDER", 'n'}, + {"ORDER BY", 'B'}, + {"ORIGINAL_DB_NAME", 'f'}, + {"ORIGINAL_LOGIN", 'f'}, + {"OUT", 'n'}, + {"OUTER", 'n'}, + {"OUTFILE", 'k'}, + {"OVERLAPS", 'f'}, + {"OVERLAY", 'f'}, + {"OWN3D", 'k'}, + {"OWN3D BY", 'B'}, + {"PARSENAME", 'f'}, + {"PARTITION", 'k'}, + {"PARTITION BY", 'B'}, + {"PASSWORD", 'n'}, + {"PATHINDEX", 'f'}, + {"PATINDEX", 'f'}, + {"PERCENTILE_COUNT", 'f'}, + {"PERCENTILE_DISC", 'f'}, + {"PERCENTILE_RANK", 'f'}, + {"PERCENT_RANK", 'f'}, + {"PERIOD_ADD", 'f'}, + {"PERIOD_DIFF", 'f'}, + {"PERMISSIONS", 'f'}, + {"PG_ADVISORY_LOCK", 'f'}, + {"PG_BACKEND_PID", 'f'}, + {"PG_CANCEL_BACKEND", 'f'}, + {"PG_CLIENT_ENCODING", 'f'}, + {"PG_CONF_LOAD_TIME", 'f'}, + {"PG_CREATE_RESTORE_POINT", 'f'}, + {"PG_HAS_ROLE", 'f'}, + {"PG_IS_IN_RECOVERY", 'f'}, + {"PG_IS_OTHER_TEMP_SCHEMA", 'f'}, + {"PG_LISTENING_CHANNELS", 'f'}, + {"PG_LS_DIR", 'f'}, + {"PG_MY_TEMP_SCHEMA", 'f'}, + {"PG_POSTMASTER_START_TIME", 'f'}, + {"PG_READ_BINARY_FILE", 'f'}, + {"PG_READ_FILE", 'f'}, + {"PG_RELOAD_CONF", 'f'}, + {"PG_ROTATE_LOGFILE", 'f'}, + {"PG_SLEEP", 'f'}, + {"PG_START_BACKUP", 'f'}, + {"PG_STAT_FILE", 'f'}, + {"PG_STOP_BACKUP", 'f'}, + {"PG_SWITCH_XLOG", 'f'}, + {"PG_TERMINATE_BACKEND", 'f'}, + {"PG_TRIGGER_DEPTH", 'f'}, + {"PI", 'f'}, + {"POSITION", 'f'}, + {"POW", 'f'}, + {"POWER", 'f'}, + {"PRECISION", 'k'}, + {"PREVIOUS VALUE", 'n'}, + {"PREVIOUS VALUE FOR", 'k'}, + {"PRIMARY", 'k'}, + {"PRINT", 'T'}, + {"PROCEDURE", 'k'}, + {"PROCEDURE ANALYSE", 'f'}, + {"PUBLISHINGSERVERNAME", 'f'}, + {"PURGE", 'k'}, + {"PWDCOMPARE", 'f'}, + {"PWDENCRYPT", 'f'}, + {"QUARTER", 'f'}, + {"QUOTE", 'f'}, + {"QUOTENAME", 'f'}, + {"QUOTE_IDENT", 'f'}, + {"QUOTE_LITERAL", 'f'}, + {"QUOTE_NULLABLE", 'f'}, + {"RADIANS", 'f'}, + {"RAISEERROR", 'E'}, + {"RAND", 'f'}, + {"RANDOM", 'f'}, + {"RANDOMBLOB", 'f'}, + {"RANGE", 'k'}, + {"RANK", 'f'}, + {"READ", 'k'}, + {"READ WRITE", 'k'}, + {"READS", 'k'}, + {"READ_WRITE", 'k'}, + {"REAL", 't'}, + {"REFERENCES", 'k'}, + {"REGCLASS", 't'}, + {"REGCONFIG", 't'}, + {"REGDICTIONARY", 't'}, + {"REGEXP", 'o'}, + {"REGEXP_INSTR", 'f'}, + {"REGEXP_MATCHES", 'f'}, + {"REGEXP_REPLACE", 'f'}, + {"REGEXP_SPLIT_TO_ARRAY", 'f'}, + {"REGEXP_SPLIT_TO_TABLE", 'f'}, + {"REGEXP_SUBSTR", 'f'}, + {"REGOPER", 't'}, + {"REGOPERATOR", 't'}, + {"REGPROC", 't'}, + {"REGPROCEDURE", 't'}, + {"REGTYPE", 't'}, + {"RELEASE", 'k'}, + {"RELEASE_LOCK", 'f'}, + {"RENAME", 'k'}, + {"REPEAT", 'k'}, + {"REPLACE", 'k'}, + {"REPLICATE", 'f'}, + {"REQUIRE", 'k'}, + {"RESIGNAL", 'k'}, + {"RESTRICT", 'k'}, + {"RETURN", 'k'}, + {"REVERSE", 'f'}, + {"REVOKE", 'k'}, + {"RIGHT", 'n'}, + {"RIGHT JOIN", 'k'}, + {"RIGHT OUTER", 'k'}, + {"RIGHT OUTER JOIN", 'k'}, + {"RLIKE", 'o'}, + {"ROUND", 'f'}, + {"ROW", 'f'}, + {"ROW_COUNT", 'f'}, + {"ROW_NUMBER", 'f'}, + {"ROW_TO_JSON", 'f'}, + {"RPAD", 'f'}, + {"RTRIM", 'f'}, + {"SCHAMA_NAME", 'f'}, + {"SCHEMA", 'k'}, + {"SCHEMAS", 'k'}, + {"SCHEMA_ID", 'f'}, + {"SCOPE_IDENTITY", 'f'}, + {"SECOND_MICROSECOND", 'k'}, + {"SEC_TO_TIME", 'f'}, + {"SELECT", 'E'}, + {"SELECT ALL", 'E'}, + {"SELECT DISTINCT", 'E'}, + {"SENSITIVE", 'k'}, + {"SEPARATOR", 'k'}, + {"SERIAL", 't'}, + {"SERIAL2", 't'}, + {"SERIAL4", 't'}, + {"SERIAL8", 't'}, + {"SERVERPROPERTY", 'f'}, + {"SESSION_USER", 'f'}, + {"SET", 'E'}, + {"SETATTR", 'f'}, + {"SETSEED", 'f'}, + {"SETVAL", 'f'}, + {"SET_BIT", 'f'}, + {"SET_BYTE", 'f'}, + {"SET_CONFIG", 'f'}, + {"SET_MASKLEN", 'f'}, + {"SHA", 'f'}, + {"SHA1", 'f'}, + {"SHA2", 'f'}, + {"SHOW", 'n'}, + {"SHUTDOWN", 'T'}, + {"SIGN", 'f'}, + {"SIGNAL", 'k'}, + {"SIGNBYASMKEY", 'f'}, + {"SIGNBYCERT", 'f'}, + {"SIMILAR", 'k'}, + {"SIMILAR TO", 'o'}, + {"SIN", 'f'}, + {"SLEEP", 'f'}, + {"SMALLDATETIMEFROMPARTS", 'f'}, + {"SMALLINT", 't'}, + {"SMALLSERIAL", 't'}, + {"SOME", 'f'}, + {"SOUNDEX", 'f'}, + {"SOUNDS", 'o'}, + {"SOUNDS LIKE", 'o'}, + {"SPACE", 'f'}, + {"SPATIAL", 'k'}, + {"SPECIFIC", 'k'}, + {"SPLIT_PART", 'f'}, + {"SQL", 'k'}, + {"SQLEXCEPTION", 'k'}, + {"SQLITE_VERSION", 'f'}, + {"SQLSTATE", 'k'}, + {"SQLWARNING", 'k'}, + {"SQL_BIG_RESULT", 'k'}, + {"SQL_BUFFER_RESULT", 'k'}, + {"SQL_CACHE", 'k'}, + {"SQL_CALC_FOUND_ROWS", 'k'}, + {"SQL_NO_CACHE", 'k'}, + {"SQL_SMALL_RESULT", 'k'}, + {"SQL_VARIANT_PROPERTY", 'f'}, + {"SQRT", 'f'}, + {"SSL", 'k'}, + {"STARTING", 'k'}, + {"STATEMENT_TIMESTAMP", 'f'}, + {"STATS_DATE", 'f'}, + {"STDDEV", 'f'}, + {"STDDEV_POP", 'f'}, + {"STDDEV_SAMP", 'f'}, + {"STRAIGHT_JOIN", 'k'}, + {"STRCMP", 'f'}, + {"STRCOMP", 'f'}, + {"STRCONV", 'f'}, + {"STRING_AGG", 'f'}, + {"STRING_TO_ARRAY", 'f'}, + {"STRPOS", 'f'}, + {"STR_TO_DATE", 'f'}, + {"STUFF", 'f'}, + {"SUBDATE", 'f'}, + {"SUBSTR", 'f'}, + {"SUBSTRING", 'f'}, + {"SUBSTRING_INDEX", 'f'}, + {"SUBTIME", 'f'}, + {"SUM", 'f'}, + {"SUSER_ID", 'f'}, + {"SUSER_NAME", 'f'}, + {"SUSER_SID", 'f'}, + {"SUSER_SNAME", 'f'}, + {"SWITCHOFFET", 'f'}, + {"SYS.DATABASE_NAME", 'n'}, + {"SYS.FN_BUILTIN_PERMISSIONS", 'f'}, + {"SYS.FN_GET_AUDIT_FILE", 'f'}, + {"SYS.FN_MY_PERMISSIONS", 'f'}, + {"SYS.STRAGG", 'f'}, + {"SYSCOLUMNS", 'k'}, + {"SYSDATE", 'f'}, + {"SYSDATETIME", 'f'}, + {"SYSDATETIMEOFFSET", 'f'}, + {"SYSOBJECTS", 'k'}, + {"SYSTEM_USER", 'f'}, + {"SYSUSERS", 'k'}, + {"SYSUTCDATETME", 'f'}, + {"TABLE", 'n'}, + {"TAN", 'f'}, + {"TERMINATED", 'k'}, + {"TERTIARY_WEIGHTS", 'f'}, + {"TEXT", 't'}, + {"TEXTPOS", 'f'}, + {"TEXTPTR", 'f'}, + {"TEXTVALID", 'f'}, + {"THEN", 'k'}, + {"TIME", 'k'}, + {"TIMEDIFF", 'f'}, + {"TIMEFROMPARTS", 'f'}, + {"TIMEOFDAY", 'f'}, + {"TIMESERIAL", 'f'}, + {"TIMESTAMP", 't'}, + {"TIMESTAMPADD", 'f'}, + {"TIMEVALUE", 'f'}, + {"TIME_FORMAT", 'f'}, + {"TIME_TO_SEC", 'f'}, + {"TINYBLOB", 'k'}, + {"TINYINT", 'k'}, + {"TINYTEXT", 'k'}, + {"TODATETIMEOFFSET", 'f'}, + {"TOP", 'k'}, + {"TOTAL", 'f'}, + {"TOTAL_CHANGES", 'f'}, + {"TO_ASCII", 'f'}, + {"TO_BASE64", 'f'}, + {"TO_CHAR", 'f'}, + {"TO_DATE", 'f'}, + {"TO_DAYS", 'f'}, + {"TO_HEX", 'f'}, + {"TO_NUMBER", 'f'}, + {"TO_SECONDS", 'f'}, + {"TO_TIMESTAMP", 'f'}, + {"TRAILING", 'n'}, + {"TRANSACTION_TIMESTAMP", 'f'}, + {"TRANSLATE", 'f'}, + {"TRIGGER", 'k'}, + {"TRIGGER_NESTLEVEL", 'f'}, + {"TRIM", 'f'}, + {"TRUE", '1'}, + {"TRUNC", 'f'}, + {"TRUNCATE", 'f'}, + {"TRY", 'T'}, + {"TRY_CAST", 'f'}, + {"TRY_CONVERT", 'f'}, + {"TRY_PARSE", 'f'}, + {"TYPEOF", 'f'}, + {"TYPEPROPERTY", 'f'}, + {"TYPE_ID", 'f'}, + {"TYPE_NAME", 'f'}, + {"UCASE", 'f'}, + {"UESCAPE", 'o'}, + {"UNCOMPRESS", 'f'}, + {"UNCOMPRESS_LENGTH", 'f'}, + {"UNDO", 'k'}, + {"UNHEX", 'f'}, + {"UNICODE", 'f'}, + {"UNION", 'U'}, + {"UNION ALL", 'U'}, + {"UNION ALL DISTINCT", 'U'}, + {"UNION DISTINCT", 'U'}, + {"UNION DISTINCT ALL", 'U'}, + {"UNIQUE", 'n'}, + {"UNIX_TIMESTAMP", 'f'}, + {"UNI_ON", 'U'}, + {"UNKNOWN", 'v'}, + {"UNLOCK", 'k'}, + {"UNNEST", 'f'}, + {"UNSIGNED", 'k'}, + {"UPDATE", 'E'}, + {"UPDATEXML", 'f'}, + {"UPPER", 'f'}, + {"UPPER_INC", 'f'}, + {"UPPER_INF", 'f'}, + {"USAGE", 'k'}, + {"USE", 'T'}, + {"USER", 'n'}, + {"USER_ID", 'n'}, + {"USER_LOCK.SLEEP", 'f'}, + {"USER_NAME", 'n'}, + {"USING", 'f'}, + {"UTC_DATE", 'k'}, + {"UTC_TIME", 'k'}, + {"UTC_TIMESTAMP", 'k'}, + {"UTL_HTTP.REQUEST", 'f'}, + {"UTL_INADDR.GET_HOST_ADDRESS", 'f'}, + {"UTL_INADDR.GET_HOST_NAME", 'f'}, + {"UUID", 'f'}, + {"UUID_SHORT", 'f'}, + {"VALUES", 'k'}, + {"VAR", 'f'}, + {"VARBINARY", 'k'}, + {"VARCHAR", 't'}, + {"VARCHARACTER", 'k'}, + {"VARIANCE", 'f'}, + {"VARP", 'f'}, + {"VARYING", 'k'}, + {"VAR_POP", 'f'}, + {"VAR_SAMP", 'f'}, + {"VERIFYSIGNEDBYASMKEY", 'f'}, + {"VERIFYSIGNEDBYCERT", 'f'}, + {"VERSION", 'f'}, + {"VOID", 't'}, + {"WAIT", 'k'}, + {"WAITFOR", 'n'}, + {"WAITFOR DELAY", 'E'}, + {"WAITFOR RECEIVE", 'E'}, + {"WAITFOR TIME", 'E'}, + {"WEEK", 'f'}, + {"WEEKDAY", 'f'}, + {"WEEKDAYNAME", 'f'}, + {"WEEKOFYEAR", 'f'}, + {"WHEN", 'k'}, + {"WHERE", 'k'}, + {"WHILE", 'T'}, + {"WIDTH_BUCKET", 'f'}, + {"WITH", 'n'}, + {"WITH ROLLUP", 'k'}, + {"XMLAGG", 'f'}, + {"XMLCOMMENT", 'f'}, + {"XMLCONCAT", 'f'}, + {"XMLELEMENT", 'f'}, + {"XMLEXISTS", 'f'}, + {"XMLFOREST", 'f'}, + {"XMLFORMAT", 'f'}, + {"XMLPI", 'f'}, + {"XMLROOT", 'f'}, + {"XMLTYPE", 'f'}, + {"XML_IS_WELL_FORMED", 'f'}, + {"XOR", '&'}, + {"XPATH", 'f'}, + {"XPATH_EXISTS", 'f'}, + {"XP_EXECRESULTSET", 'k'}, + {"YEAR", 'f'}, + {"YEARWEEK", 'f'}, + {"YEAR_MONTH", 'k'}, + {"ZEROBLOB", 'f'}, + {"ZEROFILL", 'k'}, + {"^=", 'o'}, + {"_ARMSCII8", 't'}, + {"_ASCII", 't'}, + {"_BIG5", 't'}, + {"_BINARY", 't'}, + {"_CP1250", 't'}, + {"_CP1251", 't'}, + {"_CP1257", 't'}, + {"_CP850", 't'}, + {"_CP852", 't'}, + {"_CP866", 't'}, + {"_CP932", 't'}, + {"_DEC8", 't'}, + {"_EUCJPMS", 't'}, + {"_EUCKR", 't'}, + {"_GB2312", 't'}, + {"_GBK", 't'}, + {"_GEOSTD8", 't'}, + {"_GREEK", 't'}, + {"_HEBREW", 't'}, + {"_HP8", 't'}, + {"_KEYBCS2", 't'}, + {"_KOI8R", 't'}, + {"_KOI8U", 't'}, + {"_LATIN1", 't'}, + {"_LATIN2", 't'}, + {"_LATIN5", 't'}, + {"_LATIN7", 't'}, + {"_MACCE", 't'}, + {"_MACROMAN", 't'}, + {"_SJIS", 't'}, + {"_SWE7", 't'}, + {"_TIS620", 't'}, + {"_UJIS", 't'}, + {"_USC2", 't'}, + {"_UTF8", 't'}, + {"|/", 'o'}, + {"|=", 'o'}, + {"||", '&'}, + {"~*", 'o'}, +}; +static const size_t sql_keywords_sz = 9352; +#endif diff --git a/apache2/libinjection/libinjection_xss.c b/apache2/libinjection/libinjection_xss.c new file mode 100644 index 0000000..f0df4d8 --- /dev/null +++ b/apache2/libinjection/libinjection_xss.c @@ -0,0 +1,532 @@ + +#include "libinjection.h" +#include "libinjection_xss.h" +#include "libinjection_html5.h" + +#include +#include + +typedef enum attribute { + TYPE_NONE + , TYPE_BLACK /* ban always */ + , TYPE_ATTR_URL /* attribute value takes a URL-like object */ + , TYPE_STYLE + , TYPE_ATTR_INDIRECT /* attribute *name* is given in *value* */ +} attribute_t; + + +static attribute_t is_black_attr(const char* s, size_t len); +static int is_black_tag(const char* s, size_t len); +static int is_black_url(const char* s, size_t len); +static int cstrcasecmp_with_null(const char *a, const char *b, size_t n); +static int html_decode_char_at(const char* src, size_t len, size_t* consumed); +static int htmlencode_startswith(const char* prefix, const char *src, size_t n); + + +typedef struct stringtype { + const char* name; + attribute_t atype; +} stringtype_t; + + +static const int gsHexDecodeMap[256] = { + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256, + 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256 +}; + +static int html_decode_char_at(const char* src, size_t len, size_t* consumed) +{ + int val = 0; + size_t i; + int ch; + + if (len == 0 || src == NULL) { + *consumed = 0; + return -1; + } + + *consumed = 1; + if (*src != '&' || len < 2) { + return (unsigned char)(*src); + } + + + if (*(src+1) != '#') { + /* normally this would be for named entities + * but for this case we don't actually care + */ + return '&'; + } + + if (*(src+2) == 'x' || *(src+2) == 'X') { + ch = (unsigned char) (*(src+3)); + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + /* degenerate case '&#[?]' */ + return '&'; + } + val = ch; + i = 4; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + ch = gsHexDecodeMap[ch]; + if (ch == 256) { + *consumed = i; + return val; + } + val = (val * 16) + ch; + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } else { + i = 2; + ch = (unsigned char) src[i]; + if (ch < '0' || ch > '9') { + return '&'; + } + val = ch - '0'; + i += 1; + while (i < len) { + ch = (unsigned char) src[i]; + if (ch == ';') { + *consumed = i + 1; + return val; + } + if (ch < '0' || ch > '9') { + *consumed = i; + return val; + } + val = (val * 10) + (ch - '0'); + if (val > 0x1000FF) { + return '&'; + } + ++i; + } + *consumed = i; + return val; + } +} + + +/* + * view-source: + * data: + * javascript: + */ +static stringtype_t BLACKATTR[] = { + { "ACTION", TYPE_ATTR_URL } /* form */ + , { "ATTRIBUTENAME", TYPE_ATTR_INDIRECT } /* SVG allow indirection of attribute names */ + , { "BY", TYPE_ATTR_URL } /* SVG */ + , { "BACKGROUND", TYPE_ATTR_URL } /* IE6, O11 */ + , { "DATAFORMATAS", TYPE_BLACK } /* IE */ + , { "DATASRC", TYPE_BLACK } /* IE */ + , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ + , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */ + , { "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 */ + , { "HREF", TYPE_ATTR_URL } + , { "LOWSRC", TYPE_ATTR_URL } /* Obsolete img attribute */ + , { "POSTER", TYPE_ATTR_URL } /* Opera 10,11 */ + , { "SRC", TYPE_ATTR_URL } + , { "STYLE", TYPE_STYLE } + , { "TO", TYPE_ATTR_URL } /* SVG */ + , { "VALUES", TYPE_ATTR_URL } /* SVG */ + , { "XLINK:HREF", TYPE_ATTR_URL } + , { NULL, TYPE_NONE } +}; + +/* xmlns */ +/* `xml-stylesheet` > , */ + +/* + static const char* BLACKATTR[] = { + "ATTRIBUTENAME", + "BACKGROUND", + "DATAFORMATAS", + "HREF", + "SCROLL", + "SRC", + "STYLE", + "SRCDOC", + NULL + }; +*/ + +static const char* BLACKTAG[] = { + "APPLET" + /* , "AUDIO" */ + , "BASE" + , "COMMENT" /* IE http://html5sec.org/#38 */ + , "EMBED" + /* , "FORM" */ + , "FRAME" + , "FRAMESET" + , "HANDLER" /* Opera SVG, effectively a script tag */ + , "IFRAME" + , "IMPORT" + , "ISINDEX" + , "LINK" + , "LISTENER" + /* , "MARQUEE" */ + , "META" + , "NOSCRIPT" + , "OBJECT" + , "SCRIPT" + , "STYLE" + /* , "VIDEO" */ + , "VMLFRAME" + , "XML" + , "XSS" + , NULL +}; + + +static int cstrcasecmp_with_null(const char *a, const char *b, size_t n) +{ + char ca; + char cb; + /* printf("Comparing to %s %.*s\n", a, (int)n, b); */ + while (n-- > 0) { + cb = *b++; + if (cb == '\0') continue; + + ca = *a++; + + if (cb >= 'a' && cb <= 'z') { + cb -= 0x20; + } + /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */ + if (ca != cb) { + return 1; + } + } + + if (*a == 0) { + /* printf(" MATCH \n"); */ + return 0; + } else { + return 1; + } +} + +/* + * Does an HTML encoded binary string (const char*, length) start with + * a all uppercase c-string (null terminated), case insensitive! + * + * also ignore any embedded nulls in the HTML string! + * + * return 1 if match / starts with + * return 0 if not + */ +static int htmlencode_startswith(const char *a, const char *b, size_t n) +{ + size_t consumed; + int cb; + int first = 1; + /* printf("Comparing %s with %.*s\n", a,(int)n,b); */ + while (n > 0) { + if (*a == 0) { + /* printf("Match EOL!\n"); */ + return 1; + } + cb = html_decode_char_at(b, n, &consumed); + b += consumed; + n -= consumed; + + if (first && cb <= 32) { + /* ignore all leading whitespace and control characters */ + continue; + } + first = 0; + + if (cb == 0) { + /* always ignore null characters in user input */ + continue; + } + + if (cb == 10) { + /* always ignore vertical tab characters in user input */ + /* who allows this?? */ + continue; + } + + if (cb >= 'a' && cb <= 'z') { + /* upcase */ + cb -= 0x20; + } + + if (*a != (char) cb) { + /* printf(" %c != %c\n", *a, cb); */ + /* mismatch */ + return 0; + } + a++; + } + + return (*a == 0) ? 1 : 0; +} + +static int is_black_tag(const char* s, size_t len) +{ + const char** black; + + if (len < 3) { + return 0; + } + + black = BLACKTAG; + while (*black != NULL) { + if (cstrcasecmp_with_null(*black, s, len) == 0) { + /* printf("Got black tag %s\n", *black); */ + return 1; + } + black += 1; + } + + /* anything SVG related */ + if ((s[0] == 's' || s[0] == 'S') && + (s[1] == 'v' || s[1] == 'V') && + (s[2] == 'g' || s[2] == 'G')) { + /* printf("Got SVG tag \n"); */ + return 1; + } + + /* Anything XSL(t) related */ + if ((s[0] == 'x' || s[0] == 'X') && + (s[1] == 's' || s[1] == 'S') && + (s[2] == 'l' || s[2] == 'L')) { + /* printf("Got XSL tag\n"); */ + return 1; + } + + return 0; +} + +static attribute_t is_black_attr(const char* s, size_t len) +{ + stringtype_t* black; + + if (len < 2) { + return TYPE_NONE; + } + + 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; + } + + + + /* XMLNS can be used to create arbitrary tags */ + if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) { + /* printf("Got XMLNS and XLINK tags\n"); */ + return TYPE_BLACK; + } + } + + black = BLACKATTR; + while (black->name != NULL) { + if (cstrcasecmp_with_null(black->name, s, len) == 0) { + /* printf("Got banned attribute name %s\n", black->name); */ + return black->atype; + } + black += 1; + } + + return TYPE_NONE; +} + +static int is_black_url(const char* s, size_t len) +{ + + static const char* data_url = "DATA"; + static const char* viewsource_url = "VIEW-SOURCE"; + + /* obsolete but interesting signal */ + static const char* vbscript_url = "VBSCRIPT"; + + /* covers JAVA, JAVASCRIPT, + colon */ + static const char* javascript_url = "JAVA"; + + /* skip whitespace */ + 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 UTF-8 whitespace. + * + * Also in EUC-JP some of the high bytes are just ignored. + */ + ++s; + --len; + } + + if (htmlencode_startswith(data_url, s, len)) { + return 1; + } + + if (htmlencode_startswith(viewsource_url, s, len)) { + return 1; + } + + if (htmlencode_startswith(javascript_url, s, len)) { + return 1; + } + + if (htmlencode_startswith(vbscript_url, s, len)) { + return 1; + } + return 0; +} + +int libinjection_is_xss(const char* s, size_t len, int flags) +{ + h5_state_t h5; + attribute_t attr = TYPE_NONE; + + libinjection_h5_init(&h5, s, len, (enum html5_flags) flags); + while (libinjection_h5_next(&h5)) { + if (h5.token_type != ATTR_VALUE) { + attr = TYPE_NONE; + } + + if (h5.token_type == DOCTYPE) { + return 1; + } else if (h5.token_type == TAG_NAME_OPEN) { + if (is_black_tag(h5.token_start, h5.token_len)) { + return 1; + } + } else if (h5.token_type == ATTR_NAME) { + attr = is_black_attr(h5.token_start, h5.token_len); + } else if (h5.token_type == ATTR_VALUE) { + /* + * IE6,7,8 parsing works a bit differently so + * a whole