mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-11-15 09:02:15 +03:00
Opens space for libmodsecurity
Deletes all files in the repository does not seems to be a good idea. The better approach will be to create a new repository. On other hand we don't want this to be detached from this main repository. We can push this to other repository if necessary.
This commit is contained in:
201
LICENSE
201
LICENSE
@@ -1,201 +0,0 @@
|
||||
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
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
52
Makefile.am
52
Makefile.am
@@ -1,52 +0,0 @@
|
||||
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
|
||||
5
NOTICE
5
NOTICE
@@ -1,5 +0,0 @@
|
||||
ModSecurity (www.modsecurity.org)
|
||||
Copyright [2004-2013] Trustwave Holdings, Inc
|
||||
|
||||
This product includes software developed at
|
||||
Trustwave Holdings, Inc (http://www.trustwave.com/).
|
||||
110
README.TXT
110
README.TXT
@@ -1,110 +0,0 @@
|
||||
ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
|
||||
You may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
If any of the files related to licensing are missing or if you have any
|
||||
other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
directly using the email address security@modsecurity.org.
|
||||
|
||||
|
||||
DOCUMENTATION
|
||||
|
||||
Please refer to the documentation folder (/doc) for
|
||||
the reference manual.
|
||||
|
||||
|
||||
##############################################
|
||||
----------------------------------
|
||||
OWASP ModSecurity Core Rule Set (CRS)
|
||||
|
||||
|
||||
Project Site:
|
||||
https://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project
|
||||
|
||||
|
||||
Download:
|
||||
https://github.com/SpiderLabs/owasp-modsecurity-crs
|
||||
|
||||
----------------------------------
|
||||
|
||||
ModSecurity™ is a web application firewall engine that provides very
|
||||
little protection on its own. In order to become useful, ModSecurity™ must
|
||||
be configured with rules. In order to enable users to take full advantage
|
||||
of ModSecurity™ out of the box, Trustwave's SpiderLabs is providing a free
|
||||
certified rule set for ModSecurity™ 2.x. Unlike intrusion detection and
|
||||
prevention systems, which rely on signatures specific to known
|
||||
vulnerabilities, the Core Rules provide generic protection from unknown
|
||||
vulnerabilities often found in web applications, which are in most cases
|
||||
custom coded. The Core Rules are heavily commented to allow it to be used
|
||||
as a step-by-step deployment guide for ModSecurity™.
|
||||
Core Rules Content
|
||||
|
||||
In order to provide generic web applications protection, the Core Rules
|
||||
use the following techniques:
|
||||
|
||||
* HTTP Protection - detecting violations of the HTTP protocol and a
|
||||
locally defined usage policy.
|
||||
* Real-time Blacklist Lookups - utilizes 3rd Party IP Reputation
|
||||
* Web-based Malware Detection - identifies malicious web content by check
|
||||
against the Google Safe Browsing API.
|
||||
* HTTP Denial of Service Protections - defense against HTTP Flooding and
|
||||
Slow HTTP DoS Attacks.
|
||||
* Common Web Attacks Protection - detecting common web application
|
||||
security attack.
|
||||
* Automation Detection - Detecting bots, crawlers, scanners and other
|
||||
surface malicious activity.
|
||||
* Integration with AV Scanning for File Uploads - detects malicious files
|
||||
uploaded through the web application.
|
||||
* Tracking Sensitive Data - Tracks Credit Card usage and blocks leakages.
|
||||
* Trojan Protection - Detecting access to Trojans horses.
|
||||
* Identification of Application Defects - alerts on application
|
||||
misconfigurations.
|
||||
* Error Detection and Hiding - Disguising error messages sent by the
|
||||
server.
|
||||
|
||||
|
||||
----------------------------------
|
||||
ModSecurity Rules from Trustwave SpiderLabs
|
||||
|
||||
Project Site:
|
||||
https://www.trustwave.com/modsecurity-rules-support.php
|
||||
|
||||
Download:
|
||||
https://ssl.trustwave.com/web-application-firewall
|
||||
|
||||
----------------------------------
|
||||
|
||||
|
||||
|
||||
Trustwave now provides a commercial certified rule set for ModSecurity 2.x
|
||||
that protects against known attacks that target vulnerabilities in public
|
||||
software and are based on intelligence gathered from real-world
|
||||
investigations, honeypot data and research.
|
||||
|
||||
1. More than 16,000 specific rules, broken out into the following attack
|
||||
categories:
|
||||
* SQL injection
|
||||
* Cross-site Scripting (XSS)
|
||||
* Local File Include
|
||||
* Remote File Include
|
||||
|
||||
2. User option for application specific rules, covering the same
|
||||
vulnerability classes for applications such as:
|
||||
* WordPress
|
||||
* cPanel
|
||||
* osCommerce
|
||||
* Joomla
|
||||
* For a complete listing of application coverage, please refer to this
|
||||
link (which is updated daily).
|
||||
https://modsecurity.org/projects/commercial/rules/application_coverage.html
|
||||
|
||||
3. Complements and integrates with the OWASP Core Rule Set
|
||||
4. IP Reputation capabilities which provide protection against malicious
|
||||
clients identified by the Trustwave SpiderLabs Distributed Web Honeypots
|
||||
5. Malware Detection capabilities which prevent your web site from
|
||||
distributing malicious code to clients.
|
||||
##############################################
|
||||
@@ -1,192 +0,0 @@
|
||||
=====================================================================
|
||||
MOD_SECURITY 2.6 Command-line Build notes for Windows 4/2/2011
|
||||
by Tom Donovam
|
||||
=====================================================================
|
||||
|
||||
PREREQUISITES:
|
||||
|
||||
Microsoft Visual Studio C++ tested with Visual Studio 2008 (aka VC9)
|
||||
|
||||
CMake build system from: http://www.cmake.org/ tested with CMake v2.8.0
|
||||
|
||||
Apache 2.2.x from: http://httpd.apache.org/ tested with Apache 2.2.17
|
||||
Apache must be built from source using the same Visual Studio compiler as mod_security.
|
||||
|
||||
PCRE Perl Compatible Regular Expression library from: http://www.pcre.org/ tested with PCRE v8.12
|
||||
|
||||
LibXML2 from: http://xmlsoft.org/ tested with LibXML2 v2.7.7
|
||||
Note that LibXML2 v2.7.8 does not build correctly for Windows
|
||||
|
||||
Lua Scripting Language from: http://www.lua.org/ tested with Lua v5.1.4
|
||||
|
||||
cURL multiprotocol file transfer library from: http://curl.haxx.se/ tested with cURL v7.21.4
|
||||
|
||||
|
||||
BEFORE BUILDING
|
||||
|
||||
The directory where you build software from source ( C:\work in this exmaple)
|
||||
must contain the Apache source you used to build the Apache web serverand the mod_security source
|
||||
|
||||
Apache source is in C:\work\httpd-2.2.17 in this example.
|
||||
Apache has been installed to C:\Apache2217 in this example.
|
||||
Mod_security source is in C:\work\mod_security in this example.
|
||||
|
||||
Download and untar the prerequite library sources:
|
||||
|
||||
Download pcre-8.12.tar.gz from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
|
||||
untar it into C:\work\ creating C:\work\pcre-8.12
|
||||
|
||||
Download libxml2-2.7.7.tar.gz from ftp://xmlsoft.org/libxml2/
|
||||
untar it into C:\work\ creating C:\work\libxml2-2.7.7
|
||||
|
||||
Download lua-5.1.4.tar.gz from http://www.lua.org/ftp/
|
||||
untar it into C:\work\ creating C:\work\lua-5.1.4
|
||||
|
||||
Download curl-7.21.4.tar.gz from http://curl.haxx.se/download.html
|
||||
untar it into C:\work\ creating C:\work\curl-7.21.4
|
||||
|
||||
Setup your build environment:
|
||||
|
||||
The PATH environment variable must include the Visual Studio variables as set by vsvars32.bat
|
||||
The PATH environment variable must also include the CMAKE bin\ directory
|
||||
|
||||
Set an environment variable to the Apache source code directory:
|
||||
|
||||
SET HTTPD_BUILD=C:\work\httpd-2.2.17
|
||||
|
||||
If OpenSSL and Zlib support were included when you built Apache 2.2, and you want them available to LIBXML2 and CURL
|
||||
|
||||
Ensure that cURL and libXML2 can find the OpenSSL and Zlib includes and libraries that Apache was built with.
|
||||
|
||||
SET INCLUDE=%INCLUDE%;%HTTPD_BUILD%\srclib\openssl\inc32;%HTTPD_BUILD%\srclib\zlib
|
||||
SET LIB=%LIB%;%HTTPD_BUILD%\srclib\openssl\out32dll;%HTTPD_BUILD%\srclib\zlib
|
||||
|
||||
Ensure that cURL and libXML2 don't use the static zlib library: zlib.lib.
|
||||
Force cURL and libXML2 to use zdll.lib instead, requiring zlib1.dll at runtime:
|
||||
|
||||
IF EXIST %HTTPD_BUILD%\srclib\zlib\zlib.lib DEL %HTTPD_BUILD%\srclib\zlib\zlib.lib
|
||||
|
||||
BUILD PCRE-8.12
|
||||
|
||||
CD C:\work\pcre-8.12
|
||||
CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True
|
||||
NMAKE
|
||||
|
||||
BUILD LIBXML2-2.7.7 (note: the more recent version: 2.7.8 does not build correctly on Windows)
|
||||
|
||||
CD C:\work\libxml2-2.7.7\win32
|
||||
CSCRIPT configure.js iconv=no vcmanifest=yes zlib=yes
|
||||
NMAKE -f Makefile.msvc
|
||||
|
||||
BUILD LUA-5.1.4
|
||||
|
||||
CD C:\work\lua-5.1.4\src
|
||||
CL /Ox /arch:SSE2 /GF /GL /Gy /FD /EHsc /MD /Zi /TC /wd4005 /D "_MBCS" /D "LUA_CORE" /D "LUA_BUILD_AS_DLL" /D "_CRT_SECURE_NO_WARNINGS" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_WIN32" /D "_WINDLL" /c *.c
|
||||
DEL lua.obj luac.obj
|
||||
LINK /DLL /LTCG /DEBUG /OUT:lua5.1.dll *.obj
|
||||
IF EXIST lua5.1.dll.manifest MT -manifest lua5.1.dll.manifest -outputresource:lua5.1.dll;2
|
||||
|
||||
BUILD CURL-7.21.4
|
||||
|
||||
CD C:\work\curl-7.21.4
|
||||
CMAKE -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_SHARED_LIBS=True -DCURL_ZLIB=True
|
||||
NMAKE
|
||||
|
||||
BUILD MOD_SECURITY-2.6
|
||||
|
||||
CD C:\work\mod_security\apache2
|
||||
NMAKE -f Makefile.win APACHE=C:\Apache2217 PCRE=C:\work\pcre-8.12 LIBXML2=C:\work\libxml2-2.7.7 LUA=C:\work\lua-5.1.4\src
|
||||
|
||||
INSTALL MOD_SECURITY AND RUN APACHE
|
||||
|
||||
Copy these five files to C:\Apache2217\bin:
|
||||
C:\work\pcre-8.12\pcre.dll C:\Apache2217\bin\
|
||||
C:\work\lua-5.1.4\src\lua5.1.dll C:\Apache2217\bin\
|
||||
C:\work\libxml2-2.7.7\win32\bin.msvc\libxml2.dll C:\Apache2217\bin\
|
||||
C:\work\curl-7.21.4\libcurl.dll C:\Apache2217\bin\
|
||||
C:\work\mod_security\apache2\mlogc-src\mlogc.exe
|
||||
|
||||
Copy this one file to C:\Apache2217\modules:
|
||||
|
||||
C:\work\mod_security\apache2\mod_security2.so
|
||||
|
||||
You may also copy C:\work\curl-7.21.4\curl.exe to C:\Apache2217\bin, if you want to use the cURL command-line program.
|
||||
|
||||
Download the core rules from http://sourceforge.net/projects/mod-security/files/modsecurity-crs/0-CURRENT/
|
||||
and unzip them into C:\Apache2217\conf\modsecurity_crs
|
||||
|
||||
Add configuration directives to your Apache conf\httpd.conf:
|
||||
|
||||
# mod_security requires mod_unique_id
|
||||
LoadModule unique_id_module modules/mod_unique_id.so
|
||||
|
||||
# mod_security
|
||||
LoadModule security2_module modules/mod_security2.so
|
||||
<IfModule security2_module>
|
||||
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
|
||||
</IfModule>
|
||||
|
||||
|
||||
==============================================================================================
|
||||
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
|
||||
@@ -1,13 +0,0 @@
|
||||
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@
|
||||
1418
alp2/alp2.c
1418
alp2/alp2.c
File diff suppressed because it is too large
Load Diff
164
alp2/alp2.h
164
alp2/alp2.h
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _ALP2_H_
|
||||
#define _ALP2_H_
|
||||
|
||||
#include <apr_time.h>
|
||||
#include <apr_uri.h>
|
||||
|
||||
#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
|
||||
362
alp2/alp2_pp.c
362
alp2/alp2_pp.c
@@ -1,362 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#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.
|
||||
*/
|
||||
}
|
||||
124
alp2/alp2_pp.h
124
alp2/alp2_pp.h
@@ -1,124 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _ALP2_LL_H_
|
||||
#define _ALP2_LL_H_
|
||||
|
||||
#include <apr_general.h>
|
||||
#include <apr_md5.h>
|
||||
#include <apr_strings.h>
|
||||
#include <apr_tables.h>
|
||||
#include <apr_md5.h>
|
||||
|
||||
/* -- 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
|
||||
@@ -1,192 +0,0 @@
|
||||
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
|
||||
@@ -1,93 +0,0 @@
|
||||
###########################################################################
|
||||
#
|
||||
# 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
|
||||
597
apache2/acmp.c
597
apache2/acmp.c
@@ -1,597 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
/* 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 <apr_lib.h>
|
||||
#define utf8_lcase(a) apr_tolower(a)
|
||||
#endif
|
||||
|
||||
#include <apr_tables.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/*
|
||||
*******************************************************************************
|
||||
*******************************************************************************
|
||||
* 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;
|
||||
}
|
||||
121
apache2/acmp.h
121
apache2/acmp.h
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef ACMP_H_
|
||||
#define ACMP_H_
|
||||
|
||||
#include <apr.h>
|
||||
#include <apr_pools.h>
|
||||
|
||||
#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_*/
|
||||
@@ -1,99 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _APACHE2_H_
|
||||
#define _APACHE2_H_
|
||||
|
||||
#include "http_core.h"
|
||||
#include "http_request.h"
|
||||
#include "httpd.h"
|
||||
#include "ap_release.h"
|
||||
|
||||
#include <apr_general.h>
|
||||
#include <apr_optional.h>
|
||||
|
||||
|
||||
#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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1026
apache2/apache2_io.c
1026
apache2/apache2_io.c
File diff suppressed because it is too large
Load Diff
@@ -1,396 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#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_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r->server,
|
||||
"[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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Copyright 2012, 2013 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 <string.h>
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,795 +0,0 @@
|
||||
#include "libinjection_html5.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#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)
|
||||
{
|
||||
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();
|
||||
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.
|
||||
* dont do this is pos == 0 since it means we have started
|
||||
* in a non-data state. given an input of '><foo
|
||||
* we want to make 0-length attribute name
|
||||
*/
|
||||
if (hs->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;
|
||||
|
||||
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;
|
||||
}
|
||||
ch = *(idx + 1);
|
||||
if (ch != CHAR_DASH && ch != CHAR_BANG) {
|
||||
pos = (size_t)(idx - hs->s) + 1;
|
||||
continue;
|
||||
}
|
||||
ch = *(idx + 2);
|
||||
if (ch != CHAR_GT) {
|
||||
pos = (size_t)(idx - hs->s) + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ends in --> or -!> */
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = (size_t)(idx - hs->s) - hs->pos;
|
||||
hs->pos = (size_t)(idx - hs->s) + 3;
|
||||
hs->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;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#ifndef LIBINJECTION_HTML5
|
||||
#define LIBINJECTION_HTML5
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* pull in size_t */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,295 +0,0 @@
|
||||
/**
|
||||
* Copyright 2012, 2013 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 <string.h>
|
||||
|
||||
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
|
||||
char type;
|
||||
char str_open;
|
||||
char str_close;
|
||||
|
||||
/*
|
||||
* 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 unsed in other contexts
|
||||
*/
|
||||
int count;
|
||||
|
||||
char val[32];
|
||||
};
|
||||
|
||||
typedef struct libinjection_sqli_token stoken_t;
|
||||
|
||||
/**
|
||||
* Pointer to function, takes cstr 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 index in string we are at when tokenizing
|
||||
*/
|
||||
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
|
||||
* Mimimum 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 H@CKERS ONLY
|
||||
*
|
||||
*/
|
||||
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) &&
|
||||
* libinject_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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,540 +0,0 @@
|
||||
|
||||
#include "libinjection.h"
|
||||
#include "libinjection_xss.h"
|
||||
#include "libinjection_html5.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef DEBUG
|
||||
#include <stdio.h>
|
||||
#define TRACE() printf("%s:%d\n", __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define TRACE()
|
||||
#endif
|
||||
|
||||
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 } /* HTML5 */
|
||||
, { "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 > <eval>, <if expr=> */
|
||||
|
||||
/*
|
||||
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*, lenght) start with
|
||||
* a all uppercase c-string (null terminated), case insenstive!
|
||||
*
|
||||
* 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 vtab 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;
|
||||
}
|
||||
|
||||
/* javascript on.* */
|
||||
if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) {
|
||||
/* printf("Got javascript on- attribute name\n"); */
|
||||
return TYPE_BLACK;
|
||||
}
|
||||
|
||||
|
||||
if (len >= 5) {
|
||||
/* XMLNS can be used to create arbitrary tags */
|
||||
if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) {
|
||||
/* printf("Got XMLNS and XLINK tags\n"); */
|
||||
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) {
|
||||
/*
|
||||
* HEY: this is a signed character.
|
||||
* We are intentionally skipping high-bit characters too
|
||||
* since they are not ascii, and Opera sometimes uses UTF8 whitespace
|
||||
*/
|
||||
if (*s <= 32) {
|
||||
++s;
|
||||
--len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
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 <script> or other black tag might be hiding
|
||||
* inside an attribute value under HTML5 parsing
|
||||
* See http://html5sec.org/#102
|
||||
* to avoid doing a full reparse of the value, just
|
||||
* look for "<". This probably need adjusting to
|
||||
* handle escaped characters
|
||||
*/
|
||||
/*
|
||||
if (memchr(h5.token_start, '<', h5.token_len) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
switch (attr) {
|
||||
case TYPE_NONE:
|
||||
break;
|
||||
case TYPE_BLACK:
|
||||
return 1;
|
||||
case TYPE_ATTR_URL:
|
||||
if (is_black_url(h5.token_start, h5.token_len)) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case TYPE_STYLE:
|
||||
return 1;
|
||||
case TYPE_ATTR_INDIRECT:
|
||||
/* an attribute name is specified in a _value_ */
|
||||
if (is_black_attr(h5.token_start, h5.token_len)) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
default:
|
||||
assert(0);
|
||||
*/
|
||||
}
|
||||
attr = TYPE_NONE;
|
||||
} else if (h5.token_type == TAG_COMMENT) {
|
||||
/* IE uses a "`" as a tag ending char */
|
||||
if (memchr(h5.token_start, '`', h5.token_len) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* IE conditional comment */
|
||||
if (h5.token_len > 3) {
|
||||
if (h5.token_start[0] == '[' &&
|
||||
(h5.token_start[1] == 'i' || h5.token_start[1] == 'I') &&
|
||||
(h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) {
|
||||
return 1;
|
||||
}
|
||||
if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') &&
|
||||
(h5.token_start[1] == 'm' || h5.token_start[1] == 'M') &&
|
||||
(h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (h5.token_len > 5) {
|
||||
/* IE <?import pseudo-tag */
|
||||
if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XML Entity definition */
|
||||
if (cstrcasecmp_with_null("ENTITY", h5.token_start, 6) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* wrapper
|
||||
*/
|
||||
int libinjection_xss(const char* s, size_t len)
|
||||
{
|
||||
if (libinjection_is_xss(s, len, DATA_STATE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef LIBINJECTION_XSS
|
||||
#define LIBINJECTION_XSS
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* HEY THIS ISN'T DONE
|
||||
*/
|
||||
|
||||
/* pull in size_t */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
int libinjection_is_xss(const char* s, size_t len, int flags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
/* This file is left empty for building on Windows. */
|
||||
@@ -1,828 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "apr_global_mutex.h"
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include "msc_parsers.h"
|
||||
#include "msc_util.h"
|
||||
#include "msc_json.h"
|
||||
#include "msc_xml.h"
|
||||
#include "apr_version.h"
|
||||
|
||||
#ifdef WITH_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
unsigned long int DSOLOCAL unicode_codepage = 0;
|
||||
|
||||
int DSOLOCAL *unicode_map_table = NULL;
|
||||
|
||||
/**
|
||||
* Format an alert message.
|
||||
*/
|
||||
const char * msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message,
|
||||
const char *rule_message)
|
||||
{
|
||||
const char *message = NULL;
|
||||
|
||||
if (rule_message == NULL) rule_message = "Unknown error.";
|
||||
|
||||
if (action_message == NULL) {
|
||||
message = apr_psprintf(msr->mp, "%s%s",
|
||||
rule_message, msre_format_metadata(msr, actionset));
|
||||
}
|
||||
else {
|
||||
message = apr_psprintf(msr->mp, "%s %s%s", action_message,
|
||||
rule_message, msre_format_metadata(msr, actionset));
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an alert message to the log, adding the rule metadata at the end.
|
||||
*/
|
||||
void msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
|
||||
const char *rule_message)
|
||||
{
|
||||
const char *message = msc_alert_message(msr, actionset, action_message, rule_message);
|
||||
|
||||
msr_log(msr, level, "%s", message);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Return phase name associated with the given phase number.
|
||||
*/
|
||||
static const char *phase_name(int phase) {
|
||||
switch(phase) {
|
||||
case 1 :
|
||||
return "REQUEST_HEADERS";
|
||||
break;
|
||||
case 2 :
|
||||
return "REQUEST_BODY";
|
||||
break;
|
||||
case 3 :
|
||||
return "RESPONSE_HEADERS";
|
||||
break;
|
||||
case 4 :
|
||||
return "RESPONSE_BODY";
|
||||
break;
|
||||
case 5 :
|
||||
return "LOGGING";
|
||||
break;
|
||||
}
|
||||
|
||||
return "INVALID";
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates and initialises a ModSecurity engine instance.
|
||||
*/
|
||||
msc_engine *modsecurity_create(apr_pool_t *mp, int processing_mode) {
|
||||
msc_engine *msce = NULL;
|
||||
|
||||
msce = apr_pcalloc(mp, sizeof(msc_engine));
|
||||
if (msce == NULL) return NULL;
|
||||
|
||||
msce->mp = mp;
|
||||
msce->processing_mode = processing_mode;
|
||||
|
||||
msce->msre = msre_engine_create(msce->mp);
|
||||
if (msce->msre == NULL) return NULL;
|
||||
msre_engine_register_default_variables(msce->msre);
|
||||
msre_engine_register_default_operators(msce->msre);
|
||||
msre_engine_register_default_tfns(msce->msre);
|
||||
msre_engine_register_default_actions(msce->msre);
|
||||
// TODO: msre_engine_register_default_reqbody_processors(msce->msre);
|
||||
|
||||
return msce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the modsecurity engine. This function must be invoked
|
||||
* after configuration processing is complete as Apache needs to know the
|
||||
* username it is running as.
|
||||
*/
|
||||
int modsecurity_init(msc_engine *msce, apr_pool_t *mp) {
|
||||
apr_status_t rc;
|
||||
|
||||
/**
|
||||
* Notice that curl is initialized here but never cleaned up. First version
|
||||
* of this implementation curl was initialized and cleaned for every
|
||||
* utilization. Turns out that it was not only cleaning stuff that was
|
||||
* utilized by Curl but also other OpenSSL stuff that was utilized by
|
||||
* mod_ssl leading the SSL support to crash.
|
||||
*/
|
||||
#ifdef WITH_CURL
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
#endif
|
||||
/* Serial audit log mutext */
|
||||
rc = apr_global_mutex_create(&msce->auditlog_lock, NULL, APR_LOCK_DEFAULT, mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
//ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "mod_security: Could not create modsec_auditlog_lock");
|
||||
//return HTTP_INTERNAL_SERVER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if !defined(MSC_TEST)
|
||||
#ifdef __SET_MUTEX_PERMS
|
||||
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
|
||||
rc = ap_unixd_set_global_mutex_perms(msce->auditlog_lock);
|
||||
#else
|
||||
rc = unixd_set_global_mutex_perms(msce->auditlog_lock);
|
||||
#endif
|
||||
if (rc != APR_SUCCESS) {
|
||||
// ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, "mod_security: Could not set permissions on modsec_auditlog_lock; check User and Group directives");
|
||||
// return HTTP_INTERNAL_SERVER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
#endif /* SET_MUTEX_PERMS */
|
||||
|
||||
rc = apr_global_mutex_create(&msce->geo_lock, NULL, APR_LOCK_DEFAULT, mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __SET_MUTEX_PERMS
|
||||
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2
|
||||
rc = ap_unixd_set_global_mutex_perms(msce->geo_lock);
|
||||
#else
|
||||
rc = unixd_set_global_mutex_perms(msce->geo_lock);
|
||||
#endif
|
||||
if (rc != APR_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
#endif /* SET_MUTEX_PERMS */
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs per-child (new process) initialisation.
|
||||
*/
|
||||
void modsecurity_child_init(msc_engine *msce) {
|
||||
/* Need to call this once per process before any other XML calls. */
|
||||
xmlInitParser();
|
||||
|
||||
if (msce->auditlog_lock != NULL) {
|
||||
apr_status_t rc = apr_global_mutex_child_init(&msce->auditlog_lock, NULL, msce->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
// ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init auditlog mutex");
|
||||
}
|
||||
}
|
||||
|
||||
if (msce->geo_lock != NULL) {
|
||||
apr_status_t rc = apr_global_mutex_child_init(&msce->geo_lock, NULL, msce->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
// ap_log_error(APLOG_MARK, APLOG_ERR, rs, s, "Failed to child-init geo mutex");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases resources held by engine instance.
|
||||
*/
|
||||
void modsecurity_shutdown(msc_engine *msce) {
|
||||
if (msce == NULL) return;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void modsecurity_persist_data(modsec_rec *msr) {
|
||||
const apr_array_header_t *arr;
|
||||
apr_table_entry_t *te;
|
||||
apr_time_t time_before, time_after;
|
||||
int i;
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
/* Collections, store & remove stale. */
|
||||
arr = apr_table_elts(msr->collections);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
apr_table_t *col = (apr_table_t *)te[i].val;
|
||||
|
||||
/* Only store those collections that changed. */
|
||||
if (apr_table_get(msr->collections_dirty, te[i].key)) {
|
||||
collection_store(msr, col);
|
||||
}
|
||||
}
|
||||
|
||||
time_after = apr_time_now();
|
||||
|
||||
msr->time_storage_write += time_after - time_before;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Recording persistent data took %" APR_TIME_T_FMT
|
||||
" microseconds.", msr->time_gc);
|
||||
}
|
||||
|
||||
/* Remove stale collections. */
|
||||
srand(time(NULL));
|
||||
|
||||
if (rand() < RAND_MAX/100) {
|
||||
arr = apr_table_elts(msr->collections);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
collections_remove_stale(msr, te[i].key);
|
||||
}
|
||||
|
||||
msr->time_gc = apr_time_now() - time_after;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Garbage collection took %" APR_TIME_T_FMT
|
||||
" microseconds.", msr->time_gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_tx_cleanup(void *data) {
|
||||
modsec_rec *msr = (modsec_rec *)data;
|
||||
char *my_error_msg = NULL;
|
||||
|
||||
if (msr == NULL) return APR_SUCCESS;
|
||||
|
||||
/* Multipart processor cleanup. */
|
||||
if (msr->mpd != NULL) multipart_cleanup(msr);
|
||||
|
||||
/* XML processor cleanup. */
|
||||
if (msr->xml != NULL) xml_cleanup(msr);
|
||||
|
||||
#ifdef WITH_YAJL
|
||||
/* JSON processor cleanup. */
|
||||
if (msr->json != NULL) json_cleanup(msr);
|
||||
#endif
|
||||
|
||||
// TODO: Why do we ignore return code here?
|
||||
modsecurity_request_body_clear(msr, &my_error_msg);
|
||||
if (my_error_msg != NULL) {
|
||||
msr_log(msr, 1, "%s", my_error_msg);
|
||||
}
|
||||
|
||||
if (msr->msc_full_request_length > 0 &&
|
||||
msr->msc_full_request_buffer != NULL) {
|
||||
msr->msc_full_request_length = 0;
|
||||
free(msr->msc_full_request_buffer);
|
||||
}
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
#ifdef CACHE_LUA
|
||||
if(msr->L != NULL) lua_close(msr->L);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
apr_status_t modsecurity_tx_init(modsec_rec *msr) {
|
||||
const char *s = NULL;
|
||||
const apr_array_header_t *arr;
|
||||
char *semicolon = NULL;
|
||||
char *comma = NULL;
|
||||
apr_table_entry_t *te;
|
||||
int i;
|
||||
|
||||
/* Register TX cleanup */
|
||||
apr_pool_cleanup_register(msr->mp, msr, modsecurity_tx_cleanup, apr_pool_cleanup_null);
|
||||
|
||||
/* Initialise C-L */
|
||||
msr->request_content_length = -1;
|
||||
s = apr_table_get(msr->request_headers, "Content-Length");
|
||||
if (s != NULL) {
|
||||
msr->request_content_length = strtol(s, NULL, 10);
|
||||
}
|
||||
|
||||
/* Figure out whether this request has a body */
|
||||
msr->reqbody_chunked = 0;
|
||||
msr->reqbody_should_exist = 0;
|
||||
if (msr->request_content_length == -1) {
|
||||
/* There's no C-L, but is chunked encoding used? */
|
||||
char *transfer_encoding = (char *)apr_table_get(msr->request_headers, "Transfer-Encoding");
|
||||
if ((transfer_encoding != NULL)&&(m_strcasestr(transfer_encoding, "chunked") != NULL)) {
|
||||
msr->reqbody_should_exist = 1;
|
||||
msr->reqbody_chunked = 1;
|
||||
}
|
||||
} else {
|
||||
/* C-L found */
|
||||
msr->reqbody_should_exist = 1;
|
||||
}
|
||||
|
||||
/* Initialise C-T */
|
||||
msr->request_content_type = NULL;
|
||||
s = apr_table_get(msr->request_headers, "Content-Type");
|
||||
if (s != NULL) msr->request_content_type = s;
|
||||
|
||||
/* Decide what to do with the request body. */
|
||||
if ((msr->request_content_type != NULL)
|
||||
&& (strncasecmp(msr->request_content_type, "application/x-www-form-urlencoded", 33) == 0))
|
||||
{
|
||||
/* Always place POST requests with
|
||||
* "application/x-www-form-urlencoded" payloads in memory.
|
||||
*/
|
||||
msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
|
||||
msr->msc_reqbody_spilltodisk = 0;
|
||||
msr->msc_reqbody_processor = "URLENCODED";
|
||||
} else {
|
||||
/* If the C-L is known and there's more data than
|
||||
* our limit go to disk straight away.
|
||||
*/
|
||||
if ((msr->request_content_length != -1)
|
||||
&& (msr->request_content_length > msr->txcfg->reqbody_inmemory_limit))
|
||||
{
|
||||
msr->msc_reqbody_storage = MSC_REQBODY_DISK;
|
||||
}
|
||||
|
||||
/* In all other cases, try using the memory first
|
||||
* but switch over to disk for larger bodies.
|
||||
*/
|
||||
msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
|
||||
msr->msc_reqbody_spilltodisk = 1;
|
||||
|
||||
if (msr->request_content_type != NULL) {
|
||||
if (strncasecmp(msr->request_content_type, "multipart/form-data", 19) == 0) {
|
||||
msr->msc_reqbody_processor = "MULTIPART";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we are forcing buffering, then use memory only. */
|
||||
if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
|
||||
msr->msc_reqbody_storage = MSC_REQBODY_MEMORY;
|
||||
msr->msc_reqbody_spilltodisk = 0;
|
||||
}
|
||||
|
||||
/* Initialise arguments */
|
||||
msr->arguments = apr_table_make(msr->mp, 32);
|
||||
if (msr->arguments == NULL) return -1;
|
||||
if (msr->query_string != NULL) {
|
||||
int invalid_count = 0;
|
||||
|
||||
if (parse_arguments(msr, msr->query_string, strlen(msr->query_string),
|
||||
msr->txcfg->argument_separator, "QUERY_STRING", msr->arguments,
|
||||
&invalid_count) < 0)
|
||||
{
|
||||
msr_log(msr, 1, "Initialisation: Error occurred while parsing QUERY_STRING arguments.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (invalid_count) {
|
||||
msr->urlencoded_error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
msr->arguments_to_sanitize = apr_table_make(msr->mp, 16);
|
||||
if (msr->arguments_to_sanitize == NULL) return -1;
|
||||
msr->request_headers_to_sanitize = apr_table_make(msr->mp, 16);
|
||||
if (msr->request_headers_to_sanitize == NULL) return -1;
|
||||
msr->response_headers_to_sanitize = apr_table_make(msr->mp, 16);
|
||||
if (msr->response_headers_to_sanitize == NULL) return -1;
|
||||
msr->pattern_to_sanitize = apr_table_make(msr->mp, 32);
|
||||
if (msr->pattern_to_sanitize == NULL) return -1;
|
||||
|
||||
/* remove targets */
|
||||
msr->removed_targets = apr_table_make(msr->mp, 16);
|
||||
if (msr->removed_targets == NULL) return -1;
|
||||
|
||||
/* Initialise cookies */
|
||||
msr->request_cookies = apr_table_make(msr->mp, 16);
|
||||
if (msr->request_cookies == NULL) return -1;
|
||||
|
||||
/* Initialize matched vars */
|
||||
msr->matched_vars = apr_table_make(msr->mp, 8);
|
||||
if (msr->matched_vars == NULL) return -1;
|
||||
apr_table_clear(msr->matched_vars);
|
||||
|
||||
msr->perf_rules = apr_table_make(msr->mp, 8);
|
||||
if (msr->perf_rules == NULL) return -1;
|
||||
apr_table_clear(msr->perf_rules);
|
||||
|
||||
/* Locate the cookie headers and parse them */
|
||||
arr = apr_table_elts(msr->request_headers);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
if (strcasecmp(te[i].key, "Cookie") == 0) {
|
||||
if (msr->txcfg->cookie_format == COOKIES_V0) {
|
||||
semicolon = apr_pstrdup(msr->mp, te[i].val);
|
||||
while((*semicolon != 0)&&(*semicolon != ';')) semicolon++;
|
||||
if(*semicolon == ';') {
|
||||
parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
|
||||
} else {
|
||||
comma = apr_pstrdup(msr->mp, te[i].val);
|
||||
while((*comma != 0)&&(*comma != ',')) comma++;
|
||||
if(*comma == ',') {
|
||||
comma++;
|
||||
if(*comma == 0x20) {// looks like comma is the separator
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Cookie v0 parser: Using comma as a separator. Semi-colon was not identified!");
|
||||
}
|
||||
parse_cookies_v0(msr, te[i].val, msr->request_cookies, ",");
|
||||
} else {
|
||||
parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
|
||||
}
|
||||
} else {
|
||||
parse_cookies_v0(msr, te[i].val, msr->request_cookies, ";");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parse_cookies_v1(msr, te[i].val, msr->request_cookies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Collections. */
|
||||
msr->tx_vars = apr_table_make(msr->mp, 32);
|
||||
if (msr->tx_vars == NULL) return -1;
|
||||
|
||||
msr->geo_vars = apr_table_make(msr->mp, 8);
|
||||
if (msr->geo_vars == NULL) return -1;
|
||||
|
||||
msr->collections_original = apr_table_make(msr->mp, 8);
|
||||
if (msr->collections_original == NULL) return -1;
|
||||
msr->collections = apr_table_make(msr->mp, 8);
|
||||
if (msr->collections == NULL) return -1;
|
||||
msr->collections_dirty = apr_table_make(msr->mp, 8);
|
||||
if (msr->collections_dirty == NULL) return -1;
|
||||
|
||||
/* Other */
|
||||
msr->tcache = NULL;
|
||||
msr->tcache_items = 0;
|
||||
|
||||
msr->matched_rules = apr_array_make(msr->mp, 16, sizeof(void *));
|
||||
if (msr->matched_rules == NULL) return -1;
|
||||
|
||||
msr->matched_var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
if (msr->matched_var == NULL) return -1;
|
||||
|
||||
msr->highest_severity = 255; /* high, invalid value */
|
||||
|
||||
msr->removed_rules = apr_array_make(msr->mp, 16, sizeof(char *));
|
||||
if (msr->removed_rules == NULL) return -1;
|
||||
|
||||
msr->removed_rules_tag = apr_array_make(msr->mp, 16, sizeof(char *));
|
||||
if (msr->removed_rules_tag == NULL) return -1;
|
||||
|
||||
msr->removed_rules_msg = apr_array_make(msr->mp, 16, sizeof(char *));
|
||||
if (msr->removed_rules_msg == NULL) return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int is_response_status_relevant(modsec_rec *msr, int status) {
|
||||
char *my_error_msg = NULL;
|
||||
apr_status_t rc;
|
||||
char buf[32];
|
||||
|
||||
/* ENH: Setting is_relevant here will cause an audit even if noauditlog
|
||||
* was set for the last rule that matched. Is this what we want?
|
||||
*/
|
||||
|
||||
if ((msr->txcfg->auditlog_relevant_regex == NULL)
|
||||
||(msr->txcfg->auditlog_relevant_regex == NOT_SET_P))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
apr_snprintf(buf, sizeof(buf), "%d", status);
|
||||
|
||||
rc = msc_regexec(msr->txcfg->auditlog_relevant_regex, buf, strlen(buf), &my_error_msg);
|
||||
if (rc >= 0) return 1;
|
||||
if (rc == PCRE_ERROR_NOMATCH) return 0;
|
||||
|
||||
msr_log(msr, 1, "Regex processing failed (rc %d): %s", rc, my_error_msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_process_phase_request_headers(modsec_rec *msr) {
|
||||
apr_time_t time_before;
|
||||
apr_status_t rc = 0;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Starting phase REQUEST_HEADERS.");
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
if (msr->txcfg->ruleset != NULL) {
|
||||
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||
}
|
||||
|
||||
msr->time_phase1 = apr_time_now() - time_before;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_process_phase_request_body(modsec_rec *msr) {
|
||||
apr_time_t time_before;
|
||||
apr_status_t rc = 0;
|
||||
|
||||
|
||||
if ((msr->allow_scope == ACTION_ALLOW_REQUEST)||(msr->allow_scope == ACTION_ALLOW)) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Skipping phase REQUEST_BODY (allow used).");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Starting phase REQUEST_BODY.");
|
||||
}
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
if (msr->txcfg->ruleset != NULL) {
|
||||
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||
}
|
||||
|
||||
msr->time_phase2 = apr_time_now() - time_before;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_process_phase_response_headers(modsec_rec *msr) {
|
||||
apr_time_t time_before;
|
||||
apr_status_t rc = 0;
|
||||
|
||||
if (msr->allow_scope == ACTION_ALLOW) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Skipping phase RESPONSE_HEADERS (allow used).");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Starting phase RESPONSE_HEADERS.");
|
||||
}
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
if (msr->txcfg->ruleset != NULL) {
|
||||
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||
}
|
||||
|
||||
msr->time_phase3 = apr_time_now() - time_before;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_process_phase_response_body(modsec_rec *msr) {
|
||||
apr_time_t time_before;
|
||||
apr_status_t rc = 0;
|
||||
|
||||
if (msr->allow_scope == ACTION_ALLOW) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Skipping phase RESPONSE_BODY (allow used).");
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Starting phase RESPONSE_BODY.");
|
||||
}
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
if (msr->txcfg->ruleset != NULL) {
|
||||
rc = msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||
}
|
||||
|
||||
msr->time_phase4 = apr_time_now() - time_before;
|
||||
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_process_phase_logging(modsec_rec *msr) {
|
||||
apr_time_t time_before, time_after;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Starting phase LOGGING.");
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
if (msr->txcfg->ruleset != NULL) {
|
||||
msre_ruleset_process_phase(msr->txcfg->ruleset, msr);
|
||||
}
|
||||
|
||||
modsecurity_persist_data(msr);
|
||||
|
||||
time_after = apr_time_now();
|
||||
msr->time_phase5 = time_after - time_before;
|
||||
|
||||
/* Is this request relevant for logging purposes? */
|
||||
if (msr->is_relevant == 0) {
|
||||
/* Check the status */
|
||||
msr->is_relevant += is_response_status_relevant(msr, msr->r->status);
|
||||
|
||||
/* If we processed two requests and statuses are different then
|
||||
* check the other status too.
|
||||
*/
|
||||
if (msr->r_early->status != msr->r->status) {
|
||||
msr->is_relevant += is_response_status_relevant(msr, msr->r_early->status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Figure out if we want to keep the files (if there are any, of course). */
|
||||
if ((msr->txcfg->upload_keep_files == KEEP_FILES_ON)
|
||||
|| ((msr->txcfg->upload_keep_files == KEEP_FILES_RELEVANT_ONLY)&&(msr->is_relevant)))
|
||||
{
|
||||
msr->upload_remove_files = 0;
|
||||
} else {
|
||||
msr->upload_remove_files = 1;
|
||||
}
|
||||
|
||||
/* Are we configured for audit logging? */
|
||||
switch(msr->txcfg->auditlog_flag) {
|
||||
case AUDITLOG_OFF :
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Audit log: Not configured to run for this request.");
|
||||
}
|
||||
|
||||
return DECLINED;
|
||||
break;
|
||||
|
||||
case AUDITLOG_RELEVANT :
|
||||
if (msr->is_relevant == 0) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Audit log: Ignoring a non-relevant request.");
|
||||
}
|
||||
|
||||
return DECLINED;
|
||||
}
|
||||
break;
|
||||
|
||||
case AUDITLOG_ON :
|
||||
/* All right, do nothing */
|
||||
break;
|
||||
|
||||
default :
|
||||
msr_log(msr, 1, "Internal error: Could not determine if auditing is needed, so forcing auditing.");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Invoke the Audit logger */
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Audit log: Logging this transaction.");
|
||||
}
|
||||
|
||||
sec_audit_logger(msr);
|
||||
|
||||
msr->time_logging = apr_time_now() - time_after;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes one transaction phase. The phase number does not
|
||||
* need to be explicitly provided since it's already available
|
||||
* in the modsec_rec structure.
|
||||
*/
|
||||
apr_status_t modsecurity_process_phase(modsec_rec *msr, unsigned int phase) {
|
||||
/* Check if we should run. */
|
||||
if ((msr->was_intercepted)&&(phase != PHASE_LOGGING)) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Skipping phase %d as request was already intercepted.", phase);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not process the same phase twice. */
|
||||
if (msr->phase >= phase) {
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "Skipping phase %d because it was previously run (at %d now).",
|
||||
phase, msr->phase);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
msr->phase = phase;
|
||||
|
||||
/* Clear out the transformation cache at the start of each phase */
|
||||
if (msr->txcfg->cache_trans == MODSEC_CACHE_ENABLED) {
|
||||
if (msr->tcache) {
|
||||
apr_hash_index_t *hi;
|
||||
void *dummy;
|
||||
apr_table_t *tab;
|
||||
const void *key;
|
||||
apr_ssize_t klen;
|
||||
#ifdef CACHE_DEBUG
|
||||
apr_pool_t *mp = msr->msc_rule_mptmp;
|
||||
const apr_array_header_t *ctarr;
|
||||
const apr_table_entry_t *ctelts;
|
||||
msre_cache_rec *rec;
|
||||
int cn = 0;
|
||||
int ri;
|
||||
#else
|
||||
apr_pool_t *mp = msr->mp;
|
||||
#endif
|
||||
|
||||
for (hi = apr_hash_first(mp, msr->tcache); hi; hi = apr_hash_next(hi)) {
|
||||
apr_hash_this(hi, &key, &klen, &dummy);
|
||||
tab = (apr_table_t *)dummy;
|
||||
|
||||
if (tab == NULL) continue;
|
||||
|
||||
#ifdef CACHE_DEBUG
|
||||
/* Dump the cache out as we clear */
|
||||
ctarr = apr_table_elts(tab);
|
||||
ctelts = (const apr_table_entry_t*)ctarr->elts;
|
||||
for (ri = 0; ri < ctarr->nelts; ri++) {
|
||||
cn++;
|
||||
rec = (msre_cache_rec *)ctelts[ri].val;
|
||||
if (rec->changed) {
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=\"%s\" (%pp - %pp)",
|
||||
cn, rec->hits, key, rec->num, rec->path, log_escape_nq_ex(mp, rec->val, rec->val_len),
|
||||
rec->val, rec->val + rec->val_len);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CACHE: %5d) hits=%d key=%pp %x;%s=<no change>",
|
||||
cn, rec->hits, key, rec->num, rec->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
apr_table_clear(tab);
|
||||
apr_hash_set(msr->tcache, key, klen, NULL);
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "Cleared transformation cache for phase %d", msr->phase);
|
||||
}
|
||||
}
|
||||
|
||||
msr->tcache_items = 0;
|
||||
msr->tcache = apr_hash_make(msr->mp);
|
||||
if (msr->tcache == NULL) return -1;
|
||||
}
|
||||
|
||||
switch(phase) {
|
||||
case 1 :
|
||||
return modsecurity_process_phase_request_headers(msr);
|
||||
case 2 :
|
||||
return modsecurity_process_phase_request_body(msr);
|
||||
case 3 :
|
||||
return modsecurity_process_phase_response_headers(msr);
|
||||
case 4 :
|
||||
return modsecurity_process_phase_response_body(msr);
|
||||
case 5 :
|
||||
return modsecurity_process_phase_logging(msr);
|
||||
default :
|
||||
msr_log(msr, 1, "Invalid processing phase: %d", msr->phase);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,737 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MODSECURITY_H_
|
||||
#define _MODSECURITY_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/HTMLparser.h>
|
||||
|
||||
typedef struct rule_exception rule_exception;
|
||||
typedef struct rule_exception hash_method;
|
||||
typedef struct modsec_rec modsec_rec;
|
||||
typedef struct directory_config directory_config;
|
||||
typedef struct error_message_t error_message_t;
|
||||
typedef struct msc_engine msc_engine;
|
||||
typedef struct msc_data_chunk msc_data_chunk;
|
||||
typedef struct msc_arg msc_arg;
|
||||
typedef struct msc_string msc_string;
|
||||
typedef struct msc_parm msc_parm;
|
||||
|
||||
#include "msc_release.h"
|
||||
#include "msc_logging.h"
|
||||
#include "msc_multipart.h"
|
||||
#include "msc_pcre.h"
|
||||
#include "msc_util.h"
|
||||
#include "msc_json.h"
|
||||
#include "msc_xml.h"
|
||||
#include "msc_tree.h"
|
||||
#include "msc_geo.h"
|
||||
#include "msc_gsb.h"
|
||||
#include "msc_unicode.h"
|
||||
#include "re.h"
|
||||
#include "msc_crypt.h"
|
||||
#include "msc_remote_rules.h"
|
||||
|
||||
#include "ap_config.h"
|
||||
#include "apr_md5.h"
|
||||
#include "apr_strings.h"
|
||||
#include "apr_hash.h"
|
||||
#include "httpd.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
#define PHASE_REQUEST_HEADERS 1
|
||||
#define PHASE_REQUEST_BODY 2
|
||||
#define PHASE_RESPONSE_HEADERS 3
|
||||
#define PHASE_RESPONSE_BODY 4
|
||||
#define PHASE_LOGGING 5
|
||||
#define PHASE_FIRST PHASE_REQUEST_HEADERS
|
||||
#define PHASE_LAST PHASE_LOGGING
|
||||
|
||||
#define NOT_SET -1l
|
||||
#define NOT_SET_P ((void *)-1l)
|
||||
|
||||
#define CREATEMODE ( APR_UREAD | APR_UWRITE | APR_GREAD )
|
||||
#define CREATEMODE_DIR ( APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GEXECUTE )
|
||||
|
||||
#if defined(NETWARE)
|
||||
#define CREATEMODE_UNISTD ( S_IREAD | S_IWRITE )
|
||||
#elif defined(WIN32)
|
||||
#define CREATEMODE_UNISTD ( _S_IREAD | _S_IWRITE )
|
||||
#else
|
||||
#define CREATEMODE_UNISTD ( S_IRUSR | S_IWUSR | S_IRGRP )
|
||||
#endif
|
||||
|
||||
#if !defined(O_BINARY)
|
||||
#define O_BINARY (0)
|
||||
#endif
|
||||
|
||||
#ifndef PIPE_BUF
|
||||
#define PIPE_BUF (512)
|
||||
#endif
|
||||
|
||||
#define REQUEST_BODY_HARD_LIMIT 1073741824L
|
||||
#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072
|
||||
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
|
||||
#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576
|
||||
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
|
||||
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
|
||||
|
||||
#define RESPONSE_BODY_LIMIT_ACTION_REJECT 0
|
||||
#define RESPONSE_BODY_LIMIT_ACTION_PARTIAL 1
|
||||
|
||||
#define REQUEST_BODY_FORCEBUF_OFF 0
|
||||
#define REQUEST_BODY_FORCEBUF_ON 1
|
||||
|
||||
#define REQUEST_BODY_LIMIT_ACTION_REJECT 0
|
||||
#define REQUEST_BODY_LIMIT_ACTION_PARTIAL 1
|
||||
|
||||
#define SECACTION_TARGETS "REMOTE_ADDR"
|
||||
#define SECACTION_ARGS "@unconditionalMatch"
|
||||
|
||||
#define SECMARKER_TARGETS "REMOTE_ADDR"
|
||||
#define SECMARKER_ARGS "@noMatch"
|
||||
#define SECMARKER_BASE_ACTIONS "t:none,pass,marker:"
|
||||
|
||||
#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
|
||||
#include "unixd.h"
|
||||
#define __SET_MUTEX_PERMS
|
||||
#endif
|
||||
|
||||
#define COOKIES_V0 0
|
||||
#define COOKIES_V1 1
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define NOTE_MSR "modsecurity-tx-context"
|
||||
|
||||
#define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!"
|
||||
|
||||
extern DSOLOCAL char *new_server_signature;
|
||||
extern DSOLOCAL char *real_server_signature;
|
||||
extern DSOLOCAL char *chroot_dir;
|
||||
|
||||
extern module AP_MODULE_DECLARE_DATA security2_module;
|
||||
|
||||
extern DSOLOCAL const command_rec module_directives[];
|
||||
|
||||
extern DSOLOCAL unsigned long int msc_pcre_match_limit;
|
||||
|
||||
extern DSOLOCAL unsigned long int msc_pcre_match_limit_recursion;
|
||||
|
||||
#ifdef WITH_REMOTE_RULES
|
||||
extern DSOLOCAL msc_remote_rules_server *remote_rules_server;
|
||||
#endif
|
||||
extern DSOLOCAL int remote_rules_fail_action;
|
||||
extern DSOLOCAL char *remote_rules_fail_message;
|
||||
|
||||
extern DSOLOCAL int status_engine_state;
|
||||
|
||||
extern DSOLOCAL int conn_limits_filter_state;
|
||||
|
||||
extern DSOLOCAL unsigned long int conn_read_state_limit;
|
||||
extern DSOLOCAL TreeRoot *conn_read_state_whitelist;
|
||||
extern DSOLOCAL TreeRoot *conn_read_state_suspicious_list;
|
||||
|
||||
extern DSOLOCAL unsigned long int conn_write_state_limit;
|
||||
extern DSOLOCAL TreeRoot *conn_write_state_whitelist;
|
||||
extern DSOLOCAL TreeRoot *conn_write_state_suspicious_list;
|
||||
|
||||
extern DSOLOCAL unsigned long int unicode_codepage;
|
||||
|
||||
extern DSOLOCAL int *unicode_map_table;
|
||||
|
||||
#define RESBODY_STATUS_NOT_READ 0 /* we were not configured to read the body */
|
||||
#define RESBODY_STATUS_ERROR 1 /* error occured while we were reading the body */
|
||||
#define RESBODY_STATUS_PARTIAL 2 /* partial body content available in the brigade */
|
||||
#define RESBODY_STATUS_READ_BRIGADE 3 /* body was read but not flattened */
|
||||
#define RESBODY_STATUS_READ 4 /* body was read and flattened */
|
||||
|
||||
#define IF_STATUS_NONE 0
|
||||
#define IF_STATUS_WANTS_TO_RUN 1
|
||||
#define IF_STATUS_COMPLETE 2
|
||||
|
||||
#define OF_STATUS_NOT_STARTED 0
|
||||
#define OF_STATUS_IN_PROGRESS 1
|
||||
#define OF_STATUS_COMPLETE 2
|
||||
|
||||
#define MSC_REQBODY_NONE 0
|
||||
#define MSC_REQBODY_MEMORY 1
|
||||
#define MSC_REQBODY_DISK 2
|
||||
|
||||
#define ACTION_NONE 0
|
||||
#define ACTION_DENY 1
|
||||
#define ACTION_REDIRECT 2
|
||||
#define ACTION_PROXY 3
|
||||
#define ACTION_DROP 4
|
||||
#define ACTION_ALLOW 5
|
||||
#define ACTION_ALLOW_REQUEST 6
|
||||
#define ACTION_ALLOW_PHASE 7
|
||||
#define ACTION_PAUSE 8
|
||||
|
||||
#define MODSEC_DISABLED 0
|
||||
#define MODSEC_DETECTION_ONLY 1
|
||||
#define MODSEC_ENABLED 2
|
||||
|
||||
#define STATUS_ENGINE_ENABLED 1
|
||||
#define STATUS_ENGINE_DISABLED 0
|
||||
|
||||
#define REMOTE_RULES_ABORT_ON_FAIL 0
|
||||
#define REMOTE_RULES_WARN_ON_FAIL 1
|
||||
|
||||
#define HASH_DISABLED 0
|
||||
#define HASH_ENABLED 1
|
||||
|
||||
#define HASH_URL_HREF_HASH_RX 0
|
||||
#define HASH_URL_HREF_HASH_PM 1
|
||||
#define HASH_URL_FACTION_HASH_RX 2
|
||||
#define HASH_URL_FACTION_HASH_PM 3
|
||||
#define HASH_URL_LOCATION_HASH_RX 4
|
||||
#define HASH_URL_LOCATION_HASH_PM 5
|
||||
#define HASH_URL_IFRAMESRC_HASH_RX 6
|
||||
#define HASH_URL_IFRAMESRC_HASH_PM 7
|
||||
#define HASH_URL_FRAMESRC_HASH_RX 8
|
||||
#define HASH_URL_FRAMESRC_HASH_PM 9
|
||||
|
||||
#define HASH_KEYONLY 0
|
||||
#define HASH_SESSIONID 1
|
||||
#define HASH_REMOTEIP 2
|
||||
|
||||
#define MODSEC_CACHE_DISABLED 0
|
||||
#define MODSEC_CACHE_ENABLED 1
|
||||
|
||||
#define MODSEC_OFFLINE 0
|
||||
#define MODSEC_ONLINE 1
|
||||
|
||||
#define REGEX_CAPTURE_BUFLEN 1024
|
||||
|
||||
#define KEEP_FILES_OFF 0
|
||||
#define KEEP_FILES_ON 1
|
||||
#define KEEP_FILES_RELEVANT_ONLY 2
|
||||
|
||||
#define RULE_EXCEPTION_IMPORT_ID 1
|
||||
#define RULE_EXCEPTION_IMPORT_MSG 2
|
||||
#define RULE_EXCEPTION_REMOVE_ID 3
|
||||
#define RULE_EXCEPTION_REMOVE_MSG 4
|
||||
#define RULE_EXCEPTION_REMOVE_TAG 5
|
||||
|
||||
#define NBSP 160
|
||||
|
||||
struct rule_exception {
|
||||
int type;
|
||||
const char *param;
|
||||
void *param_data;
|
||||
};
|
||||
|
||||
struct modsec_rec {
|
||||
apr_pool_t *mp;
|
||||
msc_engine *modsecurity;
|
||||
|
||||
request_rec *r_early;
|
||||
request_rec *r;
|
||||
directory_config *dcfg1;
|
||||
directory_config *dcfg2;
|
||||
directory_config *usercfg;
|
||||
directory_config *txcfg;
|
||||
|
||||
unsigned int reqbody_should_exist;
|
||||
unsigned int reqbody_chunked;
|
||||
|
||||
unsigned int phase;
|
||||
unsigned int phase_request_headers_complete;
|
||||
unsigned int phase_request_body_complete;
|
||||
|
||||
apr_bucket_brigade *if_brigade;
|
||||
unsigned int if_status;
|
||||
unsigned int if_started_forwarding;
|
||||
|
||||
apr_size_t reqbody_length;
|
||||
|
||||
apr_bucket_brigade *of_brigade;
|
||||
unsigned int of_status;
|
||||
unsigned int of_done_reading;
|
||||
unsigned int of_skipping;
|
||||
unsigned int of_partial;
|
||||
unsigned int of_is_error;
|
||||
|
||||
unsigned int resbody_status;
|
||||
apr_size_t resbody_length;
|
||||
char *resbody_data;
|
||||
unsigned int resbody_contains_html;
|
||||
|
||||
apr_size_t stream_input_length;
|
||||
char *stream_input_data;
|
||||
apr_size_t stream_output_length;
|
||||
char *stream_output_data;
|
||||
unsigned int of_stream_changed;
|
||||
unsigned int if_stream_changed;
|
||||
|
||||
apr_array_header_t *error_messages;
|
||||
apr_array_header_t *alerts;
|
||||
|
||||
const char *txid;
|
||||
const char *sessionid;
|
||||
const char *userid;
|
||||
|
||||
const char *server_software;
|
||||
const char *local_addr;
|
||||
unsigned int local_port;
|
||||
const char *local_user;
|
||||
|
||||
/* client */
|
||||
|
||||
const char *remote_addr;
|
||||
unsigned int remote_port;
|
||||
const char *remote_user;
|
||||
|
||||
/* useragent */
|
||||
const char *useragent_ip;
|
||||
|
||||
/* request */
|
||||
|
||||
const char *request_line;
|
||||
const char *request_method;
|
||||
const char *request_uri;
|
||||
const char *query_string;
|
||||
const char *request_protocol;
|
||||
|
||||
const char *hostname;
|
||||
|
||||
apr_table_t *request_headers;
|
||||
|
||||
apr_off_t request_content_length;
|
||||
const char *request_content_type;
|
||||
|
||||
apr_table_t *arguments;
|
||||
apr_table_t *arguments_to_sanitize;
|
||||
apr_table_t *request_headers_to_sanitize;
|
||||
apr_table_t *response_headers_to_sanitize;
|
||||
apr_table_t *request_cookies;
|
||||
apr_table_t *pattern_to_sanitize;
|
||||
|
||||
unsigned int urlencoded_error;
|
||||
unsigned int inbound_error;
|
||||
unsigned int outbound_error;
|
||||
|
||||
unsigned int is_relevant;
|
||||
|
||||
apr_table_t *tx_vars;
|
||||
|
||||
/* ENH: refactor to allow arbitrary var tables */
|
||||
apr_table_t *geo_vars;
|
||||
|
||||
/* response */
|
||||
unsigned int response_status;
|
||||
const char *status_line;
|
||||
const char *response_protocol;
|
||||
apr_table_t *response_headers;
|
||||
unsigned int response_headers_sent;
|
||||
apr_off_t bytes_sent;
|
||||
|
||||
/* modsecurity request body processing stuff */
|
||||
|
||||
unsigned int msc_reqbody_storage; /* on disk or in memory */
|
||||
unsigned int msc_reqbody_spilltodisk;
|
||||
unsigned int msc_reqbody_read;
|
||||
|
||||
apr_pool_t *msc_reqbody_mp; /* this is where chunks are allocated from */
|
||||
apr_array_header_t *msc_reqbody_chunks; /* data chunks when stored in memory */
|
||||
unsigned int msc_reqbody_length; /* the amount of data received */
|
||||
int msc_reqbody_chunk_position; /* used when retrieving the body */
|
||||
unsigned int msc_reqbody_chunk_offset; /* offset of the chunk currently in use */
|
||||
msc_data_chunk *msc_reqbody_chunk_current; /* current chunk */
|
||||
char *msc_reqbody_buffer;
|
||||
|
||||
const char *msc_reqbody_filename; /* when stored on disk */
|
||||
int msc_reqbody_fd;
|
||||
msc_data_chunk *msc_reqbody_disk_chunk;
|
||||
|
||||
const char *msc_reqbody_processor;
|
||||
int msc_reqbody_error;
|
||||
const char *msc_reqbody_error_msg;
|
||||
|
||||
apr_size_t msc_reqbody_no_files_length;
|
||||
|
||||
char *msc_full_request_buffer;
|
||||
int msc_full_request_length;
|
||||
|
||||
char *multipart_filename;
|
||||
char *multipart_name;
|
||||
multipart_data *mpd; /* MULTIPART processor data structure */
|
||||
|
||||
xml_data *xml; /* XML processor data structure */
|
||||
#ifdef WITH_YAJL
|
||||
json_data *json; /* JSON processor data structure */
|
||||
#endif
|
||||
|
||||
/* audit logging */
|
||||
char *new_auditlog_boundary;
|
||||
char *new_auditlog_filename;
|
||||
apr_file_t *new_auditlog_fd;
|
||||
unsigned int new_auditlog_size;
|
||||
apr_md5_ctx_t new_auditlog_md5ctx;
|
||||
|
||||
unsigned int was_intercepted;
|
||||
unsigned int rule_was_intercepted;
|
||||
unsigned int intercept_phase;
|
||||
msre_actionset *intercept_actionset;
|
||||
const char *intercept_message;
|
||||
|
||||
/* performance measurement */
|
||||
apr_time_t request_time;
|
||||
apr_time_t time_phase1;
|
||||
apr_time_t time_phase2;
|
||||
apr_time_t time_phase3;
|
||||
apr_time_t time_phase4;
|
||||
apr_time_t time_phase5;
|
||||
apr_time_t time_storage_read;
|
||||
apr_time_t time_storage_write;
|
||||
apr_time_t time_logging;
|
||||
apr_time_t time_gc;
|
||||
apr_table_t *perf_rules;
|
||||
|
||||
apr_array_header_t *matched_rules;
|
||||
msc_string *matched_var;
|
||||
int highest_severity;
|
||||
|
||||
/* upload */
|
||||
int upload_extract_files;
|
||||
int upload_remove_files;
|
||||
int upload_files_count;
|
||||
|
||||
/* other */
|
||||
apr_table_t *collections_original;
|
||||
apr_table_t *collections;
|
||||
apr_table_t *collections_dirty;
|
||||
|
||||
/* rule processing temp pool */
|
||||
apr_pool_t *msc_rule_mptmp;
|
||||
|
||||
/* content injection */
|
||||
const char *content_prepend;
|
||||
apr_off_t content_prepend_len;
|
||||
const char *content_append;
|
||||
apr_off_t content_append_len;
|
||||
|
||||
/* data cache */
|
||||
apr_hash_t *tcache;
|
||||
apr_size_t tcache_items;
|
||||
|
||||
/* removed rules */
|
||||
apr_array_header_t *removed_rules;
|
||||
apr_array_header_t *removed_rules_tag;
|
||||
apr_array_header_t *removed_rules_msg;
|
||||
|
||||
/* removed targets */
|
||||
apr_table_t *removed_targets;
|
||||
|
||||
/* When "allow" is executed the variable below is
|
||||
* updated to contain the scope of the allow action. Set
|
||||
* at 0 by default, it will have ACTION_ALLOW if we are
|
||||
* to allow phases 1-4 and ACTION_ALLOW_REQUEST if we
|
||||
* are to allow phases 1-2 only.
|
||||
*/
|
||||
unsigned int allow_scope;
|
||||
|
||||
/* matched vars */
|
||||
apr_table_t *matched_vars;
|
||||
|
||||
/* Generic request body processor context to be used by custom parsers. */
|
||||
void *reqbody_processor_ctx;
|
||||
|
||||
htmlDocPtr crypto_html_tree;
|
||||
#if defined(WITH_LUA)
|
||||
#ifdef CACHE_LUA
|
||||
lua_State *L;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int msc_sdbm_delete_error;
|
||||
};
|
||||
|
||||
struct directory_config {
|
||||
apr_pool_t *mp;
|
||||
|
||||
msre_ruleset *ruleset;
|
||||
|
||||
int is_enabled;
|
||||
int reqbody_access;
|
||||
int reqintercept_oe;
|
||||
int reqbody_buffering;
|
||||
long int reqbody_inmemory_limit;
|
||||
long int reqbody_limit;
|
||||
long int reqbody_no_files_limit;
|
||||
int resbody_access;
|
||||
|
||||
long int of_limit;
|
||||
apr_table_t *of_mime_types;
|
||||
int of_mime_types_cleared;
|
||||
int of_limit_action;
|
||||
int if_limit_action;
|
||||
|
||||
const char *debuglog_name;
|
||||
int debuglog_level;
|
||||
apr_file_t *debuglog_fd;
|
||||
|
||||
int cookie_format;
|
||||
int argument_separator;
|
||||
const char *cookiev0_separator;
|
||||
|
||||
int rule_inheritance;
|
||||
apr_array_header_t *rule_exceptions;
|
||||
|
||||
|
||||
/* -- Audit log -- */
|
||||
|
||||
/* Max rule time */
|
||||
int max_rule_time;
|
||||
|
||||
/* Whether audit log should be enabled in the context or not */
|
||||
int auditlog_flag;
|
||||
|
||||
/* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */
|
||||
int auditlog_type;
|
||||
|
||||
/* Mode for audit log directories and files */
|
||||
apr_fileperms_t auditlog_dirperms;
|
||||
apr_fileperms_t auditlog_fileperms;
|
||||
|
||||
/* The name of the audit log file (for the old type), or the
|
||||
* name of the index file (for the new audit log type)
|
||||
*/
|
||||
char *auditlog_name;
|
||||
/* The name of the secondary index file */
|
||||
char *auditlog2_name;
|
||||
|
||||
/* The file descriptors for the files above */
|
||||
apr_file_t *auditlog_fd;
|
||||
apr_file_t *auditlog2_fd;
|
||||
|
||||
/* For the new-style audit log only, the path where
|
||||
* audit log entries will be stored
|
||||
*/
|
||||
char *auditlog_storage_dir;
|
||||
|
||||
/* A list of parts to include in the new-style audit log
|
||||
* entry. By default, it contains 'ABCFHZ'. Have a look at
|
||||
* the AUDITLOG_PART_* constants above to decipher the
|
||||
* meaning.
|
||||
*/
|
||||
char *auditlog_parts;
|
||||
|
||||
/* A regular expression that determines if a response
|
||||
* status is treated as relevant.
|
||||
*/
|
||||
msc_regex_t *auditlog_relevant_regex;
|
||||
|
||||
/* Upload */
|
||||
const char *tmp_dir;
|
||||
const char *upload_dir;
|
||||
int upload_keep_files;
|
||||
int upload_validates_files;
|
||||
int upload_filemode; /* int only so NOT_SET works */
|
||||
int upload_file_limit;
|
||||
|
||||
/* Used only in the configuration phase. */
|
||||
msre_rule *tmp_chain_starter;
|
||||
msre_actionset *tmp_default_actionset;
|
||||
apr_table_t *tmp_rule_placeholders;
|
||||
|
||||
/* Misc */
|
||||
const char *data_dir;
|
||||
const char *webappid;
|
||||
const char *sensor_id;
|
||||
const char *httpBlkey;
|
||||
|
||||
/* Content injection. */
|
||||
int content_injection_enabled;
|
||||
|
||||
/* Stream Inspection */
|
||||
int stream_inbody_inspection;
|
||||
int stream_outbody_inspection;
|
||||
|
||||
/* Geo Lookup */
|
||||
geo_db *geo;
|
||||
|
||||
/* Gsb Lookup */
|
||||
gsb_db *gsb;
|
||||
|
||||
/* Unicode map */
|
||||
unicode_map *u_map;
|
||||
|
||||
/* Cache */
|
||||
int cache_trans;
|
||||
int cache_trans_incremental;
|
||||
apr_size_t cache_trans_min;
|
||||
apr_size_t cache_trans_max;
|
||||
apr_size_t cache_trans_maxitems;
|
||||
|
||||
/* Array to hold signatures of components, which will
|
||||
* appear in the ModSecurity signature in the audit log.
|
||||
*/
|
||||
apr_array_header_t *component_signatures;
|
||||
|
||||
/* Request character encoding. */
|
||||
const char *request_encoding;
|
||||
|
||||
int disable_backend_compression;
|
||||
|
||||
/* Collection timeout */
|
||||
int col_timeout;
|
||||
|
||||
/* hash of ids */
|
||||
apr_hash_t *rule_id_htab;
|
||||
|
||||
/* Hash */
|
||||
apr_array_header_t *hash_method;
|
||||
const char *crypto_key;
|
||||
int crypto_key_len;
|
||||
const char *crypto_param_name;
|
||||
int hash_is_enabled;
|
||||
int hash_enforcement;
|
||||
int crypto_key_add;
|
||||
int crypto_hash_href_rx;
|
||||
int crypto_hash_faction_rx;
|
||||
int crypto_hash_location_rx;
|
||||
int crypto_hash_iframesrc_rx;
|
||||
int crypto_hash_framesrc_rx;
|
||||
int crypto_hash_href_pm;
|
||||
int crypto_hash_faction_pm;
|
||||
int crypto_hash_location_pm;
|
||||
int crypto_hash_iframesrc_pm;
|
||||
int crypto_hash_framesrc_pm;
|
||||
|
||||
/* xml */
|
||||
int xml_external_entity;
|
||||
|
||||
/* This will be used whenever ModSecurity will be ready
|
||||
* to ask the server for newer rules.
|
||||
*/
|
||||
#if 0
|
||||
msc_remote_rules_server *remote_rules;
|
||||
int remote_timeout;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct error_message_t {
|
||||
const char *file;
|
||||
int line;
|
||||
int level;
|
||||
apr_status_t status;
|
||||
const char *message;
|
||||
};
|
||||
|
||||
struct msc_engine {
|
||||
apr_pool_t *mp;
|
||||
apr_global_mutex_t *auditlog_lock;
|
||||
apr_global_mutex_t *geo_lock;
|
||||
msre_engine *msre;
|
||||
unsigned int processing_mode;
|
||||
};
|
||||
|
||||
struct msc_data_chunk {
|
||||
char *data;
|
||||
apr_size_t length;
|
||||
unsigned int is_permanent;
|
||||
};
|
||||
|
||||
struct msc_arg {
|
||||
const char *name;
|
||||
unsigned int name_len;
|
||||
unsigned int name_origin_offset;
|
||||
unsigned int name_origin_len;
|
||||
const char *value;
|
||||
unsigned int value_len;
|
||||
unsigned int value_origin_offset;
|
||||
unsigned int value_origin_len;
|
||||
const char *origin;
|
||||
};
|
||||
|
||||
struct msc_string {
|
||||
char *name;
|
||||
unsigned int name_len;
|
||||
char *value;
|
||||
unsigned int value_len;
|
||||
};
|
||||
|
||||
struct msc_parm {
|
||||
char *value;
|
||||
int pad_1;
|
||||
int pad_2;
|
||||
};
|
||||
|
||||
/* Engine functions */
|
||||
|
||||
msc_engine DSOLOCAL *modsecurity_create(apr_pool_t *mp, int processing_mode);
|
||||
|
||||
int DSOLOCAL modsecurity_init(msc_engine *msce, apr_pool_t *mp);
|
||||
|
||||
void DSOLOCAL modsecurity_child_init(msc_engine *msce);
|
||||
|
||||
void DSOLOCAL modsecurity_shutdown(msc_engine *msce);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_tx_init(modsec_rec *msr);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_process_phase(modsec_rec *msr, unsigned int phase);
|
||||
|
||||
|
||||
/* Request body functions */
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_start(modsec_rec *msr, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_store(modsec_rec *msr,
|
||||
const char *data, apr_size_t length, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_end(modsec_rec *msr, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_end(modsec_rec *msr);
|
||||
|
||||
/* Retrieves up to nbytes bytes of the request body. Returns 1 on
|
||||
* success, 0 when there is no more data, or -1 on error. On return
|
||||
* nbytes will contain the number of bytes stored in the buffer.
|
||||
*/
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk,
|
||||
long int nbytes, char **error_msg);
|
||||
|
||||
void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset,
|
||||
const char *action_message, const char *rule_message);
|
||||
|
||||
const char DSOLOCAL *msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message,
|
||||
const char *rule_message);
|
||||
|
||||
void DSOLOCAL msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
|
||||
const char *rule_message);
|
||||
|
||||
apr_status_t DSOLOCAL modsecurity_request_body_clear(modsec_rec *msr, char **error_msg);
|
||||
|
||||
#endif
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Some APR files define PACKAGE* constants, which may conflict
|
||||
* so this is here to prevent that by removing them.
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
/* Undefine all these so there are no conflicts */
|
||||
#undef PACKAGE
|
||||
#undef PACKAGE_BUGREPORT
|
||||
#undef PACKAGE_NAME
|
||||
#undef PACKAGE_STRING
|
||||
#undef PACKAGE_TARNAME
|
||||
#undef PACKAGE_URL
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Include the real autoconf header */
|
||||
#include "modsecurity_config_auto.h"
|
||||
|
||||
/* Undefine all these (again) so there are no conflicts */
|
||||
#undef PACKAGE
|
||||
#undef PACKAGE_BUGREPORT
|
||||
#undef PACKAGE_NAME
|
||||
#undef PACKAGE_STRING
|
||||
#undef PACKAGE_TARNAME
|
||||
#undef PACKAGE_URL
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
|
||||
re re_operators re_actions re_tfns re_variables msc_json \
|
||||
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
|
||||
persist_dbm msc_reqbody pdf_protect msc_geo msc_gsb msc_crypt msc_tree msc_unicode acmp msc_lua
|
||||
|
||||
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h msc_json.h \
|
||||
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
|
||||
msc_geo.h msc_gsb.h msc_crypt.h msc_tree.h msc_unicode.h acmp.h utf8tables.h msc_lua.h
|
||||
|
||||
${MOD_SECURITY2:=.slo}: ${H}
|
||||
${MOD_SECURITY2:=.lo}: ${H}
|
||||
${MOD_SECURITY2:=.o}: ${H}
|
||||
|
||||
mod_security2.la: ${MOD_SECURITY2:=.slo}
|
||||
$(SH_LINK) -rpath $(libexecdir) -module -avoid-version ${MOD_SECURITY2:=.lo}
|
||||
|
||||
DISTCLEAN_TARGETS = modules.mk
|
||||
|
||||
shared = mod_security2.la
|
||||
1505
apache2/msc_crypt.c
1505
apache2/msc_crypt.c
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_CRYPT_H_
|
||||
#define _MSC_CRYPT_H_
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include <libxml/HTMLparser.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
#define HMAC_PAD_SIZE 65
|
||||
#define HASH_ONLY 0
|
||||
#define FULL_LINK 1
|
||||
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#endif
|
||||
|
||||
char DSOLOCAL *hmac(modsec_rec *msr, const char *key, int key_len,
|
||||
unsigned char *msg, int msglen);
|
||||
char DSOLOCAL *do_hash_link(modsec_rec *msr, char *link,
|
||||
int type);
|
||||
char DSOLOCAL *getkey(apr_pool_t *mp);
|
||||
|
||||
int DSOLOCAL init_response_body_html_parser(modsec_rec *msr);
|
||||
int DSOLOCAL hash_response_body_links(modsec_rec *msr);
|
||||
int DSOLOCAL inject_hashed_response_body(modsec_rec *msr, int elts);
|
||||
int DSOLOCAL do_hash_method(modsec_rec *msr, char *link, int type);
|
||||
int DSOLOCAL modify_response_header(modsec_rec *msr);
|
||||
char DSOLOCAL *normalize_path(modsec_rec *msr, char *input);
|
||||
#endif
|
||||
@@ -1,506 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_geo.h"
|
||||
|
||||
|
||||
/* -- Lookup Tables -- */
|
||||
|
||||
static const char geo_country_code[GEO_COUNTRY_LAST + 1][4] = {
|
||||
"--",
|
||||
"AP","EU","AD","AE","AF","AG","AI","AL","AM","AN",
|
||||
"AO","AQ","AR","AS","AT","AU","AW","AZ","BA","BB",
|
||||
"BD","BE","BF","BG","BH","BI","BJ","BM","BN","BO",
|
||||
"BR","BS","BT","BV","BW","BY","BZ","CA","CC","CD",
|
||||
"CF","CG","CH","CI","CK","CL","CM","CN","CO","CR",
|
||||
"CU","CV","CX","CY","CZ","DE","DJ","DK","DM","DO",
|
||||
"DZ","EC","EE","EG","EH","ER","ES","ET","FI","FJ",
|
||||
"FK","FM","FO","FR","FX","GA","GB","GD","GE","GF",
|
||||
"GH","GI","GL","GM","GN","GP","GQ","GR","GS","GT",
|
||||
"GU","GW","GY","HK","HM","HN","HR","HT","HU","ID",
|
||||
"IE","IL","IN","IO","IQ","IR","IS","IT","JM","JO",
|
||||
"JP","KE","KG","KH","KI","KM","KN","KP","KR","KW",
|
||||
"KY","KZ","LA","LB","LC","LI","LK","LR","LS","LT",
|
||||
"LU","LV","LY","MA","MC","MD","MG","MH","MK","ML",
|
||||
"MM","MN","MO","MP","MQ","MR","MS","MT","MU","MV",
|
||||
"MW","MX","MY","MZ","NA","NC","NE","NF","NG","NI",
|
||||
"NL","NO","NP","NR","NU","NZ","OM","PA","PE","PF",
|
||||
"PG","PH","PK","PL","PM","PN","PR","PS","PT","PW",
|
||||
"PY","QA","RE","RO","RU","RW","SA","SB","SC","SD",
|
||||
"SE","SG","SH","SI","SJ","SK","SL","SM","SN","SO",
|
||||
"SR","ST","SV","SY","SZ","TC","TD","TF","TG","TH",
|
||||
"TJ","TK","TM","TN","TO","TL","TR","TT","TV","TW",
|
||||
"TZ","UA","UG","UM","US","UY","UZ","VA","VC","VE",
|
||||
"VG","VI","VN","VU","WF","WS","YE","YT","RS","ZA",
|
||||
"ZM","ME","ZW","A1","A2","O1","AX","GG","IM","JE"
|
||||
};
|
||||
|
||||
static const char geo_country_code3[GEO_COUNTRY_LAST + 1][4] = {
|
||||
"--",
|
||||
"AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT",
|
||||
"AGO","AQ","ARG","ASM","AUT","AUS","ABW","AZE","BIH","BRB",
|
||||
"BGD","BEL","BFA","BGR","BHR","BDI","BEN","BMU","BRN","BOL",
|
||||
"BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC","COD",
|
||||
"CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI",
|
||||
"CUB","CPV","CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM",
|
||||
"DZA","ECU","EST","EGY","ESH","ERI","ESP","ETH","FIN","FJI",
|
||||
"FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD","GEO","GUF",
|
||||
"GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM",
|
||||
"GUM","GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN",
|
||||
"IRL","ISR","IND","IO","IRQ","IRN","ISL","ITA","JAM","JOR",
|
||||
"JPN","KEN","KGZ","KHM","KIR","COM","KNA","PRK","KOR","KWT",
|
||||
"CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
|
||||
"LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI",
|
||||
"MMR","MNG","MAC","MNP","MTQ","MRT","MSR","MLT","MUS","MDV",
|
||||
"MWI","MEX","MYS","MOZ","NAM","NCL","NER","NFK","NGA","NIC",
|
||||
"NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER","PYF",
|
||||
"PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW",
|
||||
"PRY","QAT","REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN",
|
||||
"SWE","SGP","SHN","SVN","SJM","SVK","SLE","SMR","SEN","SOM",
|
||||
"SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF","TGO","THA",
|
||||
"TJK","TKL","TKM","TUN","TON","TLS","TUR","TTO","TUV","TWN",
|
||||
"TZA","UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN",
|
||||
"VGB","VIR","VNM","VUT","WLF","WSM","YEM","YT","SRB","ZAF",
|
||||
"ZMB","MNE","ZWE","A1","A2","O1","ALA","GGY","IMN","JEY"
|
||||
};
|
||||
|
||||
static const char *const geo_country_name[GEO_COUNTRY_LAST + 1] = {
|
||||
"N/A",
|
||||
"Asia/Pacific Region","Europe","Andorra","United Arab Emirates","Afghanistan","Antigua and Barbuda","Anguilla","Albania","Armenia","Netherlands Antilles",
|
||||
"Angola","Antarctica","Argentina","American Samoa","Austria","Australia","Aruba","Azerbaijan","Bosnia and Herzegovina","Barbados",
|
||||
"Bangladesh","Belgium","Burkina Faso","Bulgaria","Bahrain","Burundi","Benin","Bermuda","Brunei Darussalam","Bolivia",
|
||||
"Brazil","Bahamas","Bhutan","Bouvet Island","Botswana","Belarus","Belize","Canada","Cocos (Keeling) Islands","Congo, The Democratic Republic of the",
|
||||
"Central African Republic","Congo","Switzerland","Cote D'Ivoire","Cook Islands","Chile","Cameroon","China","Colombia","Costa Rica",
|
||||
"Cuba","Cape Verde","Christmas Island","Cyprus","Czech Republic","Germany","Djibouti","Denmark","Dominica","Dominican Republic",
|
||||
"Algeria","Ecuador","Estonia","Egypt","Western Sahara","Eritrea","Spain","Ethiopia","Finland","Fiji",
|
||||
"Falkland Islands (Malvinas)","Micronesia, Federated States of","Faroe Islands","France","France, Metropolitan","Gabon","United Kingdom","Grenada","Georgia","French Guiana",
|
||||
"Ghana","Gibraltar","Greenland","Gambia","Guinea","Guadeloupe","Equatorial Guinea","Greece","South Georgia and the South Sandwich Islands","Guatemala",
|
||||
"Guam","Guinea-Bissau","Guyana","Hong Kong","Heard Island and McDonald Islands","Honduras","Croatia","Haiti","Hungary","Indonesia",
|
||||
"Ireland","Israel","India","British Indian Ocean Territory","Iraq","Iran, Islamic Republic of","Iceland","Italy","Jamaica","Jordan",
|
||||
"Japan","Kenya","Kyrgyzstan","Cambodia","Kiribati","Comoros","Saint Kitts and Nevis","Korea, Democratic People's Republic of","Korea, Republic of","Kuwait",
|
||||
"Cayman Islands","Kazakhstan","Lao People's Democratic Republic","Lebanon","Saint Lucia","Liechtenstein","Sri Lanka","Liberia","Lesotho","Lithuania",
|
||||
"Luxembourg","Latvia","Libyan Arab Jamahiriya","Morocco","Monaco","Moldova, Republic of","Madagascar","Marshall Islands","Macedonia","Mali",
|
||||
"Myanmar","Mongolia","Macau","Northern Mariana Islands","Martinique","Mauritania","Montserrat","Malta","Mauritius","Maldives",
|
||||
"Malawi","Mexico","Malaysia","Mozambique","Namibia","New Caledonia","Niger","Norfolk Island","Nigeria","Nicaragua",
|
||||
"Netherlands","Norway","Nepal","Nauru","Niue","New Zealand","Oman","Panama","Peru","French Polynesia",
|
||||
"Papua New Guinea","Philippines","Pakistan","Poland","Saint Pierre and Miquelon","Pitcairn Islands","Puerto Rico","Palestinian Territory","Portugal","Palau",
|
||||
"Paraguay","Qatar","Reunion","Romania","Russian Federation","Rwanda","Saudi Arabia","Solomon Islands","Seychelles","Sudan",
|
||||
"Sweden","Singapore","Saint Helena","Slovenia","Svalbard and Jan Mayen","Slovakia","Sierra Leone","San Marino","Senegal","Somalia","Suriname",
|
||||
"Sao Tome and Principe","El Salvador","Syrian Arab Republic","Swaziland","Turks and Caicos Islands","Chad","French Southern Territories","Togo","Thailand",
|
||||
"Tajikistan","Tokelau","Turkmenistan","Tunisia","Tonga","Timor-Leste","Turkey","Trinidad and Tobago","Tuvalu","Taiwan",
|
||||
"Tanzania, United Republic of","Ukraine","Uganda","United States Minor Outlying Islands","United States","Uruguay","Uzbekistan","Holy See (Vatican City State)","Saint Vincent and the Grenadines","Venezuela",
|
||||
"Virgin Islands, British","Virgin Islands, U.S.","Vietnam","Vanuatu","Wallis and Futuna","Samoa","Yemen","Mayotte","Serbia","South Africa",
|
||||
"Zambia","Montenegro","Zimbabwe","Anonymous Proxy","Satellite Provider","Other","Aland Islands","Guernsey","Isle of Man","Jersey"
|
||||
};
|
||||
|
||||
static const char geo_country_continent[GEO_COUNTRY_LAST + 1][4] = {
|
||||
"--",
|
||||
"AS","EU","EU","AS","AS","SA","SA","EU","AS","SA",
|
||||
"AF","AN","SA","OC","EU","OC","SA","AS","EU","SA",
|
||||
"AS","EU","AF","EU","AS","AF","AF","SA","AS","SA",
|
||||
"SA","SA","AS","AF","AF","EU","SA","NA","AS","AF",
|
||||
"AF","AF","EU","AF","OC","SA","AF","AS","SA","SA",
|
||||
"SA","AF","AS","AS","EU","EU","AF","EU","SA","SA",
|
||||
"AF","SA","EU","AF","AF","AF","EU","AF","EU","OC",
|
||||
"SA","OC","EU","EU","EU","AF","EU","SA","AS","SA",
|
||||
"AF","EU","SA","AF","AF","SA","AF","EU","SA","SA",
|
||||
"OC","AF","SA","AS","AF","SA","EU","SA","EU","AS",
|
||||
"EU","AS","AS","AS","AS","AS","EU","EU","SA","AS",
|
||||
"AS","AF","AS","AS","OC","AF","SA","AS","AS","AS",
|
||||
"SA","AS","AS","AS","SA","EU","AS","AF","AF","EU",
|
||||
"EU","EU","AF","AF","EU","EU","AF","OC","EU","AF",
|
||||
"AS","AS","AS","OC","SA","AF","SA","EU","AF","AS",
|
||||
"AF","NA","AS","AF","AF","OC","AF","OC","AF","SA",
|
||||
"EU","EU","AS","OC","OC","OC","AS","SA","SA","OC",
|
||||
"OC","AS","AS","EU","SA","OC","SA","AS","EU","OC",
|
||||
"SA","AS","AF","EU","AS","AF","AS","OC","AF","AF",
|
||||
"EU","AS","AF","EU","EU","EU","AF","EU","AF","AF",
|
||||
"SA","AF","SA","AS","AF","SA","AF","AF","AF","AS",
|
||||
"AS","OC","AS","AF","OC","AS","AS","SA","OC","AS",
|
||||
"AF","EU","AF","OC","NA","SA","AS","EU","SA","SA",
|
||||
"SA","SA","AS","OC","OC","OC","AS","AF","EU","AF",
|
||||
"AF","EU","AF","--","--","--","EU","EU","EU","EU"
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
GEOIP_COUNTRY_EDITION = 1,
|
||||
GEOIP_REGION_EDITION_REV0 = 7,
|
||||
GEOIP_CITY_EDITION_REV0 = 6,
|
||||
GEOIP_ORG_EDITION = 5,
|
||||
GEOIP_ISP_EDITION = 4,
|
||||
GEOIP_CITY_EDITION_REV1 = 2,
|
||||
GEOIP_REGION_EDITION_REV1 = 3,
|
||||
GEOIP_PROXY_EDITION = 8,
|
||||
GEOIP_ASNUM_EDITION = 9,
|
||||
GEOIP_NETSPEED_EDITION = 10,
|
||||
GEOIP_DOMAIN_EDITION = 11
|
||||
} GeoIPDBTypes;
|
||||
|
||||
static void create_segments(geo_db *geo) {
|
||||
int i, j;
|
||||
unsigned char delim[3];
|
||||
unsigned char buf[GEO_SEGMENT_RECORD_LENGTH];
|
||||
apr_size_t nbytes;
|
||||
apr_off_t offset;
|
||||
|
||||
geo->ctry_offset = 0;
|
||||
|
||||
geo->dbtype = GEOIP_COUNTRY_EDITION;
|
||||
offset = -3l;
|
||||
apr_file_seek(geo->db, APR_END, &offset);
|
||||
|
||||
for (i = 0; i < GEO_STRUCT_INFO_MAX_SIZE; i++) {
|
||||
|
||||
apr_file_read_full(geo->db, &delim, 3, &nbytes);
|
||||
|
||||
if (delim[0] == 255 && delim[1] == 255 && delim[2] == 255) {
|
||||
apr_file_read_full(geo->db, &geo->dbtype, 1, &nbytes);
|
||||
if (geo->dbtype >= 106) {
|
||||
geo->dbtype -= 105;
|
||||
}
|
||||
|
||||
if (geo->dbtype == GEOIP_REGION_EDITION_REV0) {
|
||||
geo->ctry_offset = GEO_STATE_BEGIN_REV0;
|
||||
} else if (geo->dbtype == GEOIP_REGION_EDITION_REV1) {
|
||||
geo->ctry_offset = GEO_STATE_BEGIN_REV1;
|
||||
} else if (geo->dbtype == GEOIP_CITY_EDITION_REV0 ||
|
||||
geo->dbtype == GEOIP_CITY_EDITION_REV1 ||
|
||||
geo->dbtype == GEOIP_ORG_EDITION ||
|
||||
geo->dbtype == GEOIP_ISP_EDITION ||
|
||||
geo->dbtype == GEOIP_ASNUM_EDITION) {
|
||||
geo->ctry_offset = 0;
|
||||
apr_file_read_full(geo->db, &buf, GEO_SEGMENT_RECORD_LENGTH, &nbytes);
|
||||
for (j = 0; j < GEO_SEGMENT_RECORD_LENGTH; j++) {
|
||||
geo->ctry_offset += (buf[j] << (j * 8));
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
offset = -4l;
|
||||
apr_file_seek(geo->db, APR_CUR, &offset);
|
||||
}
|
||||
}
|
||||
if (geo->dbtype == GEOIP_COUNTRY_EDITION ||
|
||||
geo->dbtype == GEOIP_PROXY_EDITION ||
|
||||
geo->dbtype == GEOIP_NETSPEED_EDITION) {
|
||||
geo->ctry_offset = GEO_COUNTRY_BEGIN;
|
||||
}
|
||||
}
|
||||
|
||||
static int db_open(directory_config *dcfg, char **error_msg)
|
||||
{
|
||||
char errstr[1024];
|
||||
apr_pool_t *mp = dcfg->mp;
|
||||
geo_db *geo = dcfg->geo;
|
||||
apr_status_t rc;
|
||||
|
||||
#ifdef DEBUG_CONF
|
||||
fprintf(stderr, "GEO: Initializing geo DB \"%s\".\n", geo->dbfn);
|
||||
#endif
|
||||
|
||||
if ((rc = apr_file_open(&geo->db, geo->dbfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not open geo database \"%s\": %s", geo->dbfn, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
create_segments(geo);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int field_length(const char *field, int maxlen)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (field == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < maxlen; i++) {
|
||||
if (field[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Geo data structure
|
||||
*/
|
||||
int geo_init(directory_config *dcfg, const char *dbfn, char **error_msg)
|
||||
{
|
||||
*error_msg = NULL;
|
||||
|
||||
if ((dcfg->geo == NULL) || (dcfg->geo == NOT_SET_P)) {
|
||||
dcfg->geo = apr_pcalloc(dcfg->mp, sizeof(geo_db));
|
||||
}
|
||||
|
||||
dcfg->geo->db = NULL;
|
||||
dcfg->geo->dbfn = apr_pstrdup(dcfg->mp, dbfn);
|
||||
dcfg->geo->dbtype = 0;
|
||||
dcfg->geo->ctry_offset = 0;
|
||||
|
||||
return db_open(dcfg, error_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform geographical lookup on target.
|
||||
*/
|
||||
int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **error_msg)
|
||||
{
|
||||
apr_sockaddr_t *addr;
|
||||
long ipnum = 0;
|
||||
char *targetip = NULL;
|
||||
geo_db *geo = msr->txcfg->geo;
|
||||
char errstr[1024];
|
||||
unsigned char buf[2* GEO_MAX_RECORD_LEN];
|
||||
const int reclen = 3; /* Algorithm needs changed if this changes */
|
||||
apr_size_t nbytes;
|
||||
unsigned int rec_val = 0;
|
||||
apr_off_t seekto = 0;
|
||||
apr_status_t ret;
|
||||
int rc;
|
||||
int country = 0;
|
||||
int level;
|
||||
double dtmp;
|
||||
int itmp;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
/* init */
|
||||
georec->country_code = geo_country_code[0];
|
||||
georec->country_code3 = geo_country_code3[0];
|
||||
georec->country_name = geo_country_name[0];
|
||||
georec->country_continent = geo_country_continent[0];
|
||||
georec->region = "";
|
||||
georec->city = "";
|
||||
georec->postal_code = "";
|
||||
georec->latitude = 0;
|
||||
georec->longitude = 0;
|
||||
georec->dma_code = 0;
|
||||
georec->area_code = 0;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: Looking up \"%s\".", log_escape(msr->mp, target));
|
||||
}
|
||||
|
||||
/* NOTE: This only works with ipv4 */
|
||||
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
return 0;
|
||||
}
|
||||
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* Why is this in host byte order? */
|
||||
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx). %lu", targetip, ipnum, ipnum);
|
||||
}
|
||||
|
||||
ret = apr_global_mutex_lock(msr->modsecurity->geo_lock);
|
||||
if (ret != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
||||
get_apr_error(msr->mp, ret));
|
||||
}
|
||||
|
||||
for (level = 31; level >= 0; level--) {
|
||||
/* Read the record */
|
||||
seekto = 2 * reclen * rec_val;
|
||||
apr_file_seek(geo->db, APR_SET, &seekto);
|
||||
/* TODO: check rc */
|
||||
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
|
||||
|
||||
/* NOTE: This is hard-coded for size 3 records */
|
||||
/* Left */
|
||||
if ((ipnum & (1 << level)) == 0) {
|
||||
rec_val = (buf[3*0 + 0] << (0*8)) +
|
||||
(buf[3*0 + 1] << (1*8)) +
|
||||
(buf[3*0 + 2] << (2*8));
|
||||
}
|
||||
/* Right */
|
||||
else {
|
||||
rec_val = (buf[3*1 + 0] << (0*8)) +
|
||||
(buf[3*1 + 1] << (1*8)) +
|
||||
(buf[3*1 + 2] << (2*8));
|
||||
}
|
||||
|
||||
/* If we are past the country offset, then we are done */
|
||||
if (rec_val >= geo->ctry_offset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rec_val == geo->ctry_offset) {
|
||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\").", log_escape(msr->mp, target));
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
|
||||
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
||||
if (ret != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
||||
get_apr_error(msr->mp, ret));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (geo->dbtype == GEO_COUNTRY_DATABASE) {
|
||||
country = rec_val;
|
||||
country -= geo->ctry_offset;
|
||||
if ((country <= 0) || (country > GEO_COUNTRY_LAST)) {
|
||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country);
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
|
||||
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
||||
if (ret != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
||||
get_apr_error(msr->mp, ret));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Country */
|
||||
georec->country_code = geo_country_code[country];
|
||||
georec->country_code3 = geo_country_code3[country];
|
||||
georec->country_name = geo_country_name[country];
|
||||
georec->country_continent = geo_country_continent[country];
|
||||
}
|
||||
else {
|
||||
int field_len = 0;
|
||||
int rec_offset = 0;
|
||||
int remaining = GEO_CITY_RECORD_LEN;
|
||||
unsigned char cbuf[GEO_CITY_RECORD_LEN];
|
||||
|
||||
seekto = rec_val + (2 * reclen - 1) * geo->ctry_offset;
|
||||
apr_file_seek(geo->db, APR_SET, &seekto);
|
||||
/* TODO: check rc */
|
||||
rc = apr_file_read_full(geo->db, &cbuf, sizeof(cbuf), &nbytes);
|
||||
|
||||
country = cbuf[0];
|
||||
if ((country <= 0) || (country > GEO_COUNTRY_LAST)) {
|
||||
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\" (country %d).", log_escape(msr->mp, target), country);
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
|
||||
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
||||
if (ret != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
||||
get_apr_error(msr->mp, ret));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
||||
}
|
||||
|
||||
/* Country */
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
|
||||
}
|
||||
georec->country_code = geo_country_code[country];
|
||||
georec->country_code3 = geo_country_code3[country];
|
||||
georec->country_name = geo_country_name[country];
|
||||
georec->country_continent = geo_country_continent[country];
|
||||
rec_offset++;
|
||||
remaining -= rec_offset;
|
||||
|
||||
/* Region */
|
||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* City */
|
||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* Postal Code */
|
||||
field_len = field_length((const char *)cbuf+rec_offset, remaining);
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
|
||||
rec_offset += field_len + 1;
|
||||
remaining -= field_len + 1;
|
||||
|
||||
/* Latitude */
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
dtmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->latitude = dtmp/10000 - 180;
|
||||
rec_offset += 3;
|
||||
remaining -= 3;
|
||||
|
||||
|
||||
/* Longitude */
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
dtmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->longitude = dtmp/10000 - 180;
|
||||
rec_offset += 3;
|
||||
remaining -= 3;
|
||||
|
||||
/* dma/area codes are in city rev1 and US only */
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
|
||||
}
|
||||
if (geo->dbtype == GEO_CITY_DATABASE_1
|
||||
&& georec->country_code[0] == 'U'
|
||||
&& georec->country_code[1] == 'S')
|
||||
{
|
||||
/* DMA Code */
|
||||
itmp = cbuf[rec_offset] +
|
||||
(cbuf[rec_offset+1] << 8) +
|
||||
(cbuf[rec_offset+2] << 16);
|
||||
georec->dma_code = itmp / 1000;
|
||||
georec->area_code = itmp % 1000;
|
||||
rec_offset += 6;
|
||||
remaining -= 6;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Geo lookup for \"%s\" succeeded.", log_escape(msr->mp, target));
|
||||
|
||||
ret = apr_global_mutex_unlock(msr->modsecurity->geo_lock);
|
||||
if (ret != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "Geo Lookup: Failed to lock proc mutex: %s",
|
||||
get_apr_error(msr->mp, ret));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_GEO_H_
|
||||
#define _MSC_GEO_H_
|
||||
|
||||
#define GEO_STRUCT_INFO_MAX_SIZE 20
|
||||
#define GEO_DB_INFO_MAX_SIZE 100
|
||||
#define GEO_COUNTRY_OFFSET 0xffff00
|
||||
#define GEO_MAX_RECORD_LEN 4
|
||||
#define GEO_COUNTRY_UNKNOWN "Unknown"
|
||||
#define GEO_CITY_UNKNOWN "Unknown"
|
||||
#define GEO_CITY_RECORD_LEN 50
|
||||
#define GEO_COUNTRY_DATABASE 1
|
||||
#define GEO_CITY_DATABASE_0 6
|
||||
#define GEO_CITY_DATABASE_1 2
|
||||
#define GEO_COUNTRY_LAST 250
|
||||
#define GEO_SEGMENT_RECORD_LENGTH 3
|
||||
#define GEO_STATE_BEGIN_REV0 16700000
|
||||
#define GEO_STATE_BEGIN_REV1 16000000
|
||||
#define GEO_COUNTRY_BEGIN 16776960
|
||||
|
||||
|
||||
typedef struct geo_rec geo_rec;
|
||||
typedef struct geo_db geo_db;
|
||||
|
||||
#include <apr_file_io.h>
|
||||
#include "modsecurity.h"
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct geo_rec {
|
||||
const char *country_code;
|
||||
const char *country_code3;
|
||||
const char *country_name;
|
||||
const char *country_continent;
|
||||
const char *region;
|
||||
const char *city;
|
||||
const char *postal_code;
|
||||
float latitude;
|
||||
float longitude;
|
||||
int dma_code;
|
||||
int area_code;
|
||||
};
|
||||
|
||||
struct geo_db {
|
||||
apr_file_t *db;
|
||||
const char *dbfn;
|
||||
int dbtype;
|
||||
unsigned int ctry_offset;
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
|
||||
int DSOLOCAL geo_init(directory_config *dcfg, const char *dbfn, char **error_msg);
|
||||
|
||||
int DSOLOCAL geo_lookup(modsec_rec *msr, geo_rec *rec, const char *target, char **error_msg);
|
||||
|
||||
#endif
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_gsb.h"
|
||||
|
||||
/** \brief Load GSB database
|
||||
*
|
||||
* \param dcfg Pointer to directory configuration
|
||||
* \param error_msg Error message
|
||||
*
|
||||
* \retval 1 On Success
|
||||
* \retval 0 On Fail
|
||||
*/
|
||||
static int gsb_db_create(directory_config *dcfg, char **error_msg)
|
||||
{
|
||||
char errstr[1024];
|
||||
apr_pool_t *mp = dcfg->mp;
|
||||
gsb_db *gsb = dcfg->gsb;
|
||||
apr_int32_t wanted = APR_FINFO_SIZE;
|
||||
apr_finfo_t finfo;
|
||||
apr_status_t rc;
|
||||
apr_size_t nbytes;
|
||||
char *buf = NULL, *p = NULL, *savedptr = NULL;
|
||||
char *op = NULL;
|
||||
|
||||
if ((rc = apr_file_open(&gsb->db, gsb->dbfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not open gsb database \"%s\": %s", gsb->dbfn, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((rc = apr_file_info_get(&finfo, wanted, gsb->db)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not cannot get gsb malware file information \"%s\": %s", gsb->dbfn, apr_strerror(rc, errstr, 1024));
|
||||
apr_file_close(gsb->db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = (char *)malloc(finfo.size+1);
|
||||
|
||||
if (buf == NULL) {
|
||||
*error_msg = apr_psprintf(mp, "Could not alloc memory for gsb data");
|
||||
apr_file_close(gsb->db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = apr_file_read_full(gsb->db, buf, finfo.size, &nbytes);
|
||||
|
||||
gsb->gsb_table = apr_hash_make(dcfg->mp);
|
||||
|
||||
if (gsb->gsb_table == NULL) {
|
||||
*error_msg = apr_psprintf(mp, "Could not alloc memory for gsb table");
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
apr_file_close(gsb->db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = apr_strtok(buf,"\t",&savedptr);
|
||||
|
||||
while (p != NULL) {
|
||||
|
||||
op = strchr(p,'+');
|
||||
|
||||
if(op != NULL) {
|
||||
char *hash = ++op;
|
||||
if(strlen(hash) == 32)
|
||||
apr_hash_set(gsb->gsb_table, hash, APR_HASH_KEY_STRING, "malware");
|
||||
}
|
||||
|
||||
op = strchr(p,'-');
|
||||
|
||||
if(op != NULL) {
|
||||
char *hash = ++op;
|
||||
if(strlen(hash) == 32)
|
||||
apr_hash_set(gsb->gsb_table, hash, APR_HASH_KEY_STRING, NULL);
|
||||
}
|
||||
|
||||
p = apr_strtok(NULL,"\t",&savedptr);
|
||||
}
|
||||
|
||||
apr_file_close(gsb->db);
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Init GSB database
|
||||
*
|
||||
* \param dcfg Pointer to directory configuration
|
||||
* \param dbfn Database filename
|
||||
* \param error_msg Error message
|
||||
*
|
||||
* \retval gsb_db_create On Success
|
||||
* \retval -1 On Fail
|
||||
*/
|
||||
int gsb_db_init(directory_config *dcfg, const char *dbfn, char **error_msg)
|
||||
{
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
if ((dcfg->gsb == NULL) || (dcfg->gsb == NOT_SET_P)) {
|
||||
dcfg->gsb = apr_pcalloc(dcfg->mp, sizeof(gsb_db));
|
||||
if (dcfg->gsb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
dcfg->gsb->db = NULL;
|
||||
dcfg->gsb->dbfn = apr_pstrdup(dcfg->mp, dbfn);
|
||||
|
||||
return gsb_db_create(dcfg, error_msg);
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_GSB_H_
|
||||
#define _MSC_GSB_H_
|
||||
|
||||
typedef struct gsb_db gsb_db;
|
||||
|
||||
#include <apr_file_io.h>
|
||||
#include "modsecurity.h"
|
||||
#include "apr_hash.h"
|
||||
|
||||
struct gsb_db {
|
||||
apr_file_t *db;
|
||||
const char *dbfn;
|
||||
apr_hash_t *gsb_table;
|
||||
};
|
||||
|
||||
int DSOLOCAL gsb_db_init(directory_config *dcfg, const char *dbfn, char **error_msg);
|
||||
|
||||
#endif
|
||||
@@ -1,317 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2011 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 "msc_json.h"
|
||||
|
||||
#ifdef WITH_YAJL
|
||||
|
||||
int json_add_argument(modsec_rec *msr, const char *value, unsigned length)
|
||||
{
|
||||
msc_arg *arg = (msc_arg *) NULL;
|
||||
|
||||
/**
|
||||
* If we do not have a prefix, we cannot create a variable name
|
||||
* to reference this argument; for now we simply ignore these
|
||||
*/
|
||||
if (!msr->json->current_key) {
|
||||
msr_log(msr, 3, "Cannot add scalar value without an associated key");
|
||||
return 1;
|
||||
}
|
||||
|
||||
arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||
|
||||
/**
|
||||
* Argument name is 'prefix + current_key'
|
||||
*/
|
||||
if (msr->json->prefix) {
|
||||
arg->name = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix,
|
||||
msr->json->current_key);
|
||||
}
|
||||
else {
|
||||
arg->name = apr_psprintf(msr->mp, "%s", msr->json->current_key);
|
||||
}
|
||||
arg->name_len = strlen(arg->name);
|
||||
|
||||
/**
|
||||
* Argument value is copied from the provided string
|
||||
*/
|
||||
arg->value = apr_pstrmemdup(msr->mp, value, length);
|
||||
arg->value_len = length;
|
||||
arg->origin = "JSON";
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "Adding JSON argument '%s' with value '%s'",
|
||||
arg->name, arg->value);
|
||||
}
|
||||
|
||||
apr_table_addn(msr->arguments,
|
||||
log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* yajl callback functions
|
||||
* For more information on the function signatures and order, check
|
||||
* http://lloyd.github.com/yajl/yajl-1.0.12/structyajl__callbacks.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Callback for hash key values; we use those to define the variable names
|
||||
* under ARGS. Whenever we reach a new key, we update the current key value.
|
||||
*/
|
||||
static int yajl_map_key(void *ctx, const unsigned char *key, size_t length)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
unsigned char *safe_key = (unsigned char *) NULL;
|
||||
|
||||
/**
|
||||
* yajl does not provide us with null-terminated strings, but
|
||||
* rather expects us to copy the data from the key up to the
|
||||
* length informed; we create a standalone null-termined copy
|
||||
* in safe_key
|
||||
*/
|
||||
safe_key = apr_pstrndup(msr->mp, key, length);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "New JSON hash key '%s'", safe_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: How do we free the previously string value stored here?
|
||||
*/
|
||||
msr->json->current_key = safe_key;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for null values
|
||||
*
|
||||
* TODO: Is there a way to define true null parameter values instead of
|
||||
* empty values?
|
||||
*/
|
||||
static int yajl_null(void *ctx)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
|
||||
return json_add_argument(msr, "", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for boolean values
|
||||
*/
|
||||
static int yajl_boolean(void *ctx, int value)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
|
||||
if (value) {
|
||||
return json_add_argument(msr, "true", strlen("true"));
|
||||
}
|
||||
else {
|
||||
return json_add_argument(msr, "false", strlen("false"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for string values
|
||||
*/
|
||||
static int yajl_string(void *ctx, const unsigned char *value, size_t length)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
|
||||
return json_add_argument(msr, value, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for numbers; YAJL can use separate callbacks for integers/longs and
|
||||
* float/double values, but since we are not interested in using the numeric
|
||||
* values here, we use a generic handler which uses numeric strings
|
||||
*/
|
||||
static int yajl_number(void *ctx, const char *value, size_t length)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
|
||||
return json_add_argument(msr, value, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for a new hash, which indicates a new subtree, labeled as the current
|
||||
* argument name, is being created
|
||||
*/
|
||||
static int yajl_start_map(void *ctx)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
|
||||
/**
|
||||
* If we do not have a current_key, this is a top-level hash, so we do not
|
||||
* need to do anything
|
||||
*/
|
||||
if (!msr->json->current_key) return 1;
|
||||
|
||||
/**
|
||||
* Check if we are already inside a hash context, and append or create the
|
||||
* current key name accordingly
|
||||
*/
|
||||
if (msr->json->prefix) {
|
||||
msr->json->prefix = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix,
|
||||
msr->json->current_key);
|
||||
}
|
||||
else {
|
||||
msr->json->prefix = apr_pstrdup(msr->mp, msr->json->current_key);
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "New JSON hash context (prefix '%s')", msr->json->prefix);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for end hash, meaning the current subtree is being closed, and that
|
||||
* we should go back to the parent variable label
|
||||
*/
|
||||
static int yajl_end_map(void *ctx)
|
||||
{
|
||||
modsec_rec *msr = (modsec_rec *) ctx;
|
||||
unsigned char *separator = (unsigned char *) NULL;
|
||||
|
||||
/**
|
||||
* If we have no prefix, then this is the end of a top-level hash and
|
||||
* we don't do anything
|
||||
*/
|
||||
if (msr->json->prefix == NULL) return 1;
|
||||
|
||||
/**
|
||||
* Current prefix might or not include a separator character; top-level
|
||||
* hash keys do not have separators in the variable name
|
||||
*/
|
||||
separator = strrchr(msr->json->prefix, '.');
|
||||
|
||||
if (separator) {
|
||||
msr->json->prefix = apr_pstrmemdup(msr->mp, msr->json->prefix,
|
||||
separator - msr->json->prefix);
|
||||
msr->json->current_key = apr_psprintf(msr->mp, "%s", separator + 1);
|
||||
}
|
||||
else {
|
||||
/**
|
||||
* TODO: Check if it is safe to do this kind of pointer tricks
|
||||
*/
|
||||
msr->json->current_key = msr->json->prefix;
|
||||
msr->json->prefix = (unsigned char *) NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise JSON parser.
|
||||
*/
|
||||
int json_init(modsec_rec *msr, char **error_msg) {
|
||||
/**
|
||||
* yajl configuration and callbacks
|
||||
*/
|
||||
static yajl_callbacks callbacks = {
|
||||
yajl_null,
|
||||
yajl_boolean,
|
||||
NULL /* yajl_integer */,
|
||||
NULL /* yajl_double */,
|
||||
yajl_number,
|
||||
yajl_string,
|
||||
yajl_start_map,
|
||||
yajl_map_key,
|
||||
yajl_end_map,
|
||||
NULL /* yajl_start_array */,
|
||||
NULL /* yajl_end_array */
|
||||
};
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
msr_log(msr, 4, "JSON parser initialization");
|
||||
msr->json = apr_pcalloc(msr->mp, sizeof(json_data));
|
||||
if (msr->json == NULL) return -1;
|
||||
|
||||
/**
|
||||
* Prefix and current key are initially empty
|
||||
*/
|
||||
msr->json->prefix = (unsigned char *) NULL;
|
||||
msr->json->current_key = (unsigned char *) NULL;
|
||||
|
||||
/**
|
||||
* yajl initialization
|
||||
*
|
||||
* yajl_parser_config definition:
|
||||
* http://lloyd.github.io/yajl/yajl-2.0.1/yajl__parse_8h.html#aec816c5518264d2ac41c05469a0f986c
|
||||
*
|
||||
* TODO: make UTF8 validation optional, as it depends on Content-Encoding
|
||||
*/
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "yajl JSON parsing callback initialization");
|
||||
}
|
||||
msr->json->handle = yajl_alloc(&callbacks, NULL, msr);
|
||||
yajl_config(msr->json->handle, yajl_allow_partial_values, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed one chunk of data to the JSON parser.
|
||||
*/
|
||||
int json_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) {
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Feed our parser and catch any errors */
|
||||
msr->json->status = yajl_parse(msr->json->handle, buf, size);
|
||||
if (msr->json->status != yajl_status_ok) {
|
||||
/* We need to free the yajl error message later, how to do this? */
|
||||
*error_msg = yajl_get_error(msr->json->handle, 0, buf, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise JSON parsing.
|
||||
*/
|
||||
int json_complete(modsec_rec *msr, char **error_msg) {
|
||||
char *json_data = (char *) NULL;
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Wrap up the parsing process */
|
||||
msr->json->status = yajl_complete_parse(msr->json->handle);
|
||||
if (msr->json->status != yajl_status_ok) {
|
||||
/* We need to free the yajl error message later, how to do this? */
|
||||
*error_msg = yajl_get_error(msr->json->handle, 0, NULL, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the resources used for XML parsing.
|
||||
*/
|
||||
apr_status_t json_cleanup(modsec_rec *msr) {
|
||||
msr_log(msr, 4, "JSON: Cleaning up JSON results");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2011 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 _MSC_JSON_H_
|
||||
#define _MSC_JSON_H_
|
||||
#ifdef WITH_YAJL
|
||||
|
||||
typedef struct json_data json_data;
|
||||
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
#include <yajl/yajl_parse.h>
|
||||
//#ifdef WITH_YAJL
|
||||
//#else
|
||||
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
/* Structures */
|
||||
struct json_data {
|
||||
/* yajl configuration and parser state */
|
||||
yajl_handle handle;
|
||||
yajl_status status;
|
||||
|
||||
/* error reporting and JSON array flag */
|
||||
unsigned char *yajl_error;
|
||||
|
||||
/* prefix is used to create data hierarchy (i.e., 'parent.child.value') */
|
||||
unsigned char *prefix;
|
||||
unsigned char *current_key;
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
|
||||
int DSOLOCAL json_init(modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL json_process(modsec_rec *msr, const char *buf,
|
||||
unsigned int size, char **error_msg);
|
||||
|
||||
int DSOLOCAL json_complete(modsec_rec *msr, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL json_cleanup(modsec_rec *msr);
|
||||
|
||||
int DSOLOCAL json_process_chunk(modsec_rec *msr, const char *buf,
|
||||
unsigned int size, char **error_msg);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_LOGGING_H_
|
||||
#define _MSC_LOGGING_H_
|
||||
|
||||
#define AUDITLOG_OFF 0
|
||||
#define AUDITLOG_ON 1
|
||||
#define AUDITLOG_RELEVANT 2
|
||||
|
||||
#define AUDITLOG_SERIAL 0
|
||||
#define AUDITLOG_CONCURRENT 1
|
||||
|
||||
#define AUDITLOG_PART_FIRST 'A'
|
||||
#define AUDITLOG_PART_HEADER 'A'
|
||||
#define AUDITLOG_PART_REQUEST_HEADERS 'B'
|
||||
#define AUDITLOG_PART_REQUEST_BODY 'C'
|
||||
#define AUDITLOG_PART_RESPONSE_HEADERS 'D'
|
||||
#define AUDITLOG_PART_RESPONSE_BODY 'E'
|
||||
#define AUDITLOG_PART_A_RESPONSE_HEADERS 'F'
|
||||
#define AUDITLOG_PART_A_RESPONSE_BODY 'G'
|
||||
#define AUDITLOG_PART_TRAILER 'H'
|
||||
#define AUDITLOG_PART_FAKE_REQUEST_BODY 'I'
|
||||
#define AUDITLOG_PART_UPLOADS 'J'
|
||||
#define AUDITLOG_PART_MATCHEDRULES 'K'
|
||||
#define AUDITLOG_PART_LAST 'K'
|
||||
#define AUDITLOG_PART_ENDMARKER 'Z'
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include "apr_pools.h"
|
||||
|
||||
int DSOLOCAL is_valid_parts_specification(char *p);
|
||||
|
||||
char DSOLOCAL *construct_log_vcombinedus_limited(modsec_rec *msr, int _limit, int *was_limited);
|
||||
|
||||
void DSOLOCAL sec_audit_logger(modsec_rec *msr);
|
||||
|
||||
#endif
|
||||
@@ -1,503 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
|
||||
#include "msc_lua.h"
|
||||
|
||||
#include "apr_strings.h"
|
||||
|
||||
typedef struct {
|
||||
apr_array_header_t *parts;
|
||||
apr_pool_t *pool;
|
||||
} msc_lua_dumpw_t;
|
||||
|
||||
typedef struct {
|
||||
msc_script *script;
|
||||
int index;
|
||||
} msc_lua_dumpr_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const char* dump_reader(lua_State* L, void* user_data, size_t* size) {
|
||||
msc_lua_dumpr_t *dumpr = (msc_lua_dumpr_t *)user_data;
|
||||
msc_script_part *part;
|
||||
|
||||
/* Do we have more chunks to return? */
|
||||
if (dumpr->index == dumpr->script->parts->nelts) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get one chunk. */
|
||||
part = ((msc_script_part **)dumpr->script->parts->elts)[dumpr->index];
|
||||
*size = part->len;
|
||||
|
||||
dumpr->index++;
|
||||
|
||||
return part->data;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int dump_writer(lua_State *L, const void* data, size_t len, void* user_data) {
|
||||
msc_lua_dumpw_t *dump = (msc_lua_dumpw_t *)user_data;
|
||||
msc_script_part *part;
|
||||
void *part_data;
|
||||
|
||||
/* Allocate new part, copy the data into it. */
|
||||
part_data = apr_palloc(dump->pool, len);
|
||||
memcpy(part_data, data, len);
|
||||
part = apr_palloc(dump->pool, sizeof(msc_script_part));
|
||||
part->data = part_data;
|
||||
part->len = len;
|
||||
|
||||
/* Then add it to the list of parsts. */
|
||||
*(const msc_script_part **)apr_array_push(dump->parts) = part;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int lua_restore(lua_State *L, msc_script *script) {
|
||||
msc_lua_dumpr_t dumpr;
|
||||
|
||||
dumpr.script = script;
|
||||
dumpr.index = 0;
|
||||
|
||||
#if LUA_VERSION_NUM > 501
|
||||
return lua_load(L, dump_reader, &dumpr, script->name, NULL);
|
||||
#else
|
||||
return lua_load(L, dump_reader, &dumpr, script->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool) {
|
||||
lua_State *L = NULL;
|
||||
msc_lua_dumpw_t dump;
|
||||
|
||||
/* Initialise state. */
|
||||
#if LUA_VERSION_NUM > 501
|
||||
L = luaL_newstate();
|
||||
#else
|
||||
L = lua_open();
|
||||
#endif
|
||||
luaL_openlibs(L);
|
||||
|
||||
/* Find script. */
|
||||
if (luaL_loadfile(L, filename)) {
|
||||
return apr_psprintf(pool, "ModSecurity: Failed to compile script %s: %s",
|
||||
filename, lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
/* Dump the script into binary form. */
|
||||
dump.pool = pool;
|
||||
dump.parts = apr_array_make(pool, 128, sizeof(msc_script_part *));
|
||||
|
||||
lua_dump(L, dump_writer, &dump);
|
||||
|
||||
(*script) = apr_pcalloc(pool, sizeof(msc_script));
|
||||
(*script)->name = filename;
|
||||
(*script)->parts = dump.parts;
|
||||
|
||||
/* Destroy state. */
|
||||
lua_close(L);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int l_log(lua_State *L) {
|
||||
modsec_rec *msr = NULL;
|
||||
const char *text;
|
||||
int level;
|
||||
|
||||
/* Retrieve parameters. */
|
||||
level = luaL_checknumber(L, 1);
|
||||
text = luaL_checkstring(L, 2);
|
||||
|
||||
/* Retrieve msr. */
|
||||
lua_getglobal(L, "__msr");
|
||||
msr = (modsec_rec *)lua_topointer(L, -1);
|
||||
|
||||
/* Log message. */
|
||||
if (msr != NULL) {
|
||||
msr_log(msr, level, "%s", text);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_array_header_t *resolve_tfns(lua_State *L, int idx, modsec_rec *msr, apr_pool_t *mp) {
|
||||
apr_array_header_t *tfn_arr = NULL;
|
||||
msre_tfn_metadata *tfn = NULL;
|
||||
char *name = NULL;
|
||||
|
||||
tfn_arr = apr_array_make(mp, 25, sizeof(msre_tfn_metadata *));
|
||||
if (tfn_arr == NULL) return NULL;
|
||||
|
||||
/* ENH: Why is this userdata and not none/nil when parameter not given? */
|
||||
if (lua_isuserdata(L, idx) || lua_isnoneornil(L, idx)) { /* No second parameter */
|
||||
return tfn_arr;
|
||||
} else if (lua_istable(L, idx)) { /* Is the second parameter an array? */
|
||||
#if LUA_VERSION_NUM > 501
|
||||
int i, n = lua_rawlen(L, idx);
|
||||
#else
|
||||
int i, n = lua_objlen(L, idx);
|
||||
#endif
|
||||
|
||||
for(i = 1; i <= n; i++) {
|
||||
lua_rawgeti(L, idx, i);
|
||||
name = (char *)luaL_checkstring(L, -1);
|
||||
|
||||
/* A "none" means start over */
|
||||
if (strcmp("none", name) == 0) {
|
||||
tfn_arr->nelts = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
|
||||
if (tfn == NULL) {
|
||||
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
|
||||
} else {
|
||||
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
|
||||
}
|
||||
}
|
||||
} else if (lua_isstring(L, idx)) { /* The second parameter may be a simple string? */
|
||||
name = (char *)luaL_checkstring(L, idx);
|
||||
|
||||
/* A "none" means start over */
|
||||
if (strcmp("none", name) == 0) {
|
||||
tfn_arr->nelts = 0;
|
||||
}
|
||||
else {
|
||||
tfn = msre_engine_tfn_resolve(msr->modsecurity->msre, name);
|
||||
if (tfn == NULL) {
|
||||
msr_log(msr, 1, "SecRuleScript: Invalid transformation function: %s", name);
|
||||
} else {
|
||||
*(msre_tfn_metadata **)apr_array_push(tfn_arr) = tfn;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
msr_log(msr, 1, "SecRuleScript: Transformation parameter must be a transformation name or array of transformation names, but found \"%s\" (type %d).", lua_typename(L, idx), lua_type(L, idx));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return tfn_arr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int l_getvar(lua_State *L) {
|
||||
char *varname = NULL, *param = NULL;
|
||||
modsec_rec *msr = NULL;
|
||||
msre_rule *rule = NULL;
|
||||
char *my_error_msg = NULL;
|
||||
char *p1 = NULL;
|
||||
apr_array_header_t *tfn_arr = NULL;
|
||||
msre_var *vx = NULL;
|
||||
msre_var *var;
|
||||
|
||||
/* Retrieve parameters. */
|
||||
p1 = (char *)luaL_checkstring(L, 1);
|
||||
|
||||
/* Retrieve msr. */
|
||||
lua_getglobal(L, "__msr");
|
||||
msr = (modsec_rec *)lua_topointer(L, -1);
|
||||
|
||||
/* Retrieve rule. */
|
||||
lua_getglobal(L, "__rule");
|
||||
rule = (msre_rule *)lua_topointer(L, -1);
|
||||
|
||||
/* Extract the variable name and its parameter from the script. */
|
||||
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
|
||||
param = strchr(varname, '.');
|
||||
if (param != NULL) {
|
||||
*param = '\0';
|
||||
param++;
|
||||
}
|
||||
|
||||
/* Resolve variable. */
|
||||
var = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
|
||||
varname, param, msr, &my_error_msg);
|
||||
|
||||
if (var == NULL) {
|
||||
msr_log(msr, 1, "%s", my_error_msg);
|
||||
|
||||
lua_pushnil(L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Resolve transformation functions. */
|
||||
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
|
||||
|
||||
/* Generate variable. */
|
||||
vx = generate_single_var(msr, var, tfn_arr, rule, msr->msc_rule_mptmp);
|
||||
if (vx == NULL) {
|
||||
lua_pushnil(L);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return variable value. */
|
||||
lua_pushlstring(L, vx->value, vx->value_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int l_getvars(lua_State *L) {
|
||||
const apr_array_header_t *tarr;
|
||||
const apr_table_entry_t *telts;
|
||||
apr_table_t *vartable = NULL;
|
||||
apr_array_header_t *tfn_arr = NULL;
|
||||
char *varname = NULL, *param = NULL;
|
||||
modsec_rec *msr = NULL;
|
||||
msre_rule *rule = NULL;
|
||||
msre_var *vartemplate = NULL;
|
||||
char *my_error_msg = NULL;
|
||||
char *p1 = NULL;
|
||||
int i;
|
||||
|
||||
/* Retrieve parameters. */
|
||||
p1 = (char *)luaL_checkstring(L, 1);
|
||||
|
||||
/* Retrieve msr. */
|
||||
lua_getglobal(L, "__msr");
|
||||
msr = (modsec_rec *)lua_topointer(L, -1);
|
||||
|
||||
/* Retrieve rule. */
|
||||
lua_getglobal(L, "__rule");
|
||||
rule = (msre_rule *)lua_topointer(L, -1);
|
||||
|
||||
/* Extract the variable name and its parameter from the script. */
|
||||
varname = apr_pstrdup(msr->msc_rule_mptmp, p1);
|
||||
param = strchr(varname, '.');
|
||||
if (param != NULL) {
|
||||
*param = '\0';
|
||||
param++;
|
||||
}
|
||||
|
||||
/* Resolve transformation functions. */
|
||||
tfn_arr = resolve_tfns(L, 2, msr, msr->msc_rule_mptmp);
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
/* Resolve variable. */
|
||||
vartemplate = msre_create_var_ex(msr->msc_rule_mptmp, msr->modsecurity->msre,
|
||||
varname, param, msr, &my_error_msg);
|
||||
|
||||
if (vartemplate == NULL) {
|
||||
msr_log(msr, 1, "%s", my_error_msg);
|
||||
|
||||
/* Returning empty table. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
vartable = generate_multi_var(msr, vartemplate, tfn_arr, rule, msr->msc_rule_mptmp);
|
||||
|
||||
tarr = apr_table_elts(vartable);
|
||||
telts = (const apr_table_entry_t*)tarr->elts;
|
||||
for (i = 0; i < tarr->nelts; i++) {
|
||||
msre_var *var = (msre_var *)telts[i].val;
|
||||
|
||||
lua_pushnumber(L, i + 1); /* Index is not zero-based. */
|
||||
|
||||
lua_newtable(L); /* Per-parameter table. */
|
||||
|
||||
lua_pushstring(L, "name");
|
||||
lua_pushlstring(L, var->name, strlen(var->name));
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "value");
|
||||
lua_pushlstring(L, var->value, var->value_len);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_settable(L, -3); /* Push one parameter into the results table. */
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief New setvar function for Lua API. Users can put back
|
||||
* data in modsecurity core via new variables
|
||||
*
|
||||
* \param L Pointer to Lua state
|
||||
*
|
||||
* \retval -1 On failure
|
||||
* \retval 0 On Collection failure
|
||||
* \retval 1 On Success
|
||||
*/
|
||||
static int l_setvar(lua_State *L) {
|
||||
modsec_rec *msr = NULL;
|
||||
msre_rule *rule = NULL;
|
||||
const char *var_value = NULL;
|
||||
const char *var_name = NULL;
|
||||
int nargs = lua_gettop(L);
|
||||
char *chr = NULL;
|
||||
|
||||
lua_getglobal(L, "__msr");
|
||||
msr = (modsec_rec *)lua_topointer(L, -1);
|
||||
|
||||
lua_getglobal(L, "__rule");
|
||||
rule = (msre_rule *)lua_topointer(L, -1);
|
||||
|
||||
if(nargs != 2) {
|
||||
msr_log(msr, 8, "m.setvar: Failed m.setvar funtion must has 2 arguments");
|
||||
return -1;
|
||||
}
|
||||
var_value = luaL_checkstring (L, 2);
|
||||
var_name = luaL_checkstring (L, 1);
|
||||
|
||||
lua_pop(L,2);
|
||||
|
||||
if(var_value == NULL || var_name == NULL)
|
||||
return -1;
|
||||
|
||||
chr = strchr((char *)var_name,0x2e);
|
||||
|
||||
if(chr == NULL) {
|
||||
msr_log(msr, 8, "m.setvar: Must specify a collection using dot character - ie m.setvar(tx.myvar,mydata)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return msre_action_setvar_execute(msr,msr->msc_rule_mptmp,rule,(char *)var_name,(char *)var_value);
|
||||
}
|
||||
|
||||
static const struct luaL_Reg mylib[] = {
|
||||
{ "log", l_log },
|
||||
{ "getvar", l_getvar },
|
||||
{ "getvars", l_getvars },
|
||||
{ "setvar", l_setvar },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg) {
|
||||
apr_time_t time_before;
|
||||
lua_State *L = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 8) {
|
||||
msr_log(msr, 8, "Lua: Executing script: %s", script->name);
|
||||
}
|
||||
|
||||
time_before = apr_time_now();
|
||||
|
||||
#ifdef CACHE_LUA
|
||||
L = msr->L;
|
||||
rc = lua_gettop(L);
|
||||
if(rc)
|
||||
lua_pop(L, rc);
|
||||
#else
|
||||
/* Create new state. */
|
||||
#if LUA_VERSION_NUM > 501
|
||||
L = luaL_newstate();
|
||||
#else
|
||||
L = lua_open();
|
||||
#endif
|
||||
luaL_openlibs(L);
|
||||
#endif
|
||||
|
||||
if(L == NULL)
|
||||
return -1;
|
||||
|
||||
/* Associate msr with the state. */
|
||||
lua_pushlightuserdata(L, (void *)msr);
|
||||
lua_setglobal(L, "__msr");
|
||||
|
||||
/* Associate rule with the state. */
|
||||
if (rule != NULL) {
|
||||
lua_pushlightuserdata(L, (void *)rule);
|
||||
lua_setglobal(L, "__rule");
|
||||
}
|
||||
|
||||
/* Register functions. */
|
||||
#if LUA_VERSION_NUM > 501
|
||||
luaL_setfuncs(L,mylib,0);
|
||||
lua_setglobal(L,"m");
|
||||
#else
|
||||
luaL_register(L, "m", mylib);
|
||||
#endif
|
||||
|
||||
rc = lua_restore(L, script);
|
||||
if (rc) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Lua: Failed to restore script with %i.", rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Execute the chunk so that the functions are defined. */
|
||||
lua_pcall(L, 0, 0, 0);
|
||||
|
||||
/* Execute main() */
|
||||
lua_getglobal(L, "main");
|
||||
|
||||
/* Put the parameter on the stack. */
|
||||
if (param != NULL) {
|
||||
lua_pushlstring(L, param, strlen(param));
|
||||
}
|
||||
|
||||
if (lua_pcall(L, ((param != NULL) ? 1 : 0), 1, 0)) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Lua: Script execution failed: %s", lua_tostring(L, -1));
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 8) {
|
||||
msr_log(msr, 8, "Lua: Script execution failed: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the response from the script. */
|
||||
*error_msg = (char *)lua_tostring(L, -1);
|
||||
if (*error_msg != NULL) {
|
||||
*error_msg = apr_pstrdup(msr->mp, *error_msg);
|
||||
}
|
||||
|
||||
/* Destroy state. */
|
||||
lua_pop(L, 1);
|
||||
#ifndef CACHE_LUA
|
||||
lua_close(L);
|
||||
#endif
|
||||
|
||||
/* Returns status code to caller. */
|
||||
if (msr->txcfg->debuglog_level >= 8) {
|
||||
msr_log(msr, 8, "Lua: Script completed in %" APR_TIME_T_FMT " usec, returning: %s.",
|
||||
(apr_time_now() - time_before), *error_msg);
|
||||
}
|
||||
|
||||
return ((*error_msg != NULL) ? RULE_MATCH : RULE_NO_MATCH);
|
||||
}
|
||||
|
||||
#endif /* WITH_LUA */
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
|
||||
#ifndef _MSC_LUA_H_
|
||||
#define _MSC_LUA_H_
|
||||
|
||||
typedef struct msc_script msc_script;
|
||||
typedef struct msc_script_part msc_script_part;
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "apr_tables.h"
|
||||
#include "modsecurity.h"
|
||||
|
||||
struct msc_script {
|
||||
const char *name;
|
||||
apr_array_header_t *parts;
|
||||
};
|
||||
|
||||
struct msc_script_part {
|
||||
const void *data;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
char DSOLOCAL *lua_compile(msc_script **script, const char *filename, apr_pool_t *pool);
|
||||
|
||||
int DSOLOCAL lua_execute(msc_script *script, char *param, modsec_rec *msr, msre_rule *rule, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL msre_action_setvar_execute(modsec_rec *r, apr_pool_t *, msre_rule *, char *, char *);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WITH_LUA */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_MULTIPART_H_
|
||||
#define _MSC_MULTIPART_H_
|
||||
|
||||
#define MULTIPART_BUF_SIZE 4096
|
||||
|
||||
#define MULTIPART_FORMDATA 1
|
||||
#define MULTIPART_FILE 2
|
||||
|
||||
typedef struct multipart_part multipart_part;
|
||||
typedef struct multipart_data multipart_data;
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "apr_tables.h"
|
||||
#include "modsecurity.h"
|
||||
|
||||
typedef struct value_part_t value_part_t;
|
||||
struct value_part_t {
|
||||
char *data;
|
||||
long int length;
|
||||
};
|
||||
|
||||
struct multipart_part {
|
||||
/* part type, can be MULTIPART_FORMDATA or MULTIPART_FILE */
|
||||
int type;
|
||||
/* the name */
|
||||
char *name;
|
||||
|
||||
/* variables only, variable value */
|
||||
char *value;
|
||||
apr_array_header_t *value_parts;
|
||||
|
||||
/* files only, the content type (where available) */
|
||||
char *content_type;
|
||||
|
||||
/* files only, the name of the temporary file holding data */
|
||||
char *tmp_file_name;
|
||||
int tmp_file_fd;
|
||||
unsigned int tmp_file_size;
|
||||
/* files only, filename as supplied by the browser */
|
||||
char *filename;
|
||||
|
||||
char *last_header_name;
|
||||
apr_table_t *headers;
|
||||
|
||||
unsigned int offset;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
struct multipart_data {
|
||||
/* this array keeps parts */
|
||||
apr_array_header_t *parts;
|
||||
|
||||
/* Number of parts that are files */
|
||||
int nfiles;
|
||||
|
||||
/* mime boundary used to detect when
|
||||
* parts end and begin
|
||||
*/
|
||||
char *boundary;
|
||||
int boundary_count;
|
||||
|
||||
/* internal buffer and other variables
|
||||
* used while parsing
|
||||
*/
|
||||
char buf[MULTIPART_BUF_SIZE + 2];
|
||||
int buf_contains_line;
|
||||
char *bufptr;
|
||||
int bufleft;
|
||||
|
||||
unsigned int buf_offset;
|
||||
|
||||
/* pointer that keeps track of a part while
|
||||
* it is being built
|
||||
*/
|
||||
multipart_part *mpp;
|
||||
|
||||
|
||||
/* part parsing state; 0 means we are reading
|
||||
* headers, 1 means we are collecting data
|
||||
*/
|
||||
int mpp_state;
|
||||
|
||||
/* because of the way this parsing algorithm
|
||||
* works we hold back the last two bytes of
|
||||
* each data chunk so that we can discard it
|
||||
* later if the next data chunk proves to be
|
||||
* a boundary; the first byte is an indicator
|
||||
* 0 - no content, 1 - two data bytes available
|
||||
*/
|
||||
char reserve[4];
|
||||
|
||||
int seen_data;
|
||||
int is_complete;
|
||||
|
||||
int flag_error;
|
||||
int flag_data_before;
|
||||
int flag_data_after;
|
||||
int flag_header_folding;
|
||||
int flag_boundary_quoted;
|
||||
int flag_lf_line;
|
||||
int flag_crlf_line;
|
||||
int flag_unmatched_boundary;
|
||||
int flag_boundary_whitespace;
|
||||
int flag_missing_semicolon;
|
||||
int flag_invalid_quoting;
|
||||
int flag_invalid_part;
|
||||
int flag_invalid_header_folding;
|
||||
int flag_file_limit_exceeded;
|
||||
};
|
||||
|
||||
|
||||
/* Functions */
|
||||
|
||||
int DSOLOCAL multipart_init(modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL multipart_complete(modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL multipart_process_chunk(modsec_rec *msr, const char *buf,
|
||||
unsigned int size, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL multipart_cleanup(modsec_rec *msr);
|
||||
|
||||
int DSOLOCAL multipart_get_arguments(modsec_rec *msr, char *origin, apr_table_t *arguments);
|
||||
|
||||
char DSOLOCAL *multipart_reconstruct_urlencoded_body_sanitize(modsec_rec *msr);
|
||||
|
||||
#endif
|
||||
@@ -1,351 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_parsers.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int parse_cookies_v0(modsec_rec *msr, char *_cookie_header,
|
||||
apr_table_t *cookies, const char *delim)
|
||||
{
|
||||
char *attr_name = NULL, *attr_value = NULL;
|
||||
char *cookie_header;
|
||||
char *saveptr = NULL;
|
||||
int cookie_count = 0;
|
||||
char *p = NULL;
|
||||
|
||||
if (_cookie_header == NULL) {
|
||||
msr_log(msr, 1, "Cookie parser: Received null for argument.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cookie_header = strdup(_cookie_header);
|
||||
if (cookie_header == NULL) return -1;
|
||||
|
||||
if(msr->txcfg->cookiev0_separator == NULL) {
|
||||
p = apr_strtok(cookie_header, delim, &saveptr);
|
||||
} else {
|
||||
p = apr_strtok(cookie_header, msr->txcfg->cookiev0_separator, &saveptr);
|
||||
}
|
||||
|
||||
while(p != NULL) {
|
||||
attr_name = NULL;
|
||||
attr_value = NULL;
|
||||
|
||||
/* ignore whitespace at the beginning of cookie name */
|
||||
while(isspace(*p)) p++;
|
||||
attr_name = p;
|
||||
|
||||
attr_value = strstr(p, "=");
|
||||
if (attr_value != NULL) {
|
||||
/* terminate cookie name */
|
||||
*attr_value = 0;
|
||||
/* move over to the beginning of the value */
|
||||
attr_value++;
|
||||
}
|
||||
|
||||
/* we ignore cookies with empty names */
|
||||
if ((attr_name != NULL)&&(strlen(attr_name) != 0)) {
|
||||
if (attr_value != NULL) {
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"",
|
||||
log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value));
|
||||
}
|
||||
|
||||
apr_table_add(cookies, attr_name, attr_value);
|
||||
} else {
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty",
|
||||
log_escape(msr->mp, attr_name));
|
||||
}
|
||||
|
||||
apr_table_add(cookies, attr_name, "");
|
||||
}
|
||||
|
||||
cookie_count++;
|
||||
}
|
||||
|
||||
if(msr->txcfg->cookiev0_separator == NULL) {
|
||||
p = apr_strtok(NULL, delim, &saveptr);
|
||||
} else {
|
||||
p = apr_strtok(NULL, msr->txcfg->cookiev0_separator, &saveptr);
|
||||
}
|
||||
}
|
||||
|
||||
free(cookie_header);
|
||||
return cookie_count;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int parse_cookies_v1(modsec_rec *msr, char *_cookie_header,
|
||||
apr_table_t *cookies)
|
||||
{
|
||||
char *attr_name = NULL, *attr_value = NULL, *p = NULL;
|
||||
char *prev_attr_name = NULL;
|
||||
char *cookie_header = NULL;
|
||||
int cookie_count = 0;
|
||||
|
||||
if (_cookie_header == NULL) return -1;
|
||||
// XXX Should it not match _v0 parser?
|
||||
//if (_cookie_header == NULL) {
|
||||
// msr_log(msr, 1, "Cookie parser: Received null for argument.");
|
||||
// return -1;
|
||||
//}
|
||||
|
||||
cookie_header = strdup(_cookie_header);
|
||||
if (cookie_header == NULL) return -1;
|
||||
|
||||
p = cookie_header;
|
||||
while(*p != 0) {
|
||||
attr_name = NULL;
|
||||
attr_value = NULL;
|
||||
|
||||
/* attribute name */
|
||||
|
||||
/* remove space from the beginning */
|
||||
while((isspace(*p))&&(*p != 0)) p++;
|
||||
attr_name = p;
|
||||
while((*p != 0)&&(*p != '=')&&(*p != ';')&&(*p != ',')) p++;
|
||||
|
||||
/* if we've reached the end of string */
|
||||
if (*p == 0) goto add_cookie;
|
||||
|
||||
/* if there is no cookie value supplied */
|
||||
if ((*p == ';')||(*p == ',')) {
|
||||
*p++ = 0; /* terminate the name */
|
||||
goto add_cookie;
|
||||
}
|
||||
|
||||
/* terminate the attribute name,
|
||||
* writing over the = character
|
||||
*/
|
||||
*p++ = 0;
|
||||
|
||||
/* attribute value */
|
||||
|
||||
/* skip over the whitespace at the beginning */
|
||||
while((isspace(*p))&&(*p != 0)) p++;
|
||||
|
||||
/* no value supplied */
|
||||
if (*p == 0) goto add_cookie;
|
||||
|
||||
if (*p == '"') {
|
||||
if (*++p == 0) goto add_cookie;
|
||||
attr_value = p;
|
||||
while((*p != 0)&&(*p != '"')) p++;
|
||||
if (*p != 0) *p++ = 0;
|
||||
else {
|
||||
/* Do nothing about this. */
|
||||
}
|
||||
} else {
|
||||
attr_value = p;
|
||||
while((*p != 0)&&(*p != ',')&&(*p != ';')) p++;
|
||||
if (*p != 0) *p++ = 0;
|
||||
|
||||
/* remove the whitespace from the end of cookie value */
|
||||
if (attr_value != NULL) {
|
||||
char *t = attr_value;
|
||||
int i = 0;
|
||||
|
||||
while(*t != 0) {
|
||||
t++;
|
||||
i++;
|
||||
}
|
||||
|
||||
while((i-- > 0)&&(isspace(*(--t)))) *t = 0;
|
||||
}
|
||||
}
|
||||
|
||||
add_cookie:
|
||||
|
||||
/* remove the whitespace from the end of cookie name */
|
||||
if (attr_name != NULL) {
|
||||
char *t = attr_name;
|
||||
int i = 0;
|
||||
|
||||
while(*t != 0) {
|
||||
t++;
|
||||
i++;
|
||||
}
|
||||
|
||||
while((i-- > 0)&&(isspace(*(--t)))) *t = 0;
|
||||
}
|
||||
|
||||
/* add the cookie to the list now */
|
||||
if ((attr_name != NULL)&&(strlen(attr_name) != 0)) {
|
||||
|
||||
/* handle special attribute names */
|
||||
if (attr_name[0] == '$') {
|
||||
if (prev_attr_name != NULL) {
|
||||
/* cookie keyword, we change the name we use
|
||||
* so they can have a unique name in the cookie table
|
||||
*/
|
||||
attr_name = apr_psprintf(msr->mp, "$%s_%s", prev_attr_name, attr_name + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_value != NULL) {
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Adding request cookie: name \"%s\", value \"%s\"",
|
||||
log_escape(msr->mp, attr_name), log_escape(msr->mp, attr_value));
|
||||
}
|
||||
|
||||
apr_table_add(cookies, attr_name, attr_value);
|
||||
} else {
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Adding request cookie: name \"%s\", value empty",
|
||||
log_escape(msr->mp, attr_name));
|
||||
}
|
||||
|
||||
apr_table_add(cookies, attr_name, "");
|
||||
}
|
||||
|
||||
cookie_count++;
|
||||
|
||||
/* only keep the cookie names for later */
|
||||
if (attr_name[0] != '$') prev_attr_name = attr_name;
|
||||
}
|
||||
|
||||
/* at this point the *p is either 0 (in which case we exit), or
|
||||
* right after the current cookie ended - we need to look for
|
||||
* the next cookie
|
||||
*/
|
||||
while( (*p != 0)&&( (*p == ',')||(*p == ';')||(isspace(*p)) ) ) p++;
|
||||
}
|
||||
|
||||
free(cookie_header);
|
||||
return cookie_count;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
||||
int argument_separator, const char *origin,
|
||||
apr_table_t *arguments, int *invalid_count)
|
||||
{
|
||||
msc_arg *arg;
|
||||
apr_size_t i, j;
|
||||
char *value = NULL;
|
||||
char *buf;
|
||||
int status;
|
||||
int changed;
|
||||
|
||||
if (s == NULL) return -1;
|
||||
if (inputlength == 0) return 1;
|
||||
|
||||
/* Check that adding one will not overflow */
|
||||
if (inputlength + 1 <= 0) return -1;
|
||||
|
||||
buf = (char *)malloc(inputlength + 1);
|
||||
if (buf == NULL) return -1;
|
||||
|
||||
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||
arg->origin = origin;
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
status = 0;
|
||||
*invalid_count = 0;
|
||||
while (i < inputlength) {
|
||||
if (status == 0) {
|
||||
/* parameter name */
|
||||
arg->name_origin_offset = i;
|
||||
while ((s[i] != '=') && (s[i] != argument_separator) && (i < inputlength)) {
|
||||
buf[j] = s[i];
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
buf[j++] = '\0';
|
||||
arg->name_origin_len = i - arg->name_origin_offset;
|
||||
} else {
|
||||
/* parameter value */
|
||||
arg->value_origin_offset = i;
|
||||
while ((s[i] != argument_separator) && (i < inputlength)) {
|
||||
buf[j] = s[i];
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
buf[j++] = '\0';
|
||||
arg->value_origin_len = i - arg->value_origin_offset;
|
||||
}
|
||||
|
||||
if (status == 0) {
|
||||
arg->name_len = urldecode_nonstrict_inplace_ex((unsigned char *)buf, arg->name_origin_len, invalid_count, &changed);
|
||||
arg->name = apr_pstrmemdup(msr->mp, buf, arg->name_len);
|
||||
|
||||
if (s[i] == argument_separator) {
|
||||
/* Empty parameter */
|
||||
arg->value_len = 0;
|
||||
arg->value = "";
|
||||
|
||||
add_argument(msr, arguments, arg);
|
||||
|
||||
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||
arg->origin = origin;
|
||||
|
||||
status = 0; /* unchanged */
|
||||
j = 0;
|
||||
} else {
|
||||
status = 1;
|
||||
value = &buf[j];
|
||||
}
|
||||
}
|
||||
else {
|
||||
arg->value_len = urldecode_nonstrict_inplace_ex((unsigned char *)value, arg->value_origin_len, invalid_count, &changed);
|
||||
arg->value = apr_pstrmemdup(msr->mp, value, arg->value_len);
|
||||
|
||||
add_argument(msr, arguments, arg);
|
||||
|
||||
arg = (msc_arg *)apr_pcalloc(msr->mp, sizeof(msc_arg));
|
||||
arg->origin = origin;
|
||||
|
||||
status = 0;
|
||||
j = 0;
|
||||
}
|
||||
|
||||
i++; /* skip over the separator */
|
||||
}
|
||||
|
||||
/* the last parameter was empty */
|
||||
if (status == 1) {
|
||||
arg->value_len = 0;
|
||||
arg->value = "";
|
||||
|
||||
add_argument(msr, arguments, arg);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg)
|
||||
{
|
||||
if (msr->txcfg->debuglog_level >= 5) {
|
||||
msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"",
|
||||
arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len),
|
||||
log_escape_ex(msr->mp, arg->value, arg->value_len));
|
||||
}
|
||||
|
||||
apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg);
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_PARSERS_H_
|
||||
#define _MSC_PARSERS_H_
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
int DSOLOCAL parse_cookies_v0(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies,
|
||||
const char *delim);
|
||||
|
||||
int DSOLOCAL parse_cookies_v1(modsec_rec *msr, char *_cookie_header, apr_table_t *cookies);
|
||||
|
||||
int DSOLOCAL parse_arguments(modsec_rec *msr, const char *s, apr_size_t inputlength,
|
||||
int argument_separator, const char *origin, apr_table_t *arguments, int *invalid_count);
|
||||
|
||||
void DSOLOCAL add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg);
|
||||
|
||||
#endif
|
||||
@@ -1,193 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_pcre.h"
|
||||
#include "apr_strings.h"
|
||||
|
||||
/**
|
||||
* Releases the resources used by a single regular expression pattern.
|
||||
*/
|
||||
static apr_status_t msc_pcre_cleanup(msc_regex_t *regex) {
|
||||
if (regex != NULL) {
|
||||
if (regex->pe != NULL) {
|
||||
#if defined(VERSION_NGINX)
|
||||
pcre_free(regex->pe);
|
||||
#else
|
||||
free(regex->pe);
|
||||
#endif
|
||||
regex->pe = NULL;
|
||||
}
|
||||
if (regex->re != NULL) {
|
||||
pcre_free(regex->re);
|
||||
regex->re = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return APR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the provided regular expression pattern. The _err*
|
||||
* parameters are optional, but if they are provided and an error
|
||||
* occurs they will contain the error message and the offset in
|
||||
* the pattern where the offending part of the pattern begins. The
|
||||
* match_limit* parameters are optional and if >0, then will set
|
||||
* match limits.
|
||||
*/
|
||||
void *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options,
|
||||
const char **_errptr, int *_erroffset,
|
||||
int match_limit, int match_limit_recursion)
|
||||
{
|
||||
const char *errptr = NULL;
|
||||
int erroffset;
|
||||
msc_regex_t *regex;
|
||||
pcre_extra *pe = NULL;
|
||||
|
||||
regex = apr_pcalloc(pool, sizeof(msc_regex_t));
|
||||
if (regex == NULL) return NULL;
|
||||
regex->pattern = pattern;
|
||||
|
||||
if ((_errptr == NULL)||(_erroffset == NULL)) {
|
||||
regex->re = pcre_compile(pattern, options, &errptr, &erroffset, NULL);
|
||||
} else {
|
||||
regex->re = pcre_compile(pattern, options, _errptr, _erroffset, NULL);
|
||||
}
|
||||
if (regex->re == NULL) return NULL;
|
||||
|
||||
#ifdef WITH_PCRE_STUDY
|
||||
#ifdef WITH_PCRE_JIT
|
||||
pe = pcre_study(regex->re, PCRE_STUDY_JIT_COMPILE, &errptr);
|
||||
#else
|
||||
pe = pcre_study(regex->re, 0, &errptr);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Setup the pcre_extra record if pcre_study did not already do it */
|
||||
if (pe == NULL) {
|
||||
#if defined(VERSION_NGINX)
|
||||
pe = pcre_malloc(sizeof(pcre_extra));
|
||||
#else
|
||||
pe = malloc(sizeof(pcre_extra));
|
||||
#endif
|
||||
if (pe == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset(pe, 0, sizeof(pcre_extra));
|
||||
}
|
||||
|
||||
#ifdef PCRE_EXTRA_MATCH_LIMIT
|
||||
/* If match limit is available, then use it */
|
||||
|
||||
/* Use ModSecurity runtime defaults */
|
||||
if (match_limit > 0) {
|
||||
pe->match_limit = match_limit;
|
||||
pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
||||
}
|
||||
#ifdef MODSEC_PCRE_MATCH_LIMIT
|
||||
/* Default to ModSecurity compiled defaults */
|
||||
else {
|
||||
pe->match_limit = MODSEC_PCRE_MATCH_LIMIT;
|
||||
pe->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
||||
}
|
||||
#endif /* MODSEC_PCRE_MATCH_LIMIT */
|
||||
#else
|
||||
#pragma message ( "This PCRE version does not support match limits! Upgrade to at least PCRE v6.5." )
|
||||
#endif /* PCRE_EXTRA_MATCH_LIMIT */
|
||||
|
||||
#ifdef PCRE_EXTRA_MATCH_LIMIT_RECURSION
|
||||
/* If match limit recursion is available, then use it */
|
||||
|
||||
/* Use ModSecurity runtime defaults */
|
||||
if (match_limit_recursion > 0) {
|
||||
pe->match_limit_recursion = match_limit_recursion;
|
||||
pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
||||
}
|
||||
#ifdef MODSEC_PCRE_MATCH_LIMIT_RECURSION
|
||||
/* Default to ModSecurity compiled defaults */
|
||||
else {
|
||||
pe->match_limit_recursion = MODSEC_PCRE_MATCH_LIMIT_RECURSION;
|
||||
pe->flags |= PCRE_EXTRA_MATCH_LIMIT_RECURSION;
|
||||
}
|
||||
#endif /* MODSEC_PCRE_MATCH_LIMIT_RECURSION */
|
||||
#else
|
||||
#pragma message ( "This PCRE version does not support match recursion limits! Upgrade to at least PCRE v6.5." )
|
||||
#endif /* PCRE_EXTRA_MATCH_LIMIT_RECURSION */
|
||||
|
||||
regex->pe = pe;
|
||||
|
||||
apr_pool_cleanup_register(pool, (void *)regex,
|
||||
(apr_status_t (*)(void *))msc_pcre_cleanup, apr_pool_cleanup_null);
|
||||
|
||||
return regex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the provided regular expression pattern. Calls msc_pregcomp_ex()
|
||||
* with default limits.
|
||||
*/
|
||||
void *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
|
||||
const char **_errptr, int *_erroffset)
|
||||
{
|
||||
return msc_pregcomp_ex(pool, pattern, options, _errptr, _erroffset, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes regular expression with extended options.
|
||||
* Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1
|
||||
* on errors, and a value > 0 when there is a match.
|
||||
*/
|
||||
int msc_regexec_ex(msc_regex_t *regex, const char *s, unsigned int slen,
|
||||
int startoffset, int options, int *ovector, int ovecsize, char **error_msg)
|
||||
{
|
||||
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
||||
*error_msg = NULL;
|
||||
|
||||
return pcre_exec(regex->re, regex->pe, s, slen, startoffset, options, ovector, ovecsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes regular expression, capturing subexpressions in the given
|
||||
* vector. Returns PCRE_ERROR_NOMATCH when there is no match, error code < -1
|
||||
* on errors, and a value > 0 when there is a match.
|
||||
*/
|
||||
int msc_regexec_capture(msc_regex_t *regex, const char *s, unsigned int slen,
|
||||
int *ovector, int ovecsize, char **error_msg)
|
||||
{
|
||||
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
||||
*error_msg = NULL;
|
||||
|
||||
return msc_regexec_ex(regex, s, slen, 0, 0, ovector, ovecsize, error_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes regular expression but ignores any of the subexpression
|
||||
* captures. See above for the return codes.
|
||||
*/
|
||||
int msc_regexec(msc_regex_t *regex, const char *s, unsigned int slen,
|
||||
char **error_msg)
|
||||
{
|
||||
if (error_msg == NULL) return -1000; /* To differentiate from PCRE as it already uses -1. */
|
||||
*error_msg = NULL;
|
||||
|
||||
return msc_regexec_ex(regex, s, slen, 0, 0, NULL, 0, error_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets info on a compiled regex.
|
||||
*/
|
||||
int msc_fullinfo(msc_regex_t *regex, int what, void *where)
|
||||
{
|
||||
return pcre_fullinfo(regex->re, regex->pe, what, where);
|
||||
}
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_PCRE_H_
|
||||
#define _MSC_PCRE_H_
|
||||
|
||||
typedef struct msc_regex_t msc_regex_t;
|
||||
|
||||
#include "pcre.h"
|
||||
|
||||
#ifndef PCRE_ERROR_MATCHLIMIT
|
||||
/* Define for compile, but not valid in this version of PCRE. */
|
||||
#define PCRE_ERROR_MATCHLIMIT (-8)
|
||||
#endif /* PCRE_ERROR_MATCHLIMIT */
|
||||
|
||||
#ifndef PCRE_ERROR_RECURSIONLIMIT
|
||||
/* Define for compile, but not valid in this version of PCRE. */
|
||||
#define PCRE_ERROR_RECURSIONLIMIT (-21)
|
||||
#endif /* PCRE_ERROR_RECURSIONLIMIT */
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "modsecurity.h"
|
||||
|
||||
struct msc_regex_t {
|
||||
void *re;
|
||||
void *pe;
|
||||
const char *pattern;
|
||||
};
|
||||
|
||||
void DSOLOCAL *msc_pregcomp_ex(apr_pool_t *pool, const char *pattern, int options,
|
||||
const char **_errptr, int *_erroffset,
|
||||
int match_limit, int match_limit_recursion);
|
||||
|
||||
void DSOLOCAL *msc_pregcomp(apr_pool_t *pool, const char *pattern, int options,
|
||||
const char **_errptr, int *_erroffset);
|
||||
|
||||
int DSOLOCAL msc_regexec_ex(msc_regex_t *regex, const char *s,
|
||||
unsigned int slen, int startoffset, int options,
|
||||
int *ovector, int ovecsize, char **error_msg);
|
||||
|
||||
int DSOLOCAL msc_regexec_capture(msc_regex_t *regex, const char *s,
|
||||
unsigned int slen, int *ovector,
|
||||
int ovecsize, char **error_msg);
|
||||
|
||||
int DSOLOCAL msc_regexec(msc_regex_t *regex, const char *s,
|
||||
unsigned int slen, char **error_msg);
|
||||
|
||||
int DSOLOCAL msc_fullinfo(msc_regex_t *regex, int what, void *where);
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_release.h"
|
||||
|
||||
static const struct modsec_build_type_rec {
|
||||
char name[12]; /* pads at 16 bytes with val */
|
||||
int val;
|
||||
} modsec_build_type[] = {
|
||||
{ "-dev", 1 }, /* Development build */
|
||||
{ "-rc", 3 }, /* Release Candidate build */
|
||||
{ "", 9 }, /* Production build */
|
||||
{ "-tw", 9 }, /* Truswave Holdings build */
|
||||
{ "-trunk", 9 } /* Trunk build */
|
||||
};
|
||||
|
||||
int get_modsec_build_type(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(modsec_build_type)/sizeof(modsec_build_type[0]); i++) {
|
||||
if (strcmp(((name == NULL) ? MODSEC_VERSION_TYPE : name), modsec_build_type[i].name) == 0) {
|
||||
return modsec_build_type[i].val;
|
||||
}
|
||||
}
|
||||
|
||||
return 9; /* so no warning */
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_RELEASE_H_
|
||||
#define _MSC_RELEASE_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* ENH: Clean this mess up by detecting this is possible */
|
||||
#if !(defined(_AIX) || defined(WIN32) || defined(CYGWIN) || defined(NETWARE) || defined(SOLARIS2) || defined(OSF1))
|
||||
#define DSOLOCAL __attribute__((visibility("hidden")))
|
||||
#else
|
||||
#define DSOLOCAL
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG_MEM)
|
||||
/* Nothing Yet */
|
||||
#endif
|
||||
|
||||
/* For GNU C, tell the compiler to check printf like formatters */
|
||||
#if (defined(__GNUC__) && !defined(SOLARIS2))
|
||||
#define PRINTF_ATTRIBUTE(a,b) __attribute__((format (printf, a, b)))
|
||||
#else
|
||||
#define PRINTF_ATTRIBUTE(a,b)
|
||||
#endif
|
||||
|
||||
#define MODSEC_VERSION_MAJOR "2"
|
||||
#define MODSEC_VERSION_MINOR "9"
|
||||
#define MODSEC_VERSION_MAINT "0"
|
||||
#define MODSEC_VERSION_TYPE ""
|
||||
#define MODSEC_VERSION_RELEASE ""
|
||||
|
||||
#define MODSEC_VERSION_SUFFIX MODSEC_VERSION_TYPE MODSEC_VERSION_RELEASE
|
||||
|
||||
#define MODSEC_VERSION \
|
||||
MODSEC_VERSION_MAJOR "." MODSEC_VERSION_MINOR "." MODSEC_VERSION_MAINT \
|
||||
MODSEC_VERSION_SUFFIX
|
||||
|
||||
/* Apache Module Defines */
|
||||
#ifdef VERSION_IIS
|
||||
#define MODSEC_MODULE_NAME "ModSecurity for IIS (STABLE)"
|
||||
#else
|
||||
#ifdef VERSION_NGINX
|
||||
#define MODSEC_MODULE_NAME "ModSecurity for nginx (STABLE)"
|
||||
#else
|
||||
#ifdef VERSION_STANDALONE
|
||||
#define MODSEC_MODULE_NAME "ModSecurity Standalone (STABLE)"
|
||||
#else
|
||||
#define MODSEC_MODULE_NAME "ModSecurity for Apache"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#define MODSEC_MODULE_VERSION MODSEC_VERSION
|
||||
#define MODSEC_MODULE_NAME_FULL MODSEC_MODULE_NAME "/" MODSEC_MODULE_VERSION " (http://www.modsecurity.org/)"
|
||||
|
||||
int DSOLOCAL get_modsec_build_type(const char *name);
|
||||
|
||||
#endif /* _MSC_RELEASE_H_ */
|
||||
@@ -1,816 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_remote_rules.h"
|
||||
#include "msc_status_engine.h"
|
||||
|
||||
#include <apr_thread_pool.h>
|
||||
|
||||
#ifdef WITH_CURL
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#include <apu.h>
|
||||
|
||||
#ifdef WITH_REMOTE_RULES
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
#include <apr_crypto.h>
|
||||
#endif
|
||||
#include <apr_sha1.h>
|
||||
#endif
|
||||
|
||||
#ifndef AP_MAX_ARGC
|
||||
#define AP_MAX_ARGC 64
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Find command in a list.
|
||||
*
|
||||
* This is a duplicate of `ap_find_command', which is part of the standalone module.
|
||||
* Apache versions does not include the standalone, thus, this is necessary for
|
||||
* the Apache versions. Once it is here it may not be necessary to be part of
|
||||
* the standalone module, but, for this version both function will co-exist
|
||||
* avoiding problems with 3rd parties that are extending the standalone module.
|
||||
*
|
||||
* @note Prefer this function instead of `ap_finc_command` which is part of the
|
||||
* standalone module.
|
||||
*
|
||||
* @param parms char pointer, function name.
|
||||
* @param cmds pointer to command_rec[].
|
||||
* @retval NULL if command was not found.
|
||||
*
|
||||
*/
|
||||
const command_rec *msc_remote_find_command(const char *name, const command_rec *cmds)
|
||||
{
|
||||
while (cmds->name) {
|
||||
if (!strcasecmp(name, cmds->name))
|
||||
return cmds;
|
||||
|
||||
++cmds;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Insert a new SecRule to be processed by ModSecurity
|
||||
*
|
||||
* This is a duplicate of `invoke_cmd', which is part of the standalone module.
|
||||
* Apache versions does not include the standalone, thus, this is necessary for
|
||||
* the Apache versions. Once it is here it may not be necessary to be part of
|
||||
* the standalone module, but, for this version both function will co-exist
|
||||
* avoiding problems with 3rd parties that are extending the standalone module.
|
||||
*
|
||||
* @note Prefer this function instead of `invoke_cmd` which is part of the
|
||||
* standalone module.
|
||||
*
|
||||
* @param cmd pointer to command_rec structure.
|
||||
* @param parms pointer to cmd_params strucutre.
|
||||
* @param mconfig pointer to main config structure.
|
||||
* @param args SecRule arguments.
|
||||
* @retval NULL if everything worked as expected otherwise an error message.
|
||||
*
|
||||
*/
|
||||
const char *msc_remote_invoke_cmd(const command_rec *cmd, cmd_parms *parms,
|
||||
void *mconfig, const char *args)
|
||||
{
|
||||
char *w, *w2, *w3;
|
||||
const char *errmsg = NULL;
|
||||
|
||||
if ((parms->override & cmd->req_override) == 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name, " not allowed here", NULL);
|
||||
|
||||
parms->info = cmd->cmd_data;
|
||||
parms->cmd = cmd;
|
||||
|
||||
switch (cmd->args_how) {
|
||||
case RAW_ARGS:
|
||||
#ifdef RESOLVE_ENV_PER_TOKEN
|
||||
args = ap_resolve_env(parms->pool,args);
|
||||
#endif
|
||||
return cmd->AP_RAW_ARGS(parms, mconfig, args);
|
||||
|
||||
case TAKE_ARGV:
|
||||
{
|
||||
char *argv[AP_MAX_ARGC];
|
||||
int argc = 0;
|
||||
|
||||
do {
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
if (*w == '\0' && *args == '\0') {
|
||||
break;
|
||||
}
|
||||
argv[argc] = w;
|
||||
argc++;
|
||||
} while (argc < AP_MAX_ARGC && *args != '\0');
|
||||
|
||||
return cmd->AP_TAKE_ARGV(parms, mconfig, argc, argv);
|
||||
}
|
||||
|
||||
case NO_ARGS:
|
||||
if (*args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name, " takes no arguments",
|
||||
NULL);
|
||||
|
||||
return cmd->AP_NO_ARGS(parms, mconfig);
|
||||
case TAKE1:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name, " takes one argument",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE1(parms, mconfig, w);
|
||||
case TAKE2:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || *w2 == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name, " takes two arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE2(parms, mconfig, w, w2);
|
||||
case TAKE12:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name, " takes 1-2 arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE2(parms, mconfig, w, *w2 ? w2 : NULL);
|
||||
case TAKE3:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = ap_getword_conf(parms->pool, &args);
|
||||
w3 = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || *w2 == '\0' || *w3 == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" takes three arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
|
||||
case TAKE23:
|
||||
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = ap_getword_conf(parms->pool, &args);
|
||||
w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
|
||||
|
||||
if (*w == '\0' || *w2 == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" takes two or three arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
|
||||
case TAKE123:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
|
||||
w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
|
||||
|
||||
if (*w == '\0' || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" takes one, two or three arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
|
||||
case TAKE13:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
w2 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
|
||||
w3 = *args ? ap_getword_conf(parms->pool, &args) : NULL;
|
||||
|
||||
if (*w == '\0' || (w2 && *w2 && !w3) || *args != 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" takes one or three arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
return cmd->AP_TAKE3(parms, mconfig, w, w2, w3);
|
||||
case ITERATE:
|
||||
while (*(w = ap_getword_conf(parms->pool, &args)) != '\0') {
|
||||
|
||||
errmsg = cmd->AP_TAKE1(parms, mconfig, w);
|
||||
|
||||
if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0)
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
case ITERATE2:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || *args == 0)
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" requires at least two arguments",
|
||||
cmd->errmsg ? ", " : NULL, cmd->errmsg, NULL);
|
||||
|
||||
while (*(w2 = ap_getword_conf(parms->pool, &args)) != '\0') {
|
||||
|
||||
errmsg = cmd->AP_TAKE2(parms, mconfig, w, w2);
|
||||
|
||||
if (errmsg && strcmp(errmsg, DECLINE_CMD) != 0)
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
return errmsg;
|
||||
case FLAG:
|
||||
w = ap_getword_conf(parms->pool, &args);
|
||||
|
||||
if (*w == '\0' || (strcasecmp(w, "on") && strcasecmp(w, "off")))
|
||||
return apr_pstrcat(parms->pool, cmd->name, " must be On or Off",
|
||||
NULL);
|
||||
|
||||
return cmd->AP_FLAG(parms, mconfig, strcasecmp(w, "off") != 0);
|
||||
default:
|
||||
return apr_pstrcat(parms->pool, cmd->name,
|
||||
" is improperly configured internally (server bug)",
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetch an URL and fill the content into a memory buffer.
|
||||
*
|
||||
* Fill an msc_curl_memory_buffer_t structure with the content of an given
|
||||
* URL.
|
||||
*
|
||||
* @note While fetching the content, it will present the ModSecurity instance
|
||||
* to the remote server, trough: ModSecurity Unique ID, ModSecurity
|
||||
* status line and also, if given, key that can be used to
|
||||
* authentication. Such data is presented in the following HTTP headers:
|
||||
* - ModSec-status
|
||||
* - ModSec-unique-id
|
||||
* - ModSec-key
|
||||
*
|
||||
* @warning Cleanup the memory after use it.
|
||||
*
|
||||
* @param mp pointer to the memory pool.
|
||||
* @param uri URI to be fetched.
|
||||
* @param key KEY to be present as ModSec-key.
|
||||
* @param chunk pointer to an msc_curl_memory_buffer_t struct.
|
||||
* @param error_msg pointer an char pointer, filled is something went wrong.
|
||||
*
|
||||
* @retval n>=0 everything went fine.
|
||||
* @retval n<-1 Something wrong happened, further details on error_msg.
|
||||
* n=-2 Download failed, but operation should not be aborted.
|
||||
* n=-3 ModSecurity was not compiled with curl support.
|
||||
*
|
||||
*/
|
||||
int msc_remote_download_content(apr_pool_t *mp, const char *uri, const char *key,
|
||||
struct msc_curl_memory_buffer_t *chunk, char **error_msg)
|
||||
{
|
||||
#ifdef WITH_CURL
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
char id[(APR_SHA1_DIGESTSIZE*2) + 1];
|
||||
char *apr_id = NULL;
|
||||
char *beacon_str = NULL;
|
||||
char *beacon_apr = NULL;
|
||||
int beacon_str_len = 0;
|
||||
int ret = 0;
|
||||
|
||||
chunk->size = 0;
|
||||
|
||||
memset(id, '\0', sizeof(id));
|
||||
if (msc_status_engine_unique_id(id))
|
||||
{
|
||||
sprintf(id, "no unique id");
|
||||
}
|
||||
|
||||
apr_id = apr_psprintf(mp, "ModSec-unique-id: %s", id);
|
||||
|
||||
curl = curl_easy_init();
|
||||
|
||||
beacon_str_len = msc_beacon_string(NULL, 0);
|
||||
|
||||
beacon_str = malloc(sizeof(char) * beacon_str_len + 1);
|
||||
if (beacon_str == NULL)
|
||||
{
|
||||
beacon_str = "Failed to retrieve beacon string";
|
||||
beacon_apr = apr_psprintf(mp, "ModSec-status: %s", beacon_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
msc_beacon_string(beacon_str, beacon_str_len);
|
||||
beacon_apr = apr_psprintf(mp, "ModSec-status: %s", beacon_str);
|
||||
free(beacon_str);
|
||||
}
|
||||
|
||||
if (curl)
|
||||
{
|
||||
struct curl_slist *headers_chunk = NULL;
|
||||
#ifdef WIN32
|
||||
char *buf = malloc(sizeof(TCHAR) * (2048 + 1));
|
||||
char *ptr = NULL;
|
||||
DWORD res_len;
|
||||
#endif
|
||||
curl_easy_setopt(curl, CURLOPT_URL, uri);
|
||||
|
||||
headers_chunk = curl_slist_append(headers_chunk, apr_id);
|
||||
headers_chunk = curl_slist_append(headers_chunk, beacon_apr);
|
||||
if (key != NULL)
|
||||
{
|
||||
char *header_key = NULL;
|
||||
header_key = apr_psprintf(mp, "ModSec-key: %s", key);
|
||||
headers_chunk = curl_slist_append(headers_chunk, header_key);
|
||||
}
|
||||
|
||||
/* Make it TLS 1.x only. */
|
||||
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
|
||||
|
||||
#ifdef WIN32
|
||||
res_len = SearchPathA(NULL, "curl-ca-bundle.crt", NULL, (2048 + 1), buf, &ptr);
|
||||
if (res_len > 0) {
|
||||
curl_easy_setopt(curl, CURLOPT_CAINFO, strdup(buf));
|
||||
}
|
||||
free(buf);
|
||||
#endif
|
||||
|
||||
/* those are the default options, but lets make sure */
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
|
||||
/* send all data to this function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, msc_curl_write_memory_cb);
|
||||
|
||||
/* we pass our 'chunk' struct to the callback function */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, "modesecurity");
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers_chunk);
|
||||
|
||||
/* We want Curl to return error in case there is an HTTP error code */
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if (res != CURLE_OK)
|
||||
{
|
||||
if (remote_rules_fail_action == REMOTE_RULES_WARN_ON_FAIL)
|
||||
{
|
||||
if (remote_rules_fail_message == NULL)
|
||||
{
|
||||
remote_rules_fail_message = "";
|
||||
}
|
||||
|
||||
remote_rules_fail_message = apr_psprintf(mp, "%sFailed to " \
|
||||
"download: \"%s\" error: %s. ",
|
||||
remote_rules_fail_message, uri,
|
||||
curl_easy_strerror(res));
|
||||
|
||||
ret = -2;
|
||||
goto failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
*error_msg = apr_psprintf(mp, "Failed to download: \"%s\" " \
|
||||
"error: %s ",
|
||||
uri, curl_easy_strerror(res));
|
||||
|
||||
ret = -1;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
curl_slist_free_all(headers_chunk);
|
||||
}
|
||||
|
||||
failed:
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return -3;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Setup an apr_crypto_key_t from a given password and salt.
|
||||
*
|
||||
* apr_crypto_* demands the key to be in a format of an apr_crypto_key_t which
|
||||
* is an structure that may be defined depending on the crypto provider, thus,
|
||||
* making necessary for us to create this structure using apr internal
|
||||
* functions.
|
||||
*
|
||||
* @warning We trust that the paramenter used in apr, such as the algorithm,
|
||||
* key size and other parameters won't change, if they do it may
|
||||
* break the interoperability with this function with others
|
||||
* implementations, as the key will end up with a different value
|
||||
* than the one expected.
|
||||
*
|
||||
* @param pool pointer to the memory pool to be used.
|
||||
* @param key password to be used while creating the key.
|
||||
* @param apr_key pointer to the pointer of an apr_crypto_key_t structure.
|
||||
* @param f pointer to apr_crypto_t.
|
||||
* @param salt string to be used as salt of the key generation
|
||||
* @param error_msg pointer to char pointer, which is filled if something
|
||||
* went wrong.
|
||||
*
|
||||
* @retval n>=0 everything went fine.
|
||||
* @retval n<-1 Something wrong happened, check error_msg for further details.
|
||||
*
|
||||
*/
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
int msc_remote_enc_key_setup(apr_pool_t *pool,
|
||||
const char *key,
|
||||
apr_crypto_key_t **apr_key,
|
||||
apr_crypto_t *f,
|
||||
unsigned char *salt,
|
||||
char **error_msg)
|
||||
{
|
||||
apr_size_t key_len = strlen(key);
|
||||
apr_size_t salt_len = 16; //FIXME: salt_len should not be hard coded.
|
||||
|
||||
const int do_pad = 1;
|
||||
apr_status_t rv;
|
||||
|
||||
rv = apr_crypto_passphrase(
|
||||
(apr_crypto_key_t **) apr_key,
|
||||
NULL,
|
||||
(const char *) key,
|
||||
(apr_size_t) key_len,
|
||||
(const unsigned char *) salt,
|
||||
(apr_size_t) salt_len,
|
||||
APR_KEY_AES_256,
|
||||
APR_MODE_CBC,
|
||||
(const int) do_pad,
|
||||
(const int) 4096,
|
||||
(const apr_crypto_t *) f,
|
||||
(apr_pool_t *) pool);
|
||||
|
||||
if (rv == APR_ENOKEY)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_passphrase: Missing key";
|
||||
return -1;
|
||||
}
|
||||
else if (rv == APR_EPADDING)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_passphrase: APR_EPADDING";
|
||||
return -1;
|
||||
}
|
||||
else if (rv == APR_EKEYTYPE)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_passphrase: APR_EKEYTYPE";
|
||||
return -1;
|
||||
}
|
||||
else if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_passphrase: Unknown error";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Decrypt an buffer into a memory buffer.
|
||||
*
|
||||
* Decrypt an msc_curl_memory_buffer_t structure into another
|
||||
* msc_curl_memory_buffer_t.
|
||||
*
|
||||
* Using the key provided, it creates and apr_key and uses it to decript the
|
||||
* content provided on chunk. The plain text content is saved under
|
||||
* chunk_plain.
|
||||
*
|
||||
* @warning Cleanup memory after usage.
|
||||
*
|
||||
* @param pool pointer to the memory pool to be used.
|
||||
* @param key pointer to the char array to be used as the key.
|
||||
* @param chunk msc_curl_memory_buffer_t that contains the encrypted content.
|
||||
* @param plain_text unsigned char which will hold the content of an url
|
||||
* @param plain_text_len size of the plain_text buffer
|
||||
* @param error_msg pointer to char pointer that is filled if something went
|
||||
* wrong.
|
||||
*
|
||||
* @retval n>=0 everything went fine.
|
||||
* @retval n<-1 Something wrong happened, further details on error_msg.
|
||||
*
|
||||
*/
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
int msc_remote_decrypt(apr_pool_t *pool,
|
||||
const char *key,
|
||||
struct msc_curl_memory_buffer_t *chunk,
|
||||
unsigned char **plain_text,
|
||||
apr_size_t *plain_text_len,
|
||||
char **error_msg)
|
||||
{
|
||||
apr_crypto_key_t *apr_key = NULL;
|
||||
apr_crypto_t *f = NULL;
|
||||
const apr_crypto_driver_t *driver = NULL;
|
||||
const apu_err_t *err = NULL;
|
||||
apr_status_t rv;
|
||||
unsigned char *iv = NULL;
|
||||
unsigned char *ciphered_text = NULL;
|
||||
unsigned char *salt = NULL;
|
||||
|
||||
apr_crypto_block_t *block = NULL;
|
||||
apr_size_t block_size = 0;
|
||||
apr_size_t len = 0;
|
||||
|
||||
// FIXME: size should not be hardcoded.
|
||||
// at least size of IV + Salt
|
||||
if (chunk->size < 16+16+1)
|
||||
{
|
||||
*error_msg = "Failed to download rules from a remote server: " \
|
||||
"Unexpected content.";
|
||||
return -1;
|
||||
}
|
||||
iv = chunk->memory;
|
||||
salt = chunk->memory + 16;
|
||||
ciphered_text = chunk->memory + (16 + 16);
|
||||
|
||||
rv = apr_crypto_init(pool);
|
||||
if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error: failed to init crypto";
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = apr_crypto_get_driver(&driver, APU_CRYPTO_RECOMMENDED_DRIVER, NULL,
|
||||
&err, pool);
|
||||
|
||||
if (rv != APR_SUCCESS || driver == NULL)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_get_driver: Unknown error";
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = apr_crypto_make(&f, driver, NULL, pool);
|
||||
if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_make: Unknown error";
|
||||
return -1;
|
||||
}
|
||||
|
||||
msc_remote_enc_key_setup(pool, key, &apr_key, f, salt, error_msg);
|
||||
if (*error_msg != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = apr_crypto_block_decrypt_init(&block, &block_size, iv, apr_key, pool);
|
||||
if (rv == APR_ENOKEY)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_init: " \
|
||||
"Missing key";
|
||||
return -1;
|
||||
}
|
||||
else if (rv == APR_ENOIV)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_init: " \
|
||||
"Missing IV";
|
||||
return -1;
|
||||
}
|
||||
else if (rv == APR_EKEYTYPE)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_init: " \
|
||||
"Wrong key type";
|
||||
return -1;
|
||||
}
|
||||
else if (rv == APR_EKEYLENGTH)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_init: " \
|
||||
"Wrong key length";
|
||||
return -1;
|
||||
}
|
||||
else if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_init: " \
|
||||
"Unknown error";
|
||||
return -1;
|
||||
}
|
||||
|
||||
//FIXME: size should not be hardcoded like that.
|
||||
// 32 = iv + salt size.
|
||||
rv = apr_crypto_block_decrypt(plain_text, plain_text_len,
|
||||
ciphered_text, (apr_size_t) chunk->size - (16 + 16) ,
|
||||
block);
|
||||
|
||||
if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt: Failed to " \
|
||||
"decrypt";
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* finalise the decryption */
|
||||
|
||||
rv = apr_crypto_block_decrypt_finish(*plain_text + *plain_text_len, &len,
|
||||
block);
|
||||
if (rv != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = "Internal error - apr_crypto_block_decrypt_finish: " \
|
||||
"Failed to decrypt";
|
||||
return -1;
|
||||
}
|
||||
|
||||
apr_crypto_block_cleanup(block);
|
||||
apr_crypto_cleanup(f);
|
||||
|
||||
// Shutdown the apr_crypto seems to be the correct thing to do.
|
||||
// However it seems to add instability especially if mod_ssl is enabled.
|
||||
// apr_crypto_shutdown(driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Add SecRules from a given URI.
|
||||
*
|
||||
* Fetch the URI and using the key provided into params decrypt and install
|
||||
* the downloaded set of rules.
|
||||
*
|
||||
* @warning Cleanup the memory may be necessary.
|
||||
*
|
||||
* @param orig_parms origin parms used at SecRemoteRule
|
||||
* @param remote_rules_server pointer to the filled msc_remote_rules_server
|
||||
* structure.
|
||||
* @param error_msg pointer to char pointer that will be filled if something
|
||||
* went wrong.
|
||||
*
|
||||
*
|
||||
* @retval n>=0 everything went fine.
|
||||
* @retval n<-1 Something wrong happened, further details on error_msg.
|
||||
*
|
||||
*/
|
||||
int msc_remote_add_rules_from_uri(cmd_parms *orig_parms,
|
||||
msc_remote_rules_server *remote_rules_server,
|
||||
char **error_msg)
|
||||
{
|
||||
|
||||
#ifdef WITH_REMOTE_RULES
|
||||
struct msc_curl_memory_buffer_t downloaded_content;
|
||||
unsigned char *plain_text = NULL;
|
||||
int len = 0;
|
||||
int start = 0;
|
||||
int end = 0;
|
||||
int added_rules = 0;
|
||||
int res = 0;
|
||||
apr_size_t plain_text_len = 0;
|
||||
|
||||
apr_pool_t *mp = orig_parms->pool;
|
||||
|
||||
downloaded_content.size = 0;
|
||||
downloaded_content.memory = NULL;
|
||||
|
||||
res = msc_remote_download_content(mp, remote_rules_server->uri,
|
||||
remote_rules_server->key, &downloaded_content, error_msg);
|
||||
if (*error_msg != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
/* error_msg is not filled when the user set SecRemoteRulesFailAction
|
||||
* to warn
|
||||
*/
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
if (remote_rules_server->crypto == 1)
|
||||
{
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
msc_remote_decrypt(mp, remote_rules_server->key, &downloaded_content,
|
||||
&plain_text,
|
||||
&plain_text_len,
|
||||
error_msg);
|
||||
|
||||
if (*error_msg != NULL)
|
||||
{
|
||||
msc_remote_clean_chunk(&downloaded_content);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
*error_msg = "ModSecurity was not compiled with crypto support.\n";
|
||||
msc_remote_clean_chunk(&downloaded_content);
|
||||
return -1;
|
||||
#endif
|
||||
msc_remote_clean_chunk(&downloaded_content);
|
||||
}
|
||||
else
|
||||
{
|
||||
plain_text = downloaded_content.memory;
|
||||
plain_text_len = strlen(plain_text);
|
||||
}
|
||||
|
||||
len = 0;
|
||||
plain_text_len = strlen(plain_text);
|
||||
while (len < plain_text_len)
|
||||
{
|
||||
if (plain_text[len] == '\n')
|
||||
{
|
||||
const char *rule = NULL;
|
||||
int tmp = len;
|
||||
char *cmd_name = NULL;
|
||||
char *word = NULL;
|
||||
const command_rec *cmd;
|
||||
|
||||
ap_directive_t *newdir;
|
||||
cmd_parms *parms = apr_pcalloc(mp, sizeof (cmd_parms));
|
||||
|
||||
rule = plain_text + start;
|
||||
end = len;
|
||||
plain_text[len] = '\0';
|
||||
|
||||
memcpy(parms, orig_parms, sizeof(cmd_parms));
|
||||
|
||||
if (*rule == '#' || *rule == '\0')
|
||||
{
|
||||
goto next;
|
||||
}
|
||||
|
||||
cmd_name = ap_getword_conf(mp, &rule);
|
||||
cmd = msc_remote_find_command(cmd_name, security2_module.cmds);
|
||||
|
||||
if (cmd == NULL)
|
||||
{
|
||||
*error_msg = apr_pstrcat(mp, "Unknown command in config: ",
|
||||
cmd_name, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
newdir = apr_pcalloc(mp, sizeof(ap_directive_t));
|
||||
newdir->filename = "remote server";
|
||||
newdir->line_num = -1;
|
||||
newdir->directive = cmd_name;
|
||||
newdir->args = apr_pstrdup(mp, rule);
|
||||
parms->directive = newdir;
|
||||
|
||||
#ifdef WIN32
|
||||
// some config commands fail in APR when there are file
|
||||
// permission issues or other OS-specific problems
|
||||
//
|
||||
__try
|
||||
{
|
||||
#endif
|
||||
*error_msg = (char *) msc_remote_invoke_cmd(cmd, parms,
|
||||
remote_rules_server->context, rule);
|
||||
if (*error_msg != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
added_rules++;
|
||||
#ifdef WIN32
|
||||
}
|
||||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
*error_msg = "Command failed to execute (check file/folder" \
|
||||
"permissions, syntax, etc.).";
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
next:
|
||||
start = end + 1;
|
||||
}
|
||||
len++;
|
||||
}
|
||||
|
||||
remote_rules_server->amount_of_rules = added_rules;
|
||||
|
||||
if (remote_rules_server->crypto != 1)
|
||||
{
|
||||
msc_remote_clean_chunk(&downloaded_content);
|
||||
}
|
||||
#else
|
||||
*error_msg = "SecRemoteRules was not enabled during ModSecurity " \
|
||||
"compilation.";
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int msc_remote_clean_chunk(struct msc_curl_memory_buffer_t *chunk)
|
||||
{
|
||||
if (chunk->size == 0)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (chunk->memory == NULL)
|
||||
{
|
||||
goto end;
|
||||
}
|
||||
|
||||
free(chunk->memory);
|
||||
chunk->size = 0;
|
||||
|
||||
end:
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef MSC_REMOTE_RULES_H
|
||||
#define MSC_REMOTE_RULES_H
|
||||
|
||||
/* forward declarations */
|
||||
typedef struct msc_remote_rules_server msc_remote_rules_server;
|
||||
struct msc_curl_memory_buffer_t;
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
#include <apr_general.h>
|
||||
#include <apr_optional.h>
|
||||
#include <apr_thread_pool.h>
|
||||
#include <apr_sha1.h>
|
||||
|
||||
#include "http_core.h"
|
||||
#include "http_config.h"
|
||||
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
#include <apr_crypto.h>
|
||||
#endif
|
||||
|
||||
struct msc_remote_rules_server {
|
||||
directory_config *context;
|
||||
const char *context_label;
|
||||
const char *uri;
|
||||
const char *key;
|
||||
int amount_of_rules;
|
||||
int crypto;
|
||||
};
|
||||
|
||||
const char *msc_remote_invoke_cmd(const command_rec *cmd, cmd_parms *parms,
|
||||
void *mconfig, const char *args);
|
||||
|
||||
int msc_remote_download_content(apr_pool_t *mp, const char *uri, const char *key,
|
||||
struct msc_curl_memory_buffer_t *chunk, char **error_msg);
|
||||
|
||||
#ifdef WITH_APU_CRYPTO
|
||||
int msc_remote_enc_key_setup(apr_pool_t *pool,
|
||||
const char *key,
|
||||
apr_crypto_key_t **apr_key,
|
||||
apr_crypto_t *f,
|
||||
unsigned char *salt,
|
||||
char **error_msg);
|
||||
|
||||
int msc_remote_decrypt(apr_pool_t *pool,
|
||||
const char *key,
|
||||
struct msc_curl_memory_buffer_t *chunk,
|
||||
unsigned char **plain_text,
|
||||
apr_size_t *plain_text_len,
|
||||
char **error_msg);
|
||||
#endif
|
||||
|
||||
int msc_remote_add_rules_from_uri(cmd_parms *orig_parms,
|
||||
msc_remote_rules_server *remote_rules_server,
|
||||
char **error_msg);
|
||||
|
||||
int msc_remote_clean_chunk(struct msc_curl_memory_buffer_t *chunk);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,946 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include "re.h"
|
||||
#include "msc_parsers.h"
|
||||
|
||||
#define CHUNK_CAPACITY 8192
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void msre_engine_reqbody_processor_register(msre_engine *engine,
|
||||
const char *name, void *fn_init, void *fn_process, void *fn_complete)
|
||||
{
|
||||
msre_reqbody_processor_metadata *metadata =
|
||||
(msre_reqbody_processor_metadata *)apr_pcalloc(engine->mp,
|
||||
sizeof(msre_reqbody_processor_metadata));
|
||||
if (metadata == NULL) return;
|
||||
|
||||
metadata->name = name;
|
||||
metadata->init = fn_init;
|
||||
metadata->process = fn_process;
|
||||
metadata->complete = fn_complete;
|
||||
apr_table_setn(engine->reqbody_processors, name, (void *)metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to accept the request body (part 2).
|
||||
*/
|
||||
static apr_status_t modsecurity_request_body_start_init(modsec_rec *msr, char **error_msg) {
|
||||
*error_msg = NULL;
|
||||
|
||||
if(msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||
/* Prepare to store request body in memory. */
|
||||
|
||||
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp,
|
||||
32, sizeof(msc_data_chunk *));
|
||||
if (msr->msc_reqbody_chunks == NULL) {
|
||||
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to prepare in-memory storage.");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Prepare to store request body on disk. */
|
||||
|
||||
msr->msc_reqbody_filename = apr_psprintf(msr->mp, "%s/%s-%s-request_body-XXXXXX",
|
||||
msr->txcfg->tmp_dir, current_filetime(msr->mp), msr->txid);
|
||||
if (msr->msc_reqbody_filename == NULL) {
|
||||
*error_msg = apr_pstrdup(msr->mp, "Input filter: Failed to generate an on-disk filename.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_fd = msc_mkstemp((char *)msr->msc_reqbody_filename);
|
||||
if (msr->msc_reqbody_fd < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to create temporary file: %s",
|
||||
msr->msc_reqbody_filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr_log(msr, 4, "Input filter: Created temporary file to store request body: %s",
|
||||
msr->msc_reqbody_filename);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to accept the request body (part 1).
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_start(modsec_rec *msr, char **error_msg) {
|
||||
*error_msg = NULL;
|
||||
msr->msc_reqbody_length = 0;
|
||||
msr->stream_input_length = 0;
|
||||
|
||||
/* Create a separate memory pool that will be used
|
||||
* to allocate structures from (not data, which is allocated
|
||||
* via malloc).
|
||||
*/
|
||||
apr_pool_create(&msr->msc_reqbody_mp, NULL);
|
||||
|
||||
/* Initialise request body processors, if any. */
|
||||
|
||||
if (msr->msc_reqbody_processor != NULL) {
|
||||
char *my_error_msg = NULL;
|
||||
msre_reqbody_processor_metadata *metadata =
|
||||
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
||||
|
||||
if (metadata != NULL) {
|
||||
if ( (metadata->init != NULL)
|
||||
&& (metadata->init(msr, &my_error_msg) < 0))
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp,
|
||||
"%s parsing error (init): %s",
|
||||
msr->msc_reqbody_processor,
|
||||
my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
// TODO: All these below need to be registered in the same way as above
|
||||
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||
if (multipart_init(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error (init): %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||
if (xml_init(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML parsing error (init): %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||
#ifdef WITH_YAJL
|
||||
if (json_init(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON parsing error (init): %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
#else
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||
/* Do nothing, URLENCODED processor does not support streaming yet. */
|
||||
}
|
||||
else {
|
||||
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
||||
msr->msc_reqbody_processor);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return modsecurity_request_body_start_init(msr, error_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a chunk of request body data to disk.
|
||||
*/
|
||||
static apr_status_t modsecurity_request_body_store_disk(modsec_rec *msr,
|
||||
const char *data, apr_size_t length, char **error_msg)
|
||||
{
|
||||
apr_size_t i;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
i = write(msr->msc_reqbody_fd, data, length);
|
||||
if (i != length) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed writing %" APR_SIZE_T_FMT
|
||||
" bytes to temporary file (rc %" APR_SIZE_T_FMT ").", length, i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores one chunk of request body data in memory.
|
||||
*/
|
||||
static apr_status_t modsecurity_request_body_store_memory(modsec_rec *msr,
|
||||
const char *data, apr_size_t length, char **error_msg)
|
||||
{
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Would storing this chunk mean going over the limit? */
|
||||
if ((msr->msc_reqbody_spilltodisk)
|
||||
&& (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_ON)
|
||||
&& (msr->msc_reqbody_length + length > (apr_size_t)msr->txcfg->reqbody_inmemory_limit))
|
||||
{
|
||||
msc_data_chunk **chunks;
|
||||
unsigned int disklen = 0;
|
||||
int i;
|
||||
|
||||
msr_log(msr, 4, "Input filter: Request too large to store in memory, switching to disk.");
|
||||
|
||||
/* NOTE Must use modsecurity_request_body_store_disk() here
|
||||
* to prevent data to be sent to the streaming
|
||||
* processors again.
|
||||
*/
|
||||
|
||||
/* Initialise disk storage */
|
||||
msr->msc_reqbody_storage = MSC_REQBODY_DISK;
|
||||
if (modsecurity_request_body_start_init(msr, error_msg) < 0) return -1;
|
||||
|
||||
/* Write the data we keep in memory */
|
||||
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
||||
disklen += chunks[i]->length;
|
||||
|
||||
if (modsecurity_request_body_store_disk(msr, chunks[i]->data, chunks[i]->length, error_msg) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(chunks[i]->data);
|
||||
chunks[i]->data = NULL;
|
||||
}
|
||||
|
||||
/* Clear the memory pool as we no longer need the bits. */
|
||||
|
||||
/* IMP1 But since we only used apr_pool_clear memory might
|
||||
* not be released back to the OS straight away?
|
||||
*/
|
||||
msr->msc_reqbody_chunks = NULL;
|
||||
apr_pool_clear(msr->msc_reqbody_mp);
|
||||
|
||||
msr_log(msr, 4, "Input filter: Wrote %u bytes from memory to disk.", disklen);
|
||||
|
||||
/* Continue with disk storage from now on */
|
||||
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
||||
}
|
||||
|
||||
/* If we're here that means we are not over the
|
||||
* request body in-memory limit yet.
|
||||
*/
|
||||
{
|
||||
unsigned long int bucket_offset, bucket_left;
|
||||
|
||||
bucket_offset = 0;
|
||||
bucket_left = length;
|
||||
|
||||
/* Although we store the request body in chunks we don't
|
||||
* want to use the same chunk sizes as the incoming memory
|
||||
* buffers. They are often of very small sizes and that
|
||||
* would make us waste a lot of memory. That's why we
|
||||
* use our own chunks of CHUNK_CAPACITY sizes.
|
||||
*/
|
||||
|
||||
/* Loop until we empty this bucket into our chunks. */
|
||||
while(bucket_left > 0) {
|
||||
/* Allocate a new chunk if we have to. */
|
||||
if (msr->msc_reqbody_chunk_current == NULL) {
|
||||
msr->msc_reqbody_chunk_current = (msc_data_chunk *)
|
||||
apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||
if (msr->msc_reqbody_chunk_current == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %lu bytes "
|
||||
"for request body chunk.", (unsigned long)sizeof(msc_data_chunk));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_chunk_current->data = malloc(CHUNK_CAPACITY);
|
||||
if (msr->msc_reqbody_chunk_current->data == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to allocate %d bytes "
|
||||
"for request body chunk data.", CHUNK_CAPACITY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_chunk_current->length = 0;
|
||||
msr->msc_reqbody_chunk_current->is_permanent = 1;
|
||||
|
||||
*(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks)
|
||||
= msr->msc_reqbody_chunk_current;
|
||||
}
|
||||
|
||||
if (bucket_left < (CHUNK_CAPACITY - msr->msc_reqbody_chunk_current->length)) {
|
||||
/* There's enough space in the current chunk. */
|
||||
memcpy(msr->msc_reqbody_chunk_current->data +
|
||||
msr->msc_reqbody_chunk_current->length, data + bucket_offset, bucket_left);
|
||||
msr->msc_reqbody_chunk_current->length += bucket_left;
|
||||
bucket_left = 0;
|
||||
} else {
|
||||
/* Fill the existing chunk. */
|
||||
unsigned long int copy_length = CHUNK_CAPACITY -
|
||||
msr->msc_reqbody_chunk_current->length;
|
||||
|
||||
memcpy(msr->msc_reqbody_chunk_current->data +
|
||||
msr->msc_reqbody_chunk_current->length, data + bucket_offset, copy_length);
|
||||
bucket_offset += copy_length;
|
||||
bucket_left -= copy_length;
|
||||
msr->msc_reqbody_chunk_current->length += copy_length;
|
||||
|
||||
/* We're done with this chunk. Setting the pointer
|
||||
* to NULL is going to force a new chunk to be allocated
|
||||
* on the next go.
|
||||
*/
|
||||
msr->msc_reqbody_chunk_current = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
msr->msc_reqbody_length += length;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores one chunk of request body data. Returns -1 on error.
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_store(modsec_rec *msr,
|
||||
const char *data, apr_size_t length, char **error_msg)
|
||||
{
|
||||
*error_msg = NULL;
|
||||
|
||||
/* If we have a processor for this request body send
|
||||
* data to it first (but only if it did not report an
|
||||
* error on previous invocations).
|
||||
*/
|
||||
if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
|
||||
char *my_error_msg = NULL;
|
||||
msre_reqbody_processor_metadata *metadata =
|
||||
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
||||
|
||||
if (metadata != NULL) {
|
||||
if ( (metadata->process != NULL)
|
||||
&& (metadata->process(msr, data, length, &my_error_msg) < 0))
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp,
|
||||
"%s parsing error: %s",
|
||||
msr->msc_reqbody_processor,
|
||||
my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
// TODO: All these below need to be registered in the same way as above
|
||||
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||
/* The per-request data length counter will
|
||||
* be updated by the multipart parser.
|
||||
*/
|
||||
|
||||
/* Process data as multipart/form-data. */
|
||||
if (multipart_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||
/* Increase per-request data length counter. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
|
||||
/* Process data as XML. */
|
||||
if (xml_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML parsing error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||
/* Increase per-request data length counter. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
|
||||
/* Process data as JSON. */
|
||||
#ifdef WITH_YAJL
|
||||
if (json_process_chunk(msr, data, length, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON parsing error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
#else
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||
/* Increase per-request data length counter. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
|
||||
/* Do nothing else, URLENCODED processor does not support streaming. */
|
||||
}
|
||||
else {
|
||||
*error_msg = apr_psprintf(msr->mp, "Unknown request body processor: %s",
|
||||
msr->msc_reqbody_processor);
|
||||
return -1;
|
||||
}
|
||||
} else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
|
||||
/* Increase per-request data length counter if forcing buffering. */
|
||||
msr->msc_reqbody_no_files_length += length;
|
||||
}
|
||||
|
||||
/* Check that we are not over the request body no files limit. */
|
||||
if (msr->msc_reqbody_no_files_length >= (unsigned long) msr->txcfg->reqbody_no_files_limit) {
|
||||
|
||||
*error_msg = apr_psprintf(msr->mp, "Request body no files data length is larger than the "
|
||||
"configured limit (%ld).", msr->txcfg->reqbody_no_files_limit);
|
||||
if (msr->txcfg->debuglog_level >= 1) {
|
||||
msr_log(msr, 1, "%s", *error_msg);
|
||||
}
|
||||
|
||||
if ((msr->txcfg->is_enabled == MODSEC_ENABLED) && (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_REJECT)) {
|
||||
return -5;
|
||||
} else if (msr->txcfg->if_limit_action == REQUEST_BODY_LIMIT_ACTION_PARTIAL) {
|
||||
if(msr->txcfg->is_enabled == MODSEC_ENABLED)
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Store data. */
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||
return modsecurity_request_body_store_memory(msr, data, length, error_msg);
|
||||
}
|
||||
else
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
return modsecurity_request_body_store_disk(msr, data, length, error_msg);
|
||||
}
|
||||
|
||||
/* Should never happen. */
|
||||
*error_msg = apr_psprintf(msr->mp, "Internal error, unknown value for msc_reqbody_storage: %u",
|
||||
msr->msc_reqbody_storage);
|
||||
return -1;
|
||||
}
|
||||
|
||||
apr_status_t modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg) {
|
||||
char *stream_input_body = NULL;
|
||||
char *data = NULL;
|
||||
int first_pkt = 0;
|
||||
|
||||
if(msr->stream_input_data == NULL) {
|
||||
msr->stream_input_data = (char *)calloc(sizeof(char), msr->stream_input_length + 1);
|
||||
first_pkt = 1;
|
||||
}
|
||||
else {
|
||||
|
||||
data = (char *)malloc(msr->stream_input_length + 1 - buflen);
|
||||
|
||||
if(data == NULL)
|
||||
return -1;
|
||||
|
||||
memset(data, 0, msr->stream_input_length + 1 - buflen);
|
||||
memcpy(data, msr->stream_input_data, msr->stream_input_length - buflen);
|
||||
|
||||
stream_input_body = (char *)realloc(msr->stream_input_data, msr->stream_input_length + 1);
|
||||
|
||||
msr->stream_input_data = (char *)stream_input_body;
|
||||
}
|
||||
|
||||
if (msr->stream_input_data == NULL) {
|
||||
if(data) {
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body on stream. Asked for %" APR_SIZE_T_FMT " bytes.",
|
||||
msr->stream_input_length + 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(msr->stream_input_data, 0, msr->stream_input_length+1);
|
||||
|
||||
if(first_pkt) {
|
||||
memcpy(msr->stream_input_data, buffer, msr->stream_input_length);
|
||||
} else {
|
||||
memcpy(msr->stream_input_data, data, msr->stream_input_length - buflen);
|
||||
memcpy(msr->stream_input_data+(msr->stream_input_length - buflen), buffer, buflen);
|
||||
}
|
||||
|
||||
if(data) {
|
||||
free(data);
|
||||
data = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* Replace a bunch of chunks holding a request body with a single large chunk.
|
||||
*/
|
||||
static apr_status_t modsecurity_request_body_end_raw(modsec_rec *msr, char **error_msg) {
|
||||
msc_data_chunk **chunks, *one_chunk;
|
||||
char *d;
|
||||
int i, sofar;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Allocate a buffer large enough to hold the request body. */
|
||||
|
||||
if (msr->msc_reqbody_length + 1 == 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Internal error, request body length will overflow: %u",
|
||||
msr->msc_reqbody_length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_buffer = malloc(msr->msc_reqbody_length + 1);
|
||||
if (msr->msc_reqbody_buffer == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Unable to allocate memory to hold request body. Asked for %u bytes.",
|
||||
msr->msc_reqbody_length + 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_buffer[msr->msc_reqbody_length] = '\0';
|
||||
|
||||
/* Copy the data we keep in chunks into the new buffer. */
|
||||
|
||||
sofar = 0;
|
||||
d = msr->msc_reqbody_buffer;
|
||||
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
||||
if (sofar + chunks[i]->length <= msr->msc_reqbody_length) {
|
||||
memcpy(d, chunks[i]->data, chunks[i]->length);
|
||||
d += chunks[i]->length;
|
||||
sofar += chunks[i]->length;
|
||||
} else {
|
||||
*error_msg = apr_psprintf(msr->mp, "Internal error, request body buffer overflow.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Now free the memory used by the chunks. */
|
||||
|
||||
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
||||
free(chunks[i]->data);
|
||||
chunks[i]->data = NULL;
|
||||
}
|
||||
|
||||
/* Create a new array with only one chunk in it. */
|
||||
|
||||
msr->msc_reqbody_chunks = apr_array_make(msr->msc_reqbody_mp, 2, sizeof(msc_data_chunk *));
|
||||
if (msr->msc_reqbody_chunks == NULL) {
|
||||
*error_msg = apr_pstrdup(msr->mp, "Failed to create structure to hold request body.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
one_chunk = (msc_data_chunk *)apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||
one_chunk->data = msr->msc_reqbody_buffer;
|
||||
one_chunk->length = msr->msc_reqbody_length;
|
||||
one_chunk->is_permanent = 1;
|
||||
*(const msc_data_chunk **)apr_array_push(msr->msc_reqbody_chunks) = one_chunk;
|
||||
|
||||
if(msr->txcfg->reqbody_limit > 0 && msr->txcfg->reqbody_limit < msr->msc_reqbody_length) {
|
||||
msr->msc_reqbody_length = msr->txcfg->reqbody_limit;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_status_t modsecurity_request_body_end_urlencoded(modsec_rec *msr, char **error_msg) {
|
||||
int invalid_count = 0;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Create the raw buffer */
|
||||
if (modsecurity_request_body_end_raw(msr, error_msg) != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Parse URL-encoded arguments in the request body. */
|
||||
|
||||
if (parse_arguments(msr, msr->msc_reqbody_buffer, msr->msc_reqbody_length,
|
||||
msr->txcfg->argument_separator, "BODY", msr->arguments, &invalid_count) < 0)
|
||||
{
|
||||
*error_msg = apr_pstrdup(msr->mp, "Initialisation: Error occurred while parsing BODY arguments.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (invalid_count) {
|
||||
msr->urlencoded_error = 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops receiving the request body.
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_end(modsec_rec *msr, char **error_msg) {
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Close open file descriptors, if any. */
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
if (msr->msc_reqbody_fd > 0) {
|
||||
close(msr->msc_reqbody_fd);
|
||||
msr->msc_reqbody_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that we've read the body. */
|
||||
msr->msc_reqbody_read = 1;
|
||||
|
||||
/* Finalise body processing. */
|
||||
if ((msr->msc_reqbody_processor != NULL) && (msr->msc_reqbody_error == 0)) {
|
||||
char *my_error_msg = NULL;
|
||||
msre_reqbody_processor_metadata *metadata =
|
||||
(msre_reqbody_processor_metadata *)apr_table_get(msr->modsecurity->msre->reqbody_processors, msr->msc_reqbody_processor);
|
||||
|
||||
if (metadata != NULL) {
|
||||
if ( (metadata->complete != NULL)
|
||||
&& (metadata->complete(msr, &my_error_msg) < 0))
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp,
|
||||
"%s parsing error (complete): %s",
|
||||
msr->msc_reqbody_processor,
|
||||
my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = my_error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
}
|
||||
}
|
||||
// TODO: All these below need to be registered in the same way as above
|
||||
else if (strcmp(msr->msc_reqbody_processor, "MULTIPART") == 0) {
|
||||
if (multipart_complete(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Multipart parsing error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "%s", *error_msg);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (multipart_get_arguments(msr, "BODY", msr->arguments) < 0) {
|
||||
*error_msg = "Multipart parsing error: Failed to retrieve arguments.";
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "JSON") == 0) {
|
||||
#ifdef WITH_YAJL
|
||||
if (json_complete(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON parser error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
*error_msg = apr_psprintf(msr->mp, "JSON support was not enabled");
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "URLENCODED") == 0) {
|
||||
return modsecurity_request_body_end_urlencoded(msr, error_msg);
|
||||
}
|
||||
else if (strcmp(msr->msc_reqbody_processor, "XML") == 0) {
|
||||
if (xml_complete(msr, &my_error_msg) < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML parser error: %s", my_error_msg);
|
||||
msr->msc_reqbody_error = 1;
|
||||
msr->msc_reqbody_error_msg = *error_msg;
|
||||
msr_log(msr, 2, "%s", *error_msg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (msr->txcfg->reqbody_buffering != REQUEST_BODY_FORCEBUF_OFF) {
|
||||
/* Convert to a single continous buffer, but don't do anything else. */
|
||||
return modsecurity_request_body_end_raw(msr, error_msg);
|
||||
}
|
||||
|
||||
/* Note the request body no files length. */
|
||||
msr_log(msr, 4, "Request body no files length: %" APR_SIZE_T_FMT, msr->msc_reqbody_no_files_length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares to forward the request body.
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg) {
|
||||
*error_msg = NULL;
|
||||
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||
msr->msc_reqbody_chunk_position = 0;
|
||||
msr->msc_reqbody_chunk_offset = 0;
|
||||
|
||||
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||
if (msr->msc_reqbody_disk_chunk == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
|
||||
(unsigned long)sizeof(msc_data_chunk));
|
||||
return -1;
|
||||
}
|
||||
msr->msc_reqbody_disk_chunk->is_permanent = 1;
|
||||
}
|
||||
else
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
msr->msc_reqbody_disk_chunk = apr_pcalloc(msr->msc_reqbody_mp, sizeof(msc_data_chunk));
|
||||
if (msr->msc_reqbody_disk_chunk == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %lu bytes for request body disk chunk.",
|
||||
(unsigned long)sizeof(msc_data_chunk));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_disk_chunk->is_permanent = 0;
|
||||
msr->msc_reqbody_disk_chunk->data = apr_palloc(msr->msc_reqbody_mp, CHUNK_CAPACITY);
|
||||
if (msr->msc_reqbody_disk_chunk->data == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Failed to allocate %d bytes for request body disk chunk data.",
|
||||
CHUNK_CAPACITY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr->msc_reqbody_fd = open(msr->msc_reqbody_filename, O_RDONLY | O_BINARY);
|
||||
if (msr->msc_reqbody_fd < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Failed to open temporary file for reading: %s",
|
||||
msr->msc_reqbody_filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_retrieve_end(modsec_rec *msr) {
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
if (msr->msc_reqbody_fd > 0) {
|
||||
close(msr->msc_reqbody_fd);
|
||||
msr->msc_reqbody_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one chunk of request body data. It stores a NULL
|
||||
* in the chunk pointer when there is no data to return. The
|
||||
* return code is 1 if more calls can be made to retrieve more
|
||||
* data, 0 if there is no more data to retrieve, or -1 on error.
|
||||
*
|
||||
* The caller can limit the amount of data returned by providing
|
||||
* a non-negative value in nbytes.
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_retrieve(modsec_rec *msr,
|
||||
msc_data_chunk **chunk, long int nbytes, char **error_msg)
|
||||
{
|
||||
msc_data_chunk **chunks;
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
if (chunk == NULL) {
|
||||
*error_msg = apr_pstrdup(msr->mp, "Internal error, retrieving request body chunk.");
|
||||
return -1;
|
||||
}
|
||||
*chunk = NULL;
|
||||
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_MEMORY) {
|
||||
/* Are there any chunks left? */
|
||||
if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
|
||||
/* No more chunks. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We always respond with the same chunk, just different information in it. */
|
||||
*chunk = msr->msc_reqbody_disk_chunk;
|
||||
|
||||
/* Advance to the current chunk and position on the
|
||||
* next byte we need to send.
|
||||
*/
|
||||
chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||
msr->msc_reqbody_disk_chunk->data = chunks[msr->msc_reqbody_chunk_position]->data
|
||||
+ msr->msc_reqbody_chunk_offset;
|
||||
|
||||
if (nbytes < 0) {
|
||||
/* Send what's left in this chunk as there is no limit on the size. */
|
||||
msr->msc_reqbody_disk_chunk->length = chunks[msr->msc_reqbody_chunk_position]->length;
|
||||
msr->msc_reqbody_chunk_position++;
|
||||
msr->msc_reqbody_chunk_offset = 0;
|
||||
} else {
|
||||
/* We have a limit we must obey. */
|
||||
|
||||
if (chunks[msr->msc_reqbody_chunk_position]->length -
|
||||
msr->msc_reqbody_chunk_offset <= (unsigned int)nbytes)
|
||||
{
|
||||
/* If what's left in our chunk is less than the limit
|
||||
* then send it all back.
|
||||
*/
|
||||
msr->msc_reqbody_disk_chunk->length =
|
||||
chunks[msr->msc_reqbody_chunk_position]->length -
|
||||
msr->msc_reqbody_chunk_offset;
|
||||
msr->msc_reqbody_chunk_position++;
|
||||
msr->msc_reqbody_chunk_offset = 0;
|
||||
} else {
|
||||
/* If we have more data in our chunk, send the
|
||||
* maximum bytes we can (nbytes).
|
||||
*/
|
||||
msr->msc_reqbody_disk_chunk->length = nbytes;
|
||||
msr->msc_reqbody_chunk_offset += nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we've advanced beyond our last chunk then
|
||||
* we have no more data to send.
|
||||
*/
|
||||
if (msr->msc_reqbody_chunk_position >= msr->msc_reqbody_chunks->nelts) {
|
||||
return 0; /* No more chunks. */
|
||||
}
|
||||
|
||||
/* More data available. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
long int my_nbytes = CHUNK_CAPACITY;
|
||||
int i;
|
||||
|
||||
/* Send CHUNK_CAPACITY bytes at a time unless a lower limit was requested. */
|
||||
if ((nbytes != -1)&&(my_nbytes > nbytes)) {
|
||||
my_nbytes = nbytes;
|
||||
}
|
||||
|
||||
i = read(msr->msc_reqbody_fd, msr->msc_reqbody_disk_chunk->data, my_nbytes);
|
||||
if (i < 0) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Error reading from temporary file: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*chunk = msr->msc_reqbody_disk_chunk;
|
||||
msr->msc_reqbody_disk_chunk->length = i;
|
||||
|
||||
if (i == 0) return 0; /* No more data available. */
|
||||
|
||||
return 1; /* More data available. */
|
||||
}
|
||||
|
||||
/* Should never happen. */
|
||||
*error_msg = apr_psprintf(msr->mp, "Internal error, invalid msc_reqbody_storage value: %u",
|
||||
msr->msc_reqbody_storage);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
apr_status_t modsecurity_request_body_clear(modsec_rec *msr, char **error_msg) {
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Release memory we used to store request body data. */
|
||||
if (msr->msc_reqbody_chunks != NULL) {
|
||||
msc_data_chunk **chunks = (msc_data_chunk **)msr->msc_reqbody_chunks->elts;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < msr->msc_reqbody_chunks->nelts; i++) {
|
||||
if (chunks[i]->data != NULL) {
|
||||
free(chunks[i]->data);
|
||||
chunks[i]->data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msr->msc_reqbody_storage == MSC_REQBODY_DISK) {
|
||||
int keep_body = 0;
|
||||
|
||||
/* Should we keep the body? This normally
|
||||
* happens when a PUT method was used, which
|
||||
* means the body is actually a file.
|
||||
*/
|
||||
if ((msr->upload_remove_files == 0)&&(strcasecmp(msr->request_method, "PUT") == 0)) {
|
||||
if (msr->txcfg->upload_dir != NULL) {
|
||||
keep_body = 1;
|
||||
} else {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: SecUploadDir is undefined, "
|
||||
"unable to store PUT file.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Deal with a request body stored in a file. */
|
||||
|
||||
if (msr->msc_reqbody_filename != NULL) {
|
||||
if (keep_body) {
|
||||
/* Move request body (which is a file) to the storage area. */
|
||||
const char *put_filename = NULL;
|
||||
const char *put_basename = NULL;
|
||||
|
||||
/* Construct the new filename. */
|
||||
put_basename = file_basename(msr->msc_reqbody_mp, msr->msc_reqbody_filename);
|
||||
if (put_basename == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate basename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
|
||||
return -1;
|
||||
}
|
||||
put_filename = apr_psprintf(msr->msc_reqbody_mp, "%s/%s",
|
||||
msr->txcfg->upload_dir, put_basename);
|
||||
if (put_filename == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to generate filename to PUT file \"%s\"", log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (apr_file_rename(msr->msc_reqbody_filename, put_filename,
|
||||
msr->msc_reqbody_mp) != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to rename file from \"%s\" to \"%s\".",
|
||||
log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
|
||||
log_escape(msr->msc_reqbody_mp, put_filename));
|
||||
return -1;
|
||||
} else {
|
||||
msr_log(msr, 4, "Input filter: Moved file from \"%s\" to \"%s\".",
|
||||
log_escape(msr->msc_reqbody_mp, msr->msc_reqbody_filename),
|
||||
log_escape(msr->msc_reqbody_mp, put_filename));
|
||||
}
|
||||
} else {
|
||||
/* make sure it is closed first */
|
||||
if (msr->msc_reqbody_fd > 0) {
|
||||
close(msr->msc_reqbody_fd);
|
||||
msr->msc_reqbody_fd = -1;
|
||||
}
|
||||
|
||||
/* We do not want to keep the request body. */
|
||||
if (apr_file_remove(msr->msc_reqbody_filename,
|
||||
msr->msc_reqbody_mp) != APR_SUCCESS)
|
||||
{
|
||||
*error_msg = apr_psprintf(msr->mp, "Input filter: Failed to delete temporary file: %s",
|
||||
log_escape(msr->mp, msr->msc_reqbody_filename));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msr_log(msr, 4, "Input filter: Removed temporary file: %s",
|
||||
msr->msc_reqbody_filename);
|
||||
}
|
||||
|
||||
msr->msc_reqbody_filename = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (msr->msc_reqbody_mp != NULL) {
|
||||
apr_pool_destroy(msr->msc_reqbody_mp);
|
||||
msr->msc_reqbody_mp = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,499 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_status_engine.h"
|
||||
#include "apr_sha1.h"
|
||||
#include "modsecurity_config.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef DARWIN
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#ifndef IFT_ETHER
|
||||
#define IFT_ETHER 0x6 /* Ethernet CSMACD */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__gnu_linux__))
|
||||
#include <linux/if.h>
|
||||
#include <linux/sockios.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UTSNAME_H
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
|
||||
// Bese32 encode, based on:
|
||||
// https://code.google.com/p/google-authenticator/source/browse/libpam/base32.c
|
||||
int DSOLOCAL msc_status_engine_base32_encode(char *encoded,
|
||||
const char *data, int len) {
|
||||
int buffer;
|
||||
int count = 0;
|
||||
char *result = encoded;
|
||||
int length = strlen(data);
|
||||
|
||||
buffer = data[0];
|
||||
|
||||
if (encoded == NULL && len == 0) {
|
||||
len = length * 3;
|
||||
count++;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
int next = 1;
|
||||
int bitsLeft = 8;
|
||||
while (count < len && (bitsLeft > 0 || next < length)) {
|
||||
int index;
|
||||
if (bitsLeft < 5) {
|
||||
if (next < length) {
|
||||
buffer <<= 8;
|
||||
buffer |= data[next++] & 0xff;
|
||||
bitsLeft += 8;
|
||||
} else {
|
||||
int pad = 5 - bitsLeft;
|
||||
buffer <<= pad;
|
||||
bitsLeft += pad;
|
||||
}
|
||||
}
|
||||
index = 0x1f & (buffer >> (bitsLeft - 5));
|
||||
bitsLeft -= 5;
|
||||
if (encoded != NULL) {
|
||||
result[count] = msc_status_engine_basis_32[index];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count < len && encoded != NULL) {
|
||||
result[count] = '\000';
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int DSOLOCAL msc_status_engine_fill_with_dots(char *encoded_with_dots,
|
||||
const char *data, int len, int space)
|
||||
{
|
||||
int i;
|
||||
int count = 0;
|
||||
|
||||
if (encoded_with_dots == NULL) {
|
||||
if (len == 0 && data != NULL) {
|
||||
len = strlen(data);
|
||||
}
|
||||
else if (len == 0 && data == NULL) {
|
||||
count = -1;
|
||||
goto return_length;
|
||||
}
|
||||
|
||||
count = len/space + len + 1;
|
||||
goto return_length;
|
||||
}
|
||||
|
||||
for (i = 0; i < strlen(data) && i < len; i++) {
|
||||
if (i % space == 0 && i != 0) {
|
||||
encoded_with_dots[count++] = '.';
|
||||
}
|
||||
encoded_with_dots[count++] = data[i];
|
||||
}
|
||||
encoded_with_dots[count] = '\0';
|
||||
|
||||
return_length:
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
// Based on:
|
||||
// http://stackoverflow.com/questions/16858782/how-to-obtain-almost-unique-system-identifier-in-a-cross-platform-way
|
||||
int DSOLOCAL msc_status_engine_machine_name(char *machine_name, size_t len) {
|
||||
#ifdef WIN32
|
||||
DWORD lenComputerName = len;
|
||||
#endif
|
||||
|
||||
memset(machine_name, '\0', sizeof(char) * len);
|
||||
|
||||
#ifdef WIN32
|
||||
if (GetComputerName(machine_name, &lenComputerName) == 0) {
|
||||
goto failed;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UTSNAME_H
|
||||
static struct utsname u;
|
||||
|
||||
if ( uname( &u ) < 0 ) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
apr_snprintf(machine_name, len-1, "%s", u.nodename);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DSOLOCAL msc_status_engine_mac_address (unsigned char *mac)
|
||||
{
|
||||
#ifdef DARWIN
|
||||
struct ifaddrs* ifaphead;
|
||||
struct ifaddrs* ifap;
|
||||
int i = 0;
|
||||
|
||||
if ( getifaddrs( &ifaphead ) != 0 ) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// iterate over the net interfaces
|
||||
for ( ifap = ifaphead; ifap; ifap = ifap->ifa_next ) {
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*)ifap->ifa_addr;
|
||||
if ( sdl && ( sdl->sdl_family == AF_LINK ) && ( sdl->sdl_type == IFT_ETHER )
|
||||
&& mac[0] && mac[1] && mac[2] && i < 6) {
|
||||
|
||||
apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(unsigned char)LLADDR(sdl)[0],
|
||||
(unsigned char)LLADDR(sdl)[1],
|
||||
(unsigned char)LLADDR(sdl)[2],
|
||||
(unsigned char)LLADDR(sdl)[3],
|
||||
(unsigned char)LLADDR(sdl)[4],
|
||||
(unsigned char)LLADDR(sdl)[5]);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs( ifaphead );
|
||||
#endif
|
||||
|
||||
#if (defined(__linux__) || defined(__gnu_linux__))
|
||||
struct ifconf conf;
|
||||
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP );
|
||||
struct ifreq* ifr;
|
||||
if ( sock < 0 ) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
char ifconfbuf[ 128 * sizeof(struct ifreq) ];
|
||||
memset( ifconfbuf, 0, sizeof( ifconfbuf ));
|
||||
conf.ifc_buf = ifconfbuf;
|
||||
conf.ifc_len = sizeof( ifconfbuf );
|
||||
if ( ioctl( sock, SIOCGIFCONF, &conf )) {
|
||||
close(sock);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for ( ifr = conf.ifc_req; ifr < conf.ifc_req + conf.ifc_len; ifr++ ) {
|
||||
if ( ioctl( sock, SIOCGIFFLAGS, ifr )) {
|
||||
continue; // failed to get flags, skip it
|
||||
}
|
||||
|
||||
if ( ioctl( sock, SIOCGIFHWADDR, ifr ) == 0 ) {
|
||||
int i = 0;
|
||||
if (!ifr->ifr_addr.sa_data[0] && !ifr->ifr_addr.sa_data[1]
|
||||
&& !ifr->ifr_addr.sa_data[2]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(unsigned char)ifr->ifr_addr.sa_data[0],
|
||||
(unsigned char)ifr->ifr_addr.sa_data[1],
|
||||
(unsigned char)ifr->ifr_addr.sa_data[2],
|
||||
(unsigned char)ifr->ifr_addr.sa_data[3],
|
||||
(unsigned char)ifr->ifr_addr.sa_data[4],
|
||||
(unsigned char)ifr->ifr_addr.sa_data[5]);
|
||||
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
close( sock );
|
||||
#endif
|
||||
|
||||
#if WIN32
|
||||
PIP_ADAPTER_INFO pAdapterInfo;
|
||||
PIP_ADAPTER_INFO pAdapter = NULL;
|
||||
DWORD dwRetVal = 0;
|
||||
|
||||
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(sizeof (IP_ADAPTER_INFO));
|
||||
if (!pAdapterInfo) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (GetAdaptersInfo(pAdapterInfo, &ulOutBufLen) == ERROR_BUFFER_OVERFLOW) {
|
||||
free(pAdapterInfo);
|
||||
pAdapterInfo = (IP_ADAPTER_INFO *)malloc(ulOutBufLen);
|
||||
if (!pAdapterInfo) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
|
||||
if (dwRetVal != NO_ERROR) {
|
||||
free(pAdapterInfo);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
pAdapter = pAdapterInfo;
|
||||
while (pAdapter && !mac[0] && !mac[1] && !mac[2])
|
||||
{
|
||||
if (pAdapter->AddressLength > 4)
|
||||
{
|
||||
apr_snprintf(mac, MAC_ADDRESS_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
(unsigned char)pAdapter->Address[0],
|
||||
(unsigned char)pAdapter->Address[1],
|
||||
(unsigned char)pAdapter->Address[2],
|
||||
(unsigned char)pAdapter->Address[3],
|
||||
(unsigned char)pAdapter->Address[4],
|
||||
(unsigned char)pAdapter->Address[5]);
|
||||
goto end;
|
||||
}
|
||||
pAdapter = pAdapter->Next;
|
||||
}
|
||||
|
||||
free(pAdapterInfo);
|
||||
#endif
|
||||
|
||||
end:
|
||||
return 0;
|
||||
failed:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest)
|
||||
{
|
||||
unsigned char hex_digest[APR_SHA1_DIGESTSIZE];
|
||||
unsigned char *mac_address = NULL;
|
||||
char *machine_name = NULL;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
apr_sha1_ctx_t context;
|
||||
|
||||
mac_address = malloc(sizeof(char)*(MAC_ADDRESS_SIZE));
|
||||
if (!mac_address) {
|
||||
ret = -1;
|
||||
goto failed_mac_address;
|
||||
}
|
||||
memset(mac_address, '\0', sizeof(char)*(MAC_ADDRESS_SIZE));
|
||||
|
||||
if (msc_status_engine_mac_address(mac_address)) {
|
||||
ret = -1;
|
||||
goto failed_set_mac_address;
|
||||
}
|
||||
|
||||
machine_name = malloc(sizeof(char)*MAX_MACHINE_NAME_SIZE);
|
||||
if (!machine_name) {
|
||||
ret = -1;
|
||||
goto failed_machine_name;
|
||||
}
|
||||
memset(machine_name, '\0', sizeof(char)*(MAX_MACHINE_NAME_SIZE));
|
||||
if (msc_status_engine_machine_name(machine_name, MAC_ADDRESS_SIZE)) {
|
||||
ret = -1;
|
||||
goto failed_set_machine_name;
|
||||
}
|
||||
|
||||
apr_sha1_init(&context);
|
||||
apr_sha1_update(&context, machine_name, strlen(machine_name));
|
||||
apr_sha1_update(&context, mac_address, strlen(mac_address));
|
||||
apr_sha1_final(hex_digest, &context);
|
||||
|
||||
for (i = 0; i < APR_SHA1_DIGESTSIZE; i++)
|
||||
{
|
||||
sprintf(digest, "%s%02x", digest, hex_digest[i]);
|
||||
}
|
||||
|
||||
failed_set_machine_name:
|
||||
free(machine_name);
|
||||
failed_machine_name:
|
||||
failed_set_mac_address:
|
||||
free(mac_address);
|
||||
failed_mac_address:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len) {
|
||||
char *apr = NULL;
|
||||
const char *apr_loaded = NULL;
|
||||
char pcre[7];
|
||||
const char *pcre_loaded = NULL;
|
||||
char *lua = NULL;
|
||||
char *libxml = NULL;
|
||||
char *modsec = NULL;
|
||||
const char *apache = NULL;
|
||||
char id[(APR_SHA1_DIGESTSIZE*2) + 1];
|
||||
int beacon_string_len = -1;
|
||||
|
||||
apr = APR_VERSION_STRING;
|
||||
apr_loaded = apr_version_string();
|
||||
apr_snprintf(pcre, 7, "%d.%d", PCRE_MAJOR, PCRE_MINOR);
|
||||
pcre_loaded = pcre_version();
|
||||
#ifdef WITH_LUA
|
||||
lua = LUA_VERSION;
|
||||
#endif
|
||||
libxml = LIBXML_DOTTED_VERSION;
|
||||
modsec = MODSEC_VERSION;
|
||||
#ifdef VERSION_IIS
|
||||
apache = "IIS";
|
||||
#elif VERSION_NGINX
|
||||
apache = "nginx";
|
||||
#else
|
||||
apache = real_server_signature;
|
||||
#endif
|
||||
|
||||
/* 6 represents: strlen("(null)") */
|
||||
beacon_string_len = (modsec ? strlen(modsec) : 6) +
|
||||
(apache ? strlen(apache) : 6) + (apr ? strlen(apr) : 6) +
|
||||
(apr_loaded ? strlen(apr_loaded) : 6) + (pcre ? strlen(pcre) : 6) +
|
||||
(pcre_loaded ? strlen(pcre_loaded) : 6) + (lua ? strlen(lua) : 6) +
|
||||
(libxml ? strlen(libxml) : 6) + (APR_SHA1_DIGESTSIZE * 2);
|
||||
|
||||
beacon_string_len = beacon_string_len + /* null terminator: */ 1 +
|
||||
/* comma: */ 6 +
|
||||
/* slash: */ 2;
|
||||
|
||||
if (beacon_string == NULL || beacon_string_max_len == 0) {
|
||||
goto return_length;
|
||||
}
|
||||
|
||||
memset(id, '\0', sizeof(id));
|
||||
if (msc_status_engine_unique_id(id)) {
|
||||
sprintf(id, "no unique id");
|
||||
}
|
||||
|
||||
apr_snprintf(beacon_string, beacon_string_max_len,
|
||||
"%.25s,%.25s,%s/%s,%s/%s,%s,%s,%s",
|
||||
modsec, apache, apr, apr_loaded, pcre, pcre_loaded, lua, libxml, id);
|
||||
|
||||
return_length:
|
||||
return beacon_string_len;
|
||||
}
|
||||
|
||||
int DSOLOCAL msc_status_engine_prepare_hostname (char *hostname, const char *plain_data,
|
||||
int max_length)
|
||||
{
|
||||
int str_enc_len = 0;
|
||||
int str_enc_spl_len = 0;
|
||||
char *tmp = NULL;
|
||||
int length = -1;
|
||||
time_t ltime;
|
||||
|
||||
str_enc_len = msc_status_engine_base32_encode(NULL, plain_data, 0);
|
||||
|
||||
str_enc_spl_len = msc_status_engine_fill_with_dots(NULL, NULL, str_enc_len,
|
||||
STATUS_ENGINE_DNS_IN_BETWEEN_DOTS);
|
||||
if (str_enc_spl_len < 0) {
|
||||
goto failed_enc_spl_len;
|
||||
}
|
||||
|
||||
length = str_enc_spl_len + strlen(STATUS_ENGINE_DNS_SUFFIX) +
|
||||
/* epoch: */ 10 + /* dots: */ 2 + /* terminator: */ 1 -
|
||||
/* removed unsed terminators from str_enc and str_enc_spl: */ 2;
|
||||
|
||||
if (hostname == NULL || max_length == 0) {
|
||||
goto return_length;
|
||||
}
|
||||
|
||||
memset(hostname, '\0', sizeof(char) * max_length);
|
||||
|
||||
msc_status_engine_base32_encode(hostname, plain_data, str_enc_len);
|
||||
|
||||
tmp = strdup(hostname);
|
||||
if (tmp == NULL) {
|
||||
length = -1;
|
||||
goto failed_strdup;
|
||||
}
|
||||
|
||||
str_enc_spl_len = msc_status_engine_fill_with_dots(hostname, tmp, max_length,
|
||||
STATUS_ENGINE_DNS_IN_BETWEEN_DOTS);
|
||||
if (str_enc_spl_len < 0) {
|
||||
length = -1;
|
||||
goto failed_enc_spl;
|
||||
}
|
||||
|
||||
time ( <ime );
|
||||
apr_snprintf(hostname, max_length, "%s.%ld.%s", hostname,
|
||||
(long) ltime, STATUS_ENGINE_DNS_SUFFIX);
|
||||
|
||||
failed_enc_spl:
|
||||
free(tmp);
|
||||
failed_strdup:
|
||||
return_length:
|
||||
failed_enc_spl_len:
|
||||
return length;
|
||||
}
|
||||
|
||||
int msc_status_engine_call (void) {
|
||||
char *beacon_str = NULL;
|
||||
int beacon_str_len = 0;
|
||||
char *hostname = NULL;
|
||||
int hostname_len = 0;
|
||||
int ret = -1;
|
||||
|
||||
/* Retrieve the beacon string */
|
||||
beacon_str_len = msc_beacon_string(NULL, 0);
|
||||
|
||||
beacon_str = malloc(sizeof(char) * beacon_str_len);
|
||||
if (beacon_str == NULL) {
|
||||
goto failed_beacon_string_malloc;
|
||||
}
|
||||
msc_beacon_string(beacon_str, beacon_str_len);
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||||
"ModSecurity: StatusEngine call: \"%s\"", beacon_str);
|
||||
|
||||
/* Get beacon string in the format of a hostname */
|
||||
hostname_len = msc_status_engine_prepare_hostname(NULL, beacon_str, 0);
|
||||
if (hostname_len < 0) {
|
||||
goto failed_hostname_len;
|
||||
}
|
||||
|
||||
hostname = malloc(sizeof(char) * hostname_len);
|
||||
if (hostname == NULL) {
|
||||
goto failed_hostname_malloc;
|
||||
}
|
||||
hostname_len = msc_status_engine_prepare_hostname(hostname, beacon_str,
|
||||
hostname_len);
|
||||
if (hostname_len < 0) {
|
||||
goto failed_hostname;
|
||||
}
|
||||
|
||||
/* Perform the DNS query. */
|
||||
if (gethostbyname(hostname)) {
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||||
"ModSecurity: StatusEngine call successfully sent. For more " \
|
||||
"information visit: http://%s/", STATUS_ENGINE_DNS_SUFFIX);
|
||||
} else {
|
||||
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
|
||||
"ModSecurity: StatusEngine call failed. Query: %s",
|
||||
hostname);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
failed_hostname:
|
||||
free(hostname);
|
||||
failed_hostname_malloc:
|
||||
failed_hostname_len:
|
||||
free(beacon_str);
|
||||
failed_beacon_string_malloc:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef MSC_STATUS_ENGINE_H
|
||||
#define MSC_STATUS_ENGINE_H
|
||||
|
||||
#include "apr.h"
|
||||
#include "apr_pools.h"
|
||||
#include "apr_version.h"
|
||||
#include "apr_optional.h"
|
||||
#include "msc_pcre.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#define STATUS_ENGINE_DNS_IN_BETWEEN_DOTS 32
|
||||
#else
|
||||
#define STATUS_ENGINE_DNS_IN_BETWEEN_DOTS 30
|
||||
#endif
|
||||
|
||||
#define STATUS_ENGINE_DNS_SUFFIX "status.modsecurity.org"
|
||||
|
||||
#define MAX_MACHINE_NAME_SIZE 100
|
||||
|
||||
#define MAC_ADDRESS_SIZE 20
|
||||
|
||||
static const char msc_status_engine_basis_32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
int msc_status_engine_call(void);
|
||||
|
||||
int DSOLOCAL msc_status_engine_unique_id (unsigned char *digest);
|
||||
|
||||
int DSOLOCAL msc_beacon_string (char *beacon_string, int beacon_string_max_len);
|
||||
|
||||
#endif
|
||||
@@ -1,916 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if APR_HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#if APR_HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if APR_HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#include "apr_lib.h"
|
||||
#include "msc_util.h"
|
||||
#include "msc_tree.h"
|
||||
|
||||
CPTTree *CPTCreateRadixTree(apr_pool_t *pool) {
|
||||
CPTTree *tree = NULL;
|
||||
|
||||
tree = apr_palloc(pool, sizeof(CPTTree));
|
||||
|
||||
if(tree == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(tree, 0, sizeof(CPTTree));
|
||||
tree->pool = pool;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void ConvertIPNetmask(unsigned char *buffer, unsigned char netmask, unsigned int ip_bitmask) {
|
||||
int aux = 0, bytes = 0;
|
||||
int mask = 0, mask_bit = 0;
|
||||
|
||||
bytes = ip_bitmask/8;
|
||||
|
||||
while(aux < bytes) {
|
||||
mask_bit = ((1+aux) * 8);
|
||||
|
||||
if (mask_bit > netmask) {
|
||||
mask = 0;
|
||||
if ((mask_bit - netmask) < 8) mask = SHIFT_LEFT_MASK(mask_bit - netmask);
|
||||
} else {
|
||||
mask = -1;
|
||||
}
|
||||
|
||||
buffer[aux] &= mask;
|
||||
aux++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
TreeNode *CPTCreateNode(apr_pool_t *pool) {
|
||||
TreeNode *node = NULL;
|
||||
|
||||
node = apr_palloc(pool, sizeof(TreeNode));
|
||||
|
||||
if(node == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(node, 0, sizeof(TreeNode));
|
||||
return node;
|
||||
}
|
||||
|
||||
CPTData *CPTCreateCPTData(unsigned char netmask, apr_pool_t *pool) {
|
||||
|
||||
CPTData *prefix_data = apr_palloc(pool, sizeof(CPTData));
|
||||
|
||||
if (prefix_data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(prefix_data, 0, sizeof(CPTData));
|
||||
|
||||
prefix_data->netmask = netmask;
|
||||
|
||||
return prefix_data;
|
||||
}
|
||||
|
||||
TreePrefix *InsertDataPrefix(TreePrefix *prefix, unsigned char *ipdata, unsigned int ip_bitmask,
|
||||
unsigned char netmask, apr_pool_t *pool) {
|
||||
|
||||
if(prefix == NULL)
|
||||
return NULL;
|
||||
|
||||
memcpy(prefix->buffer, ipdata, ip_bitmask/8);
|
||||
prefix->bitlen = ip_bitmask;
|
||||
|
||||
prefix->prefix_data = CPTCreateCPTData(netmask, pool);
|
||||
|
||||
if(prefix->prefix_data == NULL)
|
||||
return NULL;
|
||||
|
||||
return prefix;
|
||||
}
|
||||
|
||||
TreePrefix *CPTCreatePrefix(unsigned char *ipdata, unsigned int ip_bitmask,
|
||||
unsigned char netmask, apr_pool_t *pool) {
|
||||
|
||||
TreePrefix *prefix = NULL;
|
||||
int bytes = ip_bitmask/8;
|
||||
|
||||
if ((ip_bitmask % 8 != 0) || (ipdata == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
prefix = apr_palloc(pool, sizeof(TreePrefix));
|
||||
if (prefix == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(prefix, 0, sizeof(TreePrefix));
|
||||
|
||||
prefix->buffer = apr_palloc(pool, bytes);
|
||||
|
||||
if(prefix->buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(prefix->buffer, 0, bytes);
|
||||
|
||||
return InsertDataPrefix(prefix, ipdata, ip_bitmask, netmask, pool);
|
||||
}
|
||||
|
||||
void CPTAppendToCPTDataList(CPTData *new, CPTData **list) {
|
||||
CPTData *temp = NULL, *prev = NULL;
|
||||
|
||||
if (new == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (list == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
prev = *list;
|
||||
temp = *list;
|
||||
|
||||
while (temp != NULL) {
|
||||
if (new->netmask > temp->netmask)
|
||||
break;
|
||||
prev = temp;
|
||||
temp = temp->next;
|
||||
}
|
||||
|
||||
if (temp == *list) {
|
||||
new->next = *list;
|
||||
*list = new;
|
||||
} else {
|
||||
new->next = prev->next;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int TreePrefixContainNetmask(TreePrefix *prefix, unsigned char netmask) {
|
||||
CPTData *prefix_data = NULL;
|
||||
|
||||
if (prefix == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
prefix_data = prefix->prefix_data;
|
||||
|
||||
while (prefix_data != NULL) {
|
||||
if (prefix_data->netmask == netmask)
|
||||
return 1;
|
||||
prefix_data = prefix_data->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CheckBitmask(unsigned char netmask, unsigned int ip_bitmask) {
|
||||
|
||||
switch(netmask) {
|
||||
|
||||
case 0xff:
|
||||
return 1;
|
||||
case 0x20:
|
||||
if(ip_bitmask == 0x20)
|
||||
return 1;
|
||||
break;
|
||||
case 0x80:
|
||||
if(ip_bitmask == 0x80)
|
||||
return 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TreeNode *CPTCreateHead(TreePrefix *prefix, TreeNode *node, CPTTree *tree, unsigned char netmask, unsigned int ip_bitmask) {
|
||||
|
||||
if(tree == NULL)
|
||||
return NULL;
|
||||
|
||||
if(prefix == NULL)
|
||||
return NULL;
|
||||
|
||||
if (node != NULL) {
|
||||
|
||||
node->prefix = prefix;
|
||||
node->bit = prefix->bitlen;
|
||||
tree->head = node;
|
||||
|
||||
if(CheckBitmask(netmask, ip_bitmask))
|
||||
return node;
|
||||
|
||||
node->count++;
|
||||
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(unsigned char)));
|
||||
|
||||
if(node->netmasks)
|
||||
node->netmasks[0] = netmask;
|
||||
|
||||
return node;
|
||||
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TreeNode *SetParentNode(TreeNode *node, TreeNode *new_node, CPTTree *tree) {
|
||||
|
||||
if (node->parent == NULL)
|
||||
tree->head = new_node;
|
||||
else if (node->parent->right == node)
|
||||
node->parent->right = new_node;
|
||||
else
|
||||
node->parent->left = new_node;
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
int InsertNetmask(TreeNode *node, TreeNode *parent, TreeNode *new_node,
|
||||
CPTTree *tree, unsigned char netmask, unsigned char bitlen) {
|
||||
int i;
|
||||
|
||||
if (netmask != NETMASK_256-1 && netmask != NETMASK_128) {
|
||||
if ((netmask != NETMASK_32 || (netmask == NETMASK_32 && bitlen != NETMASK_32))) {
|
||||
|
||||
node = new_node;
|
||||
parent = new_node->parent;
|
||||
|
||||
while (parent != NULL && netmask < (parent->bit + 1)) {
|
||||
node = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
node->count++;
|
||||
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(unsigned char)));
|
||||
|
||||
if(node->netmasks == NULL)
|
||||
return 0;
|
||||
if ((node->count-1) == 0) {
|
||||
node->netmasks[0] = netmask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
node->netmasks[node->count - 1] = netmask;
|
||||
|
||||
i = node->count - 2;
|
||||
while (i >= 0) {
|
||||
if (netmask < node->netmasks[i]) {
|
||||
node->netmasks[i + 1] = netmask;
|
||||
break;
|
||||
}
|
||||
|
||||
node->netmasks[i + 1] = node->netmasks[i];
|
||||
node->netmasks[i] = netmask;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
TreeNode *CPTAddElement(unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree, unsigned char netmask) {
|
||||
unsigned char *buffer = NULL;
|
||||
unsigned char bitlen = 0;
|
||||
int bit_validation = 0, test_bit = 0;
|
||||
int i = 0, j = 0, temp = 0;
|
||||
unsigned int x, y;
|
||||
TreeNode *node = NULL, *new_node = NULL;
|
||||
TreeNode *parent = NULL, *i_node = NULL;
|
||||
TreeNode *bottom_node = NULL;
|
||||
TreePrefix *prefix = NULL;
|
||||
|
||||
if (tree == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ConvertIPNetmask(ipdata, netmask, ip_bitmask);
|
||||
|
||||
prefix = CPTCreatePrefix(ipdata, ip_bitmask, netmask, tree->pool);
|
||||
|
||||
if (prefix == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tree->head == NULL) {
|
||||
node = CPTCreateNode(tree->pool);
|
||||
return CPTCreateHead(prefix, node, tree, netmask, ip_bitmask);
|
||||
}
|
||||
|
||||
node = tree->head;
|
||||
buffer = prefix->buffer;
|
||||
bitlen = prefix->bitlen;
|
||||
|
||||
while (node->bit < bitlen || node->prefix == NULL) {
|
||||
|
||||
if (bitlen < node->bit) {
|
||||
if (node->right == NULL)
|
||||
break;
|
||||
else
|
||||
node = node->right;
|
||||
} else {
|
||||
x = SHIFT_RIGHT_MASK(node->bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (node->bit % 8));
|
||||
|
||||
if (TREE_CHECK(buffer[x],y)) {
|
||||
if (node->right == NULL)
|
||||
break;
|
||||
node = node->right;
|
||||
} else {
|
||||
if (node->left == NULL)
|
||||
break;
|
||||
else
|
||||
node = node->left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bottom_node = node;
|
||||
|
||||
if(node->bit < bitlen)
|
||||
bit_validation = node->bit;
|
||||
else
|
||||
bit_validation = bitlen;
|
||||
|
||||
for (i = 0; (i * NETMASK_8) < bit_validation; i++) {
|
||||
int net = 0, div = 0;
|
||||
int cnt = 0;
|
||||
|
||||
if ((temp = (buffer[i] ^ bottom_node->prefix->buffer[i])) == 0) {
|
||||
test_bit = (i + 1) * NETMASK_8;
|
||||
continue;
|
||||
}
|
||||
|
||||
temp += temp;
|
||||
|
||||
for(cnt = 0, net = NETMASK_256, div = 2; net >= NETMASK_2; net = NETMASK_256/div,
|
||||
div += div, cnt++) {
|
||||
if(temp >= net) {
|
||||
test_bit = (i * NETMASK_8) + cnt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (bit_validation < test_bit)
|
||||
test_bit = bit_validation;
|
||||
|
||||
parent = node->parent;
|
||||
|
||||
while (parent && test_bit <= parent->bit) {
|
||||
node = parent;
|
||||
parent = node->parent;
|
||||
}
|
||||
|
||||
if (test_bit == bitlen && node->bit == bitlen) {
|
||||
if (node->prefix != NULL) {
|
||||
int found = 0;
|
||||
CPTData *prefix_data = NULL;
|
||||
|
||||
prefix_data = node->prefix->prefix_data;
|
||||
|
||||
while(prefix_data != NULL) {
|
||||
if (prefix_data->netmask == netmask)
|
||||
++found;
|
||||
prefix_data = prefix_data->next;
|
||||
}
|
||||
|
||||
if (found != 0) {
|
||||
|
||||
CPTData *prefix_data = CPTCreateCPTData(netmask, tree->pool);
|
||||
CPTAppendToCPTDataList(prefix_data, &prefix->prefix_data);
|
||||
|
||||
if(CheckBitmask(netmask, ip_bitmask))
|
||||
return node;
|
||||
|
||||
parent = node->parent;
|
||||
while (parent != NULL && netmask < (parent->bit + 1)) {
|
||||
node = parent;
|
||||
parent = parent->parent;
|
||||
}
|
||||
|
||||
node->count++;
|
||||
new_node = node;
|
||||
node->netmasks = apr_palloc(tree->pool, (node->count * sizeof(unsigned char)));
|
||||
|
||||
if ((node->count -1) == 0) {
|
||||
node->netmasks[0] = netmask;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
node->netmasks[node->count - 1] = netmask;
|
||||
|
||||
i = node->count - 2;
|
||||
while (i >= 0) {
|
||||
if (netmask < node->netmasks[i]) {
|
||||
node->netmasks[i + 1] = netmask;
|
||||
break;
|
||||
}
|
||||
|
||||
node->netmasks[i + 1] = node->netmasks[i];
|
||||
node->netmasks[i] = netmask;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node->prefix = CPTCreatePrefix(prefix->buffer, prefix->bitlen,
|
||||
NETMASK_256-1, tree->pool);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
new_node = CPTCreateNode(tree->pool);
|
||||
|
||||
if(new_node == NULL)
|
||||
return NULL;
|
||||
|
||||
new_node->prefix = prefix;
|
||||
new_node->bit = prefix->bitlen;
|
||||
|
||||
if (test_bit == bitlen) {
|
||||
|
||||
x = SHIFT_RIGHT_MASK(test_bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (test_bit % 8));
|
||||
|
||||
if (TREE_CHECK(bottom_node->prefix->buffer[x],y)) {
|
||||
new_node->right = node;
|
||||
} else {
|
||||
new_node->left = node;
|
||||
}
|
||||
|
||||
new_node->parent = node->parent;
|
||||
node->parent = SetParentNode(node, new_node, tree);
|
||||
|
||||
} else {
|
||||
i_node = CPTCreateNode(tree->pool);
|
||||
|
||||
if(i_node == NULL)
|
||||
return NULL;
|
||||
|
||||
//i_node->prefix = NULL;
|
||||
i_node->bit = test_bit;
|
||||
i_node->parent = node->parent;
|
||||
|
||||
if (node->netmasks != NULL) {
|
||||
i = 0;
|
||||
while(i < node->count) {
|
||||
if (node->netmasks[i] < test_bit + 1)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
i_node->netmasks = apr_palloc(tree->pool, (node->count - i) * sizeof(unsigned char));
|
||||
|
||||
if(i_node->netmasks == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
while (j < (node->count - i)) {
|
||||
i_node->netmasks[j] = node->netmasks[i + j];
|
||||
j++;
|
||||
}
|
||||
|
||||
i_node->count = (node->count - i);
|
||||
node->count = i;
|
||||
|
||||
if (node->count == 0) {
|
||||
node->netmasks = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
x = SHIFT_RIGHT_MASK(test_bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (test_bit % 8));
|
||||
|
||||
if (TREE_CHECK(buffer[x],y)) {
|
||||
i_node->left = node;
|
||||
i_node->right = new_node;
|
||||
} else {
|
||||
i_node->left = new_node;
|
||||
i_node->right = node;
|
||||
}
|
||||
|
||||
new_node->parent = i_node;
|
||||
node->parent = SetParentNode(node, i_node, tree);
|
||||
}
|
||||
|
||||
if (InsertNetmask(node, parent, new_node, tree, netmask, bitlen))
|
||||
return new_node;
|
||||
|
||||
return new_node;
|
||||
}
|
||||
|
||||
int TreeCheckData(TreePrefix *prefix, CPTData *prefix_data, unsigned int netmask) {
|
||||
|
||||
while(prefix_data != NULL) {
|
||||
if (prefix_data->netmask == netmask) {
|
||||
return 1;
|
||||
}
|
||||
prefix_data = prefix_data->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TreePrefixNetmask(modsec_rec *msr, TreePrefix *prefix, unsigned int netmask, int flag) {
|
||||
CPTData *prefix_data = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (prefix == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "TreePrefixNetmask: prefix is NULL.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
prefix_data = prefix->prefix_data;
|
||||
|
||||
if (flag == 1) {
|
||||
|
||||
if(prefix_data == NULL) return 0;
|
||||
|
||||
if (prefix_data->netmask != netmask) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "TreePrefixNetmask: Cannot find a prefix with correct netmask.");
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "TreePrefixNetmask: Found a prefix with correct netmask.");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "TreePrefixNetmask: Check if a prefix has a the correct netmask");
|
||||
}
|
||||
|
||||
ret = TreeCheckData(prefix, prefix_data, netmask);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TreeNode *CPTRetriveNode(modsec_rec *msr, unsigned char *buffer, unsigned int ip_bitmask, TreeNode *node) {
|
||||
unsigned int x, y;
|
||||
|
||||
if(node == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTRetriveNode: Node tree is NULL.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(buffer == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTRetriveNode: Empty ip address. Nothing to search for.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (node->bit < ip_bitmask) {
|
||||
|
||||
x = SHIFT_RIGHT_MASK(node->bit, 3); y = SHIFT_RIGHT_MASK(NETMASK_128, (node->bit % 8));
|
||||
|
||||
if (TREE_CHECK(buffer[x], y)) {
|
||||
node = node->right;
|
||||
if (node == NULL) return NULL;
|
||||
} else {
|
||||
node = node->left;
|
||||
if (node == NULL) return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTRetriveNode: Found the node for provided ip address.");
|
||||
}
|
||||
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
TreeNode *CPTRetriveParentNode(TreeNode *node) {
|
||||
|
||||
while (node != NULL && node->netmasks == NULL)
|
||||
node = node->parent;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
TreeNode *CPTFindElementIPNetblock(modsec_rec *msr, unsigned char *ipdata, unsigned char ip_bitmask, TreeNode *node) {
|
||||
TreeNode *netmask_node = NULL;
|
||||
int mask = 0, bytes = 0;
|
||||
int i = 0, j = 0;
|
||||
int mask_bits = 0;
|
||||
|
||||
node = CPTRetriveParentNode(node);
|
||||
|
||||
if (node == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElementIPNetblock: Node tree is NULL.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
netmask_node = node;
|
||||
|
||||
while(j < netmask_node->count) {
|
||||
bytes = ip_bitmask / 8;
|
||||
|
||||
while( i < bytes ) {
|
||||
|
||||
mask = -1;
|
||||
mask_bits = ((i + 1) * 8);
|
||||
|
||||
if (mask_bits > netmask_node->netmasks[j]) {
|
||||
if ((mask_bits - netmask_node->netmasks[j]) < 8)
|
||||
mask = SHIFT_LEFT_MASK(mask_bits - netmask_node->netmasks[j]);
|
||||
else
|
||||
mask = 0;
|
||||
}
|
||||
|
||||
ipdata[i] &= mask;
|
||||
i++;
|
||||
}
|
||||
|
||||
node = CPTRetriveNode(msr, ipdata, ip_bitmask, node);
|
||||
|
||||
if (node && node->bit != ip_bitmask) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but netmask is different.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (node && node->prefix == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElementIPNetblock: Found a tree node but prefix is NULL.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (memcmp(node->prefix->buffer, ipdata, bytes) == 0) {
|
||||
mask = SHIFT_LEFT_MASK(8 - ip_bitmask % 8);
|
||||
|
||||
if ((ip_bitmask % 8) == 0) {
|
||||
if (TreePrefixNetmask(msr, node->prefix, netmask_node->netmasks[j], FALSE)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElementIPNetblock: Node found for provided ip address");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
if ((node->prefix->buffer[bytes] & mask) == (ipdata[bytes] & mask)) {
|
||||
if (TreePrefixNetmask(msr, node->prefix, netmask_node->netmasks[j], FALSE)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElementIPNetblock: Node found for provided ip address");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
return CPTFindElementIPNetblock(msr, ipdata, ip_bitmask, netmask_node->parent);
|
||||
}
|
||||
|
||||
TreeNode *CPTFindElement(modsec_rec *msr, unsigned char *ipdata, unsigned int ip_bitmask, CPTTree *tree) {
|
||||
TreeNode *node = NULL;
|
||||
int mask = 0, bytes = 0;
|
||||
unsigned char temp_data[NETMASK_256-1];
|
||||
|
||||
if (tree == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Tree is NULL. Cannot proceed searching the ip.");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
if (tree->head == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Tree head is NULL. Cannot proceed searching the ip.");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
node = tree->head;
|
||||
|
||||
if (ip_bitmask > (NETMASK_256-1)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Netmask cannot be greater than 255");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes = ip_bitmask/8;
|
||||
|
||||
memset(temp_data, 0, NETMASK_256-1);
|
||||
memcpy(temp_data, ipdata, bytes);
|
||||
|
||||
node = CPTRetriveNode(msr, temp_data, ip_bitmask, node);
|
||||
|
||||
if (node && (node->bit != ip_bitmask)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Found a tree node but netmask is different.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(node == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Node tree is NULL.");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
if(node->prefix == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Found a tree node but prefix is NULL.");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
if (memcmp(node->prefix->buffer, temp_data, bytes) == 0) {
|
||||
mask = SHIFT_LEFT_MASK(8 - ip_bitmask % 8);
|
||||
|
||||
if ((ip_bitmask % 8) == 0) {
|
||||
if (TreePrefixNetmask(msr, node->prefix, ip_bitmask, TRUE)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Node found for provided ip address");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
if ((node->prefix->buffer[bytes] & mask) == (temp_data[bytes] & mask)) {
|
||||
if (TreePrefixNetmask(msr, node->prefix, ip_bitmask, TRUE)) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTFindElement: Node found for provided ip address");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CPTFindElementIPNetblock(msr, temp_data, ip_bitmask, node);
|
||||
}
|
||||
|
||||
TreeNode *CPTIpMatch(modsec_rec *msr, unsigned char *ipdata, CPTTree *tree, int type) {
|
||||
|
||||
if(tree == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTIpMatch: Tree is NULL. Cannot proceed searching the ip.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ipdata == NULL) {
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTIpMatch: Empty ip address. Nothing to search for.");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case IPV4_TREE:
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTIpMatch: Searching ip type 0x%x", type);
|
||||
}
|
||||
return CPTFindElement(msr, ipdata, NETMASK_32, tree);
|
||||
case IPV6_TREE:
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTIpMatch: Searching ip type 0x%x", type);
|
||||
}
|
||||
return CPTFindElement(msr, ipdata, NETMASK_128, tree);
|
||||
default:
|
||||
if (msr && msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "CPTIpMatch: Unknown ip type 0x%x", type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode *TreeAddIP(const char *buffer, CPTTree *tree, int type) {
|
||||
unsigned long ip, ret;
|
||||
unsigned char netmask_v4 = NETMASK_32, netmask_v6 = NETMASK_128;
|
||||
char ip_strv4[NETMASK_32], ip_strv6[NETMASK_128];
|
||||
struct in_addr addr4;
|
||||
struct in6_addr addr6;
|
||||
int pos = 0;
|
||||
char *ptr = NULL;
|
||||
|
||||
if(tree == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = strchr(buffer, '/') - buffer;
|
||||
|
||||
switch(type) {
|
||||
|
||||
case IPV4_TREE:
|
||||
memset(&addr4, 0, sizeof(addr4));
|
||||
memset(ip_strv4, 0x0, NETMASK_32);
|
||||
|
||||
strncpy(ip_strv4, buffer, sizeof(ip_strv4));
|
||||
*(ip_strv4 + (sizeof(ip_strv4) - 1)) = '\0';
|
||||
|
||||
ptr = strdup(ip_strv4);
|
||||
netmask_v4 = is_netmask_v4(ptr);
|
||||
|
||||
if (netmask_v4 > NETMASK_32) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ptr != NULL) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
if(netmask_v4 == 0) {
|
||||
return NULL;
|
||||
}
|
||||
else if (netmask_v4 != NETMASK_32 && pos < strlen(ip_strv4)) {
|
||||
ip_strv4[pos] = '\0';
|
||||
}
|
||||
|
||||
ret = inet_pton(AF_INET, ip_strv4, &addr4);
|
||||
|
||||
if (ret <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ip = addr4.s_addr;
|
||||
|
||||
tree->count++;
|
||||
|
||||
return CPTAddElement((unsigned char *)&ip, NETMASK_32, tree, netmask_v4);
|
||||
|
||||
case IPV6_TREE:
|
||||
memset(&addr6, 0, sizeof(addr6));
|
||||
memset(ip_strv6, 0x0, NETMASK_128);
|
||||
|
||||
strncpy(ip_strv6, buffer, sizeof(ip_strv6));
|
||||
*(ip_strv6 + sizeof(ip_strv6) - 1) = '\0';
|
||||
|
||||
ptr = strdup(ip_strv6);
|
||||
netmask_v6 = is_netmask_v6(ptr);
|
||||
|
||||
if (netmask_v6 > NETMASK_128) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ptr != NULL) {
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
if(netmask_v6 == 0) {
|
||||
return NULL;
|
||||
}
|
||||
else if (netmask_v6 != NETMASK_128 && pos < strlen(ip_strv6)) {
|
||||
ip_strv6[pos] = '\0';
|
||||
}
|
||||
|
||||
ret = inet_pton(AF_INET6, ip_strv6, &addr6);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tree->count++;
|
||||
|
||||
return CPTAddElement((unsigned char *)&addr6.s6_addr, NETMASK_128, tree, netmask_v6);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef __MSC_TREE_H__
|
||||
#define __MSC_TREE_H__
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
typedef struct CPTData CPTData;
|
||||
typedef struct TreePrefix TreePrefix;
|
||||
typedef struct TreeNode TreeNode;
|
||||
typedef struct CPTTree CPTTree;
|
||||
typedef struct TreeRoot TreeRoot;
|
||||
|
||||
#define IPV4_TREE 0x1
|
||||
#define IPV6_TREE 0x2
|
||||
|
||||
#define IPV4_LEN 0x20
|
||||
#define IPV6_LEN 0x80
|
||||
|
||||
#define TREE_CHECK(x, y) ((x) & (y))
|
||||
#define MASK_BITS(x) ((x + 1) * 8)
|
||||
#define SHIFT_LEFT_MASK(x) ((-1) << (x))
|
||||
#define SHIFT_RIGHT_MASK(x,y) ((x) >> (y))
|
||||
|
||||
#define NETMASK_256 0x100
|
||||
#define NETMASK_128 0x80
|
||||
#define NETMASK_64 0x40
|
||||
#define NETMASK_32 0x20
|
||||
#define NETMASK_16 0x10
|
||||
#define NETMASK_8 0x8
|
||||
#define NETMASK_4 0x4
|
||||
#define NETMASK_2 0x2
|
||||
|
||||
struct CPTData {
|
||||
unsigned char netmask;
|
||||
struct CPTData *next;
|
||||
};
|
||||
|
||||
struct TreePrefix {
|
||||
unsigned char *buffer;
|
||||
unsigned int bitlen;
|
||||
CPTData *prefix_data;
|
||||
};
|
||||
|
||||
struct TreeNode {
|
||||
unsigned int bit;
|
||||
int count;
|
||||
unsigned char *netmasks;
|
||||
TreePrefix *prefix;
|
||||
struct TreeNode *left, *right;
|
||||
struct TreeNode *parent;
|
||||
};
|
||||
|
||||
struct CPTTree {
|
||||
int count;
|
||||
apr_pool_t *pool;
|
||||
TreeNode *head;
|
||||
};
|
||||
|
||||
struct TreeRoot {
|
||||
CPTTree *ipv4_tree;
|
||||
CPTTree *ipv6_tree;
|
||||
};
|
||||
|
||||
CPTTree DSOLOCAL *CPTCreateRadixTree(apr_pool_t *pool);
|
||||
TreeNode DSOLOCAL *CPTIpMatch(modsec_rec *msr, unsigned char *ipdata, CPTTree *tree, int type);
|
||||
TreeNode DSOLOCAL *TreeAddIP(const char *buffer, CPTTree *tree, int type);
|
||||
|
||||
#endif /*__MSC_TREE_H__ */
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_unicode.h"
|
||||
|
||||
#define CODEPAGE_SEPARATORS " \t\n\r"
|
||||
|
||||
/** \brief Load Unicode file
|
||||
*
|
||||
* \param dcfg Pointer to directory configuration
|
||||
* \param error_msg Error message
|
||||
*
|
||||
* \retval 1 On Success
|
||||
* \retval 0 On Fail
|
||||
*/
|
||||
static int unicode_map_create(directory_config *dcfg, char **error_msg)
|
||||
{
|
||||
char errstr[1024];
|
||||
apr_pool_t *mp = dcfg->mp;
|
||||
unicode_map *u_map = dcfg->u_map;
|
||||
apr_int32_t wanted = APR_FINFO_SIZE;
|
||||
apr_finfo_t finfo;
|
||||
apr_status_t rc;
|
||||
apr_size_t nbytes;
|
||||
unsigned int codepage = 0;
|
||||
char *buf = NULL, *p = NULL, *savedptr = NULL;
|
||||
char *ucode = NULL, *hmap = NULL;
|
||||
int found = 0, processing = 0;
|
||||
int Code = 0, Map = 0;
|
||||
|
||||
if(unicode_map_table != NULL) {
|
||||
free(unicode_map_table);
|
||||
unicode_map_table = NULL;
|
||||
}
|
||||
|
||||
if ((rc = apr_file_open(&u_map->map, u_map->mapfn, APR_READ, APR_OS_DEFAULT, mp)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not open unicode map file \"%s\": %s", u_map->mapfn, apr_strerror(rc, errstr, 1024));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((rc = apr_file_info_get(&finfo, wanted, u_map->map)) != APR_SUCCESS) {
|
||||
*error_msg = apr_psprintf(mp, "Could not cannot get unicode map file information \"%s\": %s", u_map->mapfn, apr_strerror(rc, errstr, 1024));
|
||||
apr_file_close(u_map->map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
buf = (char *)malloc(finfo.size+1);
|
||||
|
||||
if (buf == NULL) {
|
||||
*error_msg = apr_psprintf(mp, "Could not alloc memory for unicode map");
|
||||
apr_file_close(u_map->map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = apr_file_read_full(u_map->map, buf, finfo.size, &nbytes);
|
||||
|
||||
if (unicode_map_table != NULL) {
|
||||
memset(unicode_map_table, -1, (sizeof(int)*65536));
|
||||
} else {
|
||||
unicode_map_table = (int *)malloc(sizeof(int) * 65536);
|
||||
|
||||
if(unicode_map_table == NULL) {
|
||||
*error_msg = apr_psprintf(mp, "Could not alloc memory for unicode map");
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
apr_file_close(u_map->map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(unicode_map_table, -1, (sizeof(int)*65536));
|
||||
}
|
||||
|
||||
/* Setting some unicode values - http://tools.ietf.org/html/rfc3490#section-3.1 */
|
||||
|
||||
/* Set 0x3002 -> 0x2e */
|
||||
unicode_map_table[0x3002] = 0x2e;
|
||||
/* Set 0xFF61 -> 0x2e */
|
||||
unicode_map_table[0xff61] = 0x2e;
|
||||
/* Set 0xFF0E -> 0x2e */
|
||||
unicode_map_table[0xff0e] = 0x2e;
|
||||
/* Set 0x002E -> 0x2e */
|
||||
unicode_map_table[0x002e] = 0x2e;
|
||||
|
||||
p = apr_strtok(buf,CODEPAGE_SEPARATORS,&savedptr);
|
||||
|
||||
while (p != NULL) {
|
||||
|
||||
codepage = atol(p);
|
||||
|
||||
if (codepage == unicode_codepage) {
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found == 1 && (strchr(p,':') != NULL)) {
|
||||
char *mapping = strdup(p);
|
||||
processing = 1;
|
||||
|
||||
if(mapping != NULL) {
|
||||
ucode = apr_strtok(mapping,":", &hmap);
|
||||
sscanf(ucode,"%x",&Code);
|
||||
sscanf(hmap,"%x",&Map);
|
||||
if(Code >= 0 && Code <= 65535) {
|
||||
unicode_map_table[Code] = Map;
|
||||
}
|
||||
|
||||
free(mapping);
|
||||
mapping = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (processing == 1 && (strchr(p,':') == NULL)) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
p = apr_strtok(NULL,CODEPAGE_SEPARATORS,&savedptr);
|
||||
}
|
||||
|
||||
apr_file_close(u_map->map);
|
||||
|
||||
if(buf) {
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Init unicode map
|
||||
*
|
||||
* \param dcfg Pointer to directory configuration
|
||||
* \param mapfn Unicode map filename
|
||||
* \param error_msg Error message
|
||||
*
|
||||
* \retval unicode_map_create On Success
|
||||
* \retval -1 On Fail
|
||||
*/
|
||||
int unicode_map_init(directory_config *dcfg, const char *mapfn, char **error_msg)
|
||||
{
|
||||
|
||||
*error_msg = NULL;
|
||||
|
||||
if ((dcfg->u_map == NULL) || (dcfg->u_map == NOT_SET_P)) {
|
||||
dcfg->u_map = apr_pcalloc(dcfg->mp, sizeof(unicode_map));
|
||||
if (dcfg->u_map == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
dcfg->u_map->map = NULL;
|
||||
dcfg->u_map->mapfn = apr_pstrdup(dcfg->mp, mapfn);
|
||||
|
||||
return unicode_map_create(dcfg, error_msg);
|
||||
}
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_UNICODE_H_
|
||||
#define _MSC_UNICODE_H_
|
||||
|
||||
typedef struct unicode_map unicode_map;
|
||||
|
||||
#include <apr_file_io.h>
|
||||
#include "modsecurity.h"
|
||||
#include "apr_hash.h"
|
||||
|
||||
struct unicode_map {
|
||||
apr_file_t *map;
|
||||
const char *mapfn;
|
||||
};
|
||||
|
||||
int DSOLOCAL unicode_map_init(directory_config *dcfg, const char *mapfn, char **error_msg);
|
||||
|
||||
#endif
|
||||
2834
apache2/msc_util.c
2834
apache2/msc_util.c
File diff suppressed because it is too large
Load Diff
@@ -1,182 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _UTIL_H_
|
||||
#define _UTIL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <apr_file_info.h>
|
||||
|
||||
#ifndef APR_WSTICKY
|
||||
/* Add extra flags added to APR in 0.9.5 */
|
||||
#define APR_USETID 0x8000 /**< Set user id */
|
||||
#define APR_GSETID 0x4000 /**< Set group id */
|
||||
#define APR_WSTICKY 0x2000 /**< Sticky bit */
|
||||
#endif
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include "re.h"
|
||||
#include "msc_tree.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <ws2tcpip.h>
|
||||
// This is a trick: for ModSecurity modules this will declare inet_pton,
|
||||
// but for mymodule.cpp (IIS module) this will skip, because we include
|
||||
// windows.h before including msc_util.h
|
||||
// Without the trick we have redefinition conflict.
|
||||
//
|
||||
#if !(NTDDI_VERSION >= NTDDI_VISTA)
|
||||
int DSOLOCAL inet_pton(int family, const char *src, void *dst);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define UNICODE_ERROR_CHARACTERS_MISSING -1
|
||||
#define UNICODE_ERROR_INVALID_ENCODING -2
|
||||
#define UNICODE_ERROR_OVERLONG_CHARACTER -3
|
||||
#define UNICODE_ERROR_RESTRICTED_CHARACTER -4
|
||||
#define UNICODE_ERROR_DECODING_ERROR -5
|
||||
|
||||
#ifdef LINUX_S390
|
||||
int DSOLOCAL swap_int32(int x);
|
||||
#endif
|
||||
|
||||
|
||||
char DSOLOCAL *utf8_unicode_inplace_ex(apr_pool_t *mp, unsigned char *input, long int input_len, int *changed);
|
||||
|
||||
char DSOLOCAL *m_strcasestr(const char *haystack, const char *needle);
|
||||
|
||||
int DSOLOCAL normalize_path_inplace(unsigned char *input, int len, int win, int *changed);
|
||||
|
||||
int DSOLOCAL parse_boolean(const char *input);
|
||||
|
||||
char DSOLOCAL *remove_quotes(apr_pool_t *mptmp, const char *input, int input_len);
|
||||
|
||||
char DSOLOCAL *parse_pm_content(const char *op_parm, unsigned short int op_len, msre_rule *rule, char **error_msg);
|
||||
|
||||
char DSOLOCAL *remove_escape(apr_pool_t *mptmp, const char *input, int input_len);
|
||||
|
||||
int DSOLOCAL parse_name_eq_value(apr_pool_t *mp, const char *input, char **name, char **value);
|
||||
|
||||
char DSOLOCAL *url_encode(apr_pool_t *mp, char *input, unsigned int input_len, int *changed);
|
||||
|
||||
char DSOLOCAL *strnurlencat(char *destination, char *source, unsigned int maxlen);
|
||||
|
||||
char DSOLOCAL *file_dirname(apr_pool_t *p, const char *filename);
|
||||
|
||||
char DSOLOCAL *file_basename(apr_pool_t *p, const char *filename);
|
||||
|
||||
int DSOLOCAL sql_hex2bytes_inplace(unsigned char *data, int len);
|
||||
|
||||
int DSOLOCAL hex2bytes_inplace(unsigned char *data, int len);
|
||||
|
||||
char DSOLOCAL *bytes2hex(apr_pool_t *pool, unsigned char *data, int len);
|
||||
|
||||
int DSOLOCAL is_token_char(unsigned char c);
|
||||
|
||||
int DSOLOCAL remove_lf_crlf_inplace(char *text);
|
||||
|
||||
char DSOLOCAL *guess_tmp_dir(apr_pool_t *p);
|
||||
|
||||
char DSOLOCAL *current_logtime(apr_pool_t *mp);
|
||||
|
||||
char DSOLOCAL *current_filetime(apr_pool_t *mp);
|
||||
|
||||
int DSOLOCAL msc_mkstemp_ex(char *templat, int mode);
|
||||
|
||||
int DSOLOCAL msc_mkstemp(char *templat);
|
||||
|
||||
char DSOLOCAL *strtolower_inplace(unsigned char *str);
|
||||
|
||||
char DSOLOCAL *log_escape_re(apr_pool_t *p, const char *text);
|
||||
|
||||
char DSOLOCAL *log_escape(apr_pool_t *p, const char *text);
|
||||
|
||||
char DSOLOCAL *log_escape_nq(apr_pool_t *p, const char *text);
|
||||
|
||||
char DSOLOCAL *log_escape_ex(apr_pool_t *p, const char *text, unsigned long int text_length);
|
||||
|
||||
char DSOLOCAL *log_escape_nq_ex(apr_pool_t *p, const char *text, unsigned long int text_length);
|
||||
|
||||
char DSOLOCAL *log_escape_hex(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length);
|
||||
|
||||
char DSOLOCAL *log_escape_raw(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length);
|
||||
|
||||
char DSOLOCAL *log_escape_nul(apr_pool_t *mp, const unsigned char *text, unsigned long int text_length);
|
||||
|
||||
int DSOLOCAL decode_base64_ext(char *plain_text, const unsigned char *input, int input_len);
|
||||
|
||||
int DSOLOCAL convert_to_int(const char c);
|
||||
|
||||
int DSOLOCAL set_match_to_tx(modsec_rec *msr, int capture, const char *match, int tx_n);
|
||||
|
||||
int DSOLOCAL js_decode_nonstrict_inplace(unsigned char *input, long int input_len);
|
||||
|
||||
int DSOLOCAL urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_length, int * changed);
|
||||
|
||||
int DSOLOCAL urldecode_nonstrict_inplace_ex(unsigned char *input, long int input_length, int *invalid_count, int *changed);
|
||||
|
||||
int DSOLOCAL html_entities_decode_inplace(apr_pool_t *mp, unsigned char *input, int len);
|
||||
|
||||
int DSOLOCAL ansi_c_sequences_decode_inplace(unsigned char *input, int len);
|
||||
|
||||
char DSOLOCAL *modsec_build(apr_pool_t *mp);
|
||||
|
||||
int DSOLOCAL is_empty_string(const char *string);
|
||||
|
||||
char DSOLOCAL *resolve_relative_path(apr_pool_t *pool, const char *parent_filename, const char *filename);
|
||||
|
||||
int DSOLOCAL css_decode_inplace(unsigned char *input, long int input_len);
|
||||
|
||||
apr_fileperms_t DSOLOCAL mode2fileperms(int mode);
|
||||
|
||||
char DSOLOCAL *construct_single_var(modsec_rec *msr, char *name);
|
||||
|
||||
char DSOLOCAL *format_all_performance_variables(modsec_rec *msr, apr_pool_t *mp);
|
||||
|
||||
unsigned char DSOLOCAL is_netmask_v4(char *ip_strv4);
|
||||
|
||||
unsigned char DSOLOCAL is_netmask_v6(char *ip_strv6);
|
||||
|
||||
int DSOLOCAL msc_headers_to_buffer(const apr_array_header_t *arr, char *buffer, int max_length);
|
||||
|
||||
int DSOLOCAL ip_tree_from_file(TreeRoot **rtree, char *uri,
|
||||
apr_pool_t *mp, char **error_msg);
|
||||
|
||||
int DSOLOCAL tree_contains_ip(apr_pool_t *mp, TreeRoot *rtree,
|
||||
const char *value, modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL ip_tree_from_param(apr_pool_t *pool,
|
||||
char *param, TreeRoot **rtree, char **error_msg);
|
||||
|
||||
#ifdef WITH_CURL
|
||||
int ip_tree_from_uri(TreeRoot **rtree, char *uri,
|
||||
apr_pool_t *mp, char **error_msg);
|
||||
#endif
|
||||
|
||||
int read_line(char *buff, int size, FILE *fp);
|
||||
|
||||
size_t msc_curl_write_memory_cb(void *contents, size_t size,
|
||||
size_t nmemb, void *userp);
|
||||
|
||||
struct msc_curl_memory_buffer_t
|
||||
{
|
||||
char *memory;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
char *strtok_r(char *str, const char *delim, char **nextp);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,146 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "msc_xml.h"
|
||||
|
||||
static xmlParserInputBufferPtr
|
||||
xml_unload_external_entity(const char *URI, xmlCharEncoding enc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialise XML parser.
|
||||
*/
|
||||
int xml_init(modsec_rec *msr, char **error_msg) {
|
||||
xmlParserInputBufferCreateFilenameFunc entity;
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
msr->xml = apr_pcalloc(msr->mp, sizeof(xml_data));
|
||||
if (msr->xml == NULL) return -1;
|
||||
|
||||
if(msr->txcfg->xml_external_entity == 0) {
|
||||
entity = xmlParserInputBufferCreateFilenameDefault(xml_unload_external_entity);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void xml_receive_sax_error(void *data, const char *msg, ...) {
|
||||
modsec_rec *msr = (modsec_rec *)data;
|
||||
char message[256];
|
||||
|
||||
if (msr == NULL) return;
|
||||
|
||||
apr_snprintf(message, sizeof(message), "%s (line %d offset %d)",
|
||||
log_escape_nq(msr->mp, msr->xml->parsing_ctx->lastError.message),
|
||||
msr->xml->parsing_ctx->lastError.line,
|
||||
msr->xml->parsing_ctx->lastError.int2);
|
||||
|
||||
msr_log(msr, 5, "XML: Parsing error: %s", message);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Feed one chunk of data to the XML parser.
|
||||
*/
|
||||
int xml_process_chunk(modsec_rec *msr, const char *buf, unsigned int size, char **error_msg) {
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
/* We want to initialise our parsing context here, to
|
||||
* enable us to pass it the first chunk of data so that
|
||||
* it can attempt to auto-detect the encoding.
|
||||
*/
|
||||
if (msr->xml->parsing_ctx == NULL) {
|
||||
|
||||
/* First invocation. */
|
||||
|
||||
msr_log(msr, 4, "XML: Initialising parser.");
|
||||
|
||||
/* NOTE When Sax interface is used libxml will not
|
||||
* create the document object, but we need it.
|
||||
|
||||
msr->xml->sax_handler = (xmlSAXHandler *)apr_pcalloc(msr->mp, sizeof(xmlSAXHandler));
|
||||
if (msr->xml->sax_handler == NULL) return -1;
|
||||
msr->xml->sax_handler->error = xml_receive_sax_error;
|
||||
msr->xml->sax_handler->warning = xml_receive_sax_error;
|
||||
msr->xml->parsing_ctx = xmlCreatePushParserCtxt(msr->xml->sax_handler, msr,
|
||||
buf, size, "body.xml");
|
||||
|
||||
*/
|
||||
|
||||
msr->xml->parsing_ctx = xmlCreatePushParserCtxt(NULL, NULL, buf, size, "body.xml");
|
||||
if (msr->xml->parsing_ctx == NULL) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML: Failed to create parsing context.");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
|
||||
/* Not a first invocation. */
|
||||
|
||||
xmlParseChunk(msr->xml->parsing_ctx, buf, size, 0);
|
||||
if (msr->xml->parsing_ctx->wellFormed != 1) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalise XML parsing.
|
||||
*/
|
||||
int xml_complete(modsec_rec *msr, char **error_msg) {
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
/* Only if we have a context, meaning we've done some work. */
|
||||
if (msr->xml->parsing_ctx != NULL) {
|
||||
/* This is how we signalise the end of parsing to libxml. */
|
||||
xmlParseChunk(msr->xml->parsing_ctx, NULL, 0, 1);
|
||||
|
||||
/* Preserve the results for our reference. */
|
||||
msr->xml->well_formed = msr->xml->parsing_ctx->wellFormed;
|
||||
msr->xml->doc = msr->xml->parsing_ctx->myDoc;
|
||||
|
||||
/* Clean up everything else. */
|
||||
xmlFreeParserCtxt(msr->xml->parsing_ctx);
|
||||
msr->xml->parsing_ctx = NULL;
|
||||
msr_log(msr, 4, "XML: Parsing complete (well_formed %u).", msr->xml->well_formed);
|
||||
|
||||
if (msr->xml->well_formed != 1) {
|
||||
*error_msg = apr_psprintf(msr->mp, "XML: Failed parsing document.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees the resources used for XML parsing.
|
||||
*/
|
||||
apr_status_t xml_cleanup(modsec_rec *msr) {
|
||||
if (msr->xml->doc != NULL) {
|
||||
xmlFreeDoc(msr->xml->doc);
|
||||
msr->xml->doc = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_XML_H_
|
||||
#define _MSC_XML_H_
|
||||
|
||||
typedef struct xml_data xml_data;
|
||||
|
||||
#include "modsecurity.h"
|
||||
#include <libxml/xmlschemas.h>
|
||||
#include <libxml/xpath.h>
|
||||
|
||||
/* Structures */
|
||||
|
||||
struct xml_data {
|
||||
xmlSAXHandler *sax_handler;
|
||||
xmlParserCtxtPtr parsing_ctx;
|
||||
xmlDocPtr doc;
|
||||
|
||||
unsigned int well_formed;
|
||||
};
|
||||
|
||||
/* Functions */
|
||||
|
||||
int DSOLOCAL xml_init(modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL xml_process_chunk(modsec_rec *msr, const char *buf,
|
||||
unsigned int size, char **error_msg);
|
||||
|
||||
int DSOLOCAL xml_complete(modsec_rec *msr, char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL xml_cleanup(modsec_rec *msr);
|
||||
|
||||
#endif
|
||||
@@ -1,709 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "persist_dbm.h"
|
||||
#include "apr_sdbm.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size,
|
||||
int log_vars)
|
||||
{
|
||||
apr_table_t *col = NULL;
|
||||
unsigned int blob_offset;
|
||||
|
||||
col = apr_table_make(msr->mp, 32);
|
||||
if (col == NULL) return NULL;
|
||||
|
||||
/* ENH verify the first 3 bytes (header) */
|
||||
|
||||
blob_offset = 3;
|
||||
while (blob_offset + 1 < blob_size) {
|
||||
msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
|
||||
var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1];
|
||||
if (var->name_len == 0) {
|
||||
/* Is the length a name length, or just the end of the blob? */
|
||||
if (blob_offset < blob_size - 2) {
|
||||
/* This should never happen as the name length
|
||||
* includes the terminating NUL and should be 1 for ""
|
||||
*/
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset));
|
||||
}
|
||||
msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (var->name_len > 65536) {
|
||||
/* This should never happen as the length is restricted on store
|
||||
* to 65536.
|
||||
*/
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_unpack: BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset));
|
||||
}
|
||||
msr_log(msr, 4, "collection_unpack: Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
blob_offset += 2;
|
||||
if (blob_offset + var->name_len > blob_size) return NULL;
|
||||
var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1);
|
||||
blob_offset += var->name_len;
|
||||
var->name_len--;
|
||||
|
||||
var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1];
|
||||
blob_offset += 2;
|
||||
|
||||
if (blob_offset + var->value_len > blob_size) return NULL;
|
||||
var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1);
|
||||
blob_offset += var->value_len;
|
||||
var->value_len--;
|
||||
|
||||
if (log_vars && (msr->txcfg->debuglog_level >= 9)) {
|
||||
msr_log(msr, 9, "collection_unpack: Read variable: name \"%s\", value \"%s\".",
|
||||
log_escape_ex(msr->mp, var->name, var->name_len),
|
||||
log_escape_ex(msr->mp, var->value, var->value_len));
|
||||
}
|
||||
|
||||
apr_table_addn(col, var->name, (void *)var);
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name,
|
||||
const char *col_key, int col_key_len)
|
||||
{
|
||||
char *dbm_filename = NULL;
|
||||
apr_status_t rc;
|
||||
apr_sdbm_datum_t key;
|
||||
apr_sdbm_datum_t *value = NULL;
|
||||
apr_sdbm_t *dbm = NULL;
|
||||
apr_table_t *col = NULL;
|
||||
const apr_array_header_t *arr;
|
||||
apr_table_entry_t *te;
|
||||
int expired = 0;
|
||||
int i;
|
||||
|
||||
if (msr->txcfg->data_dir == NULL) {
|
||||
msr_log(msr, 1, "collection_retrieve_ex: Unable to retrieve collection (name \"%s\", key \"%s\"). Use "
|
||||
"SecDataDir to define data directory first.", log_escape(msr->mp, col_name),
|
||||
log_escape_ex(msr->mp, col_key, col_key_len));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_retrieve_ex: collection_retrieve_ex: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name),
|
||||
log_escape(msr->mp, dbm_filename));
|
||||
}
|
||||
|
||||
key.dptr = (char *)col_key;
|
||||
key.dsize = col_key_len + 1;
|
||||
|
||||
if (existing_dbm == NULL) {
|
||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK,
|
||||
CREATEMODE, msr->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
dbm = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbm = existing_dbm;
|
||||
}
|
||||
|
||||
value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t));
|
||||
rc = apr_sdbm_fetch(dbm, value, key);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_retrieve_ex: Failed to read from DBM file \"%s\": %s", log_escape(msr->mp,
|
||||
dbm_filename), get_apr_error(msr->mp, rc));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (value->dptr == NULL) { /* Key not found in DBM file. */
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* ENH Need expiration (and perhaps other metadata) accessible in blob
|
||||
* form to determine if converting to a table is needed. This will
|
||||
* save some cycles.
|
||||
*/
|
||||
|
||||
/* Transform raw data into a table. */
|
||||
col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1);
|
||||
if (col == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Close after "value" used from fetch or memory may be overwritten. */
|
||||
if (existing_dbm == NULL) {
|
||||
apr_sdbm_close(dbm);
|
||||
dbm = NULL;
|
||||
}
|
||||
|
||||
/* Remove expired variables. */
|
||||
do {
|
||||
arr = apr_table_elts(col);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
if (strncmp(te[i].key, "__expire_", 9) == 0) {
|
||||
msc_string *var = (msc_string *)te[i].val;
|
||||
int expiry_time = atoi(var->value);
|
||||
|
||||
if (expiry_time <= apr_time_sec(msr->request_time)) {
|
||||
char *key_to_expire = te[i].key;
|
||||
|
||||
/* Done early if the col expired */
|
||||
if (strcmp(key_to_expire, "__expire_KEY") == 0) {
|
||||
expired = 1;
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire + 9);
|
||||
msr_log(msr, 9, "collection_retrieve_ex: Removing key \"%s\" from collection.", key_to_expire);
|
||||
}
|
||||
|
||||
apr_table_unset(col, key_to_expire + 9);
|
||||
apr_table_unset(col, key_to_expire);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "collection_retrieve_ex: Removed expired variable \"%s\".", key_to_expire + 9);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(!expired && (i != arr->nelts));
|
||||
|
||||
/* Delete the collection if the variable "KEY" does not exist.
|
||||
*
|
||||
* ENH It would probably be more efficient to hold the DBM
|
||||
* open until determined if it needs deleted than to open a second
|
||||
* time.
|
||||
*/
|
||||
if (apr_table_get(col, "KEY") == NULL) {
|
||||
if (existing_dbm == NULL) {
|
||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
|
||||
CREATEMODE, msr->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_retrieve_ex: Failed to access DBM file \"%s\": %s",
|
||||
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
|
||||
dbm = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dbm = existing_dbm;
|
||||
}
|
||||
|
||||
rc = apr_sdbm_delete(dbm, key);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_retrieve_ex: Failed deleting collection (name \"%s\", "
|
||||
"key \"%s\"): %s", log_escape(msr->mp, col_name),
|
||||
log_escape_ex(msr->mp, col_key, col_key_len), get_apr_error(msr->mp, rc));
|
||||
msr->msc_sdbm_delete_error = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
if (existing_dbm == NULL) {
|
||||
apr_sdbm_close(dbm);
|
||||
dbm = NULL;
|
||||
}
|
||||
|
||||
if (expired && (msr->txcfg->debuglog_level >= 9)) {
|
||||
msr_log(msr, 9, "collection_retrieve_ex: Collection expired (name \"%s\", key \"%s\").", col_name,
|
||||
log_escape_ex(msr->mp, col_key, col_key_len));
|
||||
}
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "collection_retrieve_ex: Deleted collection (name \"%s\", key \"%s\").",
|
||||
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Update UPDATE_RATE */
|
||||
{
|
||||
msc_string *var;
|
||||
int create_time, counter;
|
||||
|
||||
var = (msc_string *)apr_table_get(col, "CREATE_TIME");
|
||||
if (var == NULL) {
|
||||
/* Error. */
|
||||
} else {
|
||||
create_time = atoi(var->value);
|
||||
var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER");
|
||||
if (var == NULL) {
|
||||
/* Error. */
|
||||
} else {
|
||||
apr_time_t td;
|
||||
counter = atoi(var->value);
|
||||
|
||||
/* UPDATE_RATE is removed on store, so add it back here */
|
||||
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
var->name = "UPDATE_RATE";
|
||||
var->name_len = strlen(var->name);
|
||||
apr_table_setn(col, var->name, (void *)var);
|
||||
|
||||
/* NOTE: No rate if there has been no time elapsed */
|
||||
td = (apr_time_sec(apr_time_now()) - create_time);
|
||||
if (td == 0) {
|
||||
var->value = apr_psprintf(msr->mp, "%d", 0);
|
||||
}
|
||||
else {
|
||||
var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT,
|
||||
(apr_time_t)((60 * counter)/td));
|
||||
}
|
||||
var->value_len = strlen(var->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "collection_retrieve_ex: Retrieved collection (name \"%s\", key \"%s\").",
|
||||
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
|
||||
}
|
||||
|
||||
if ((existing_dbm == NULL) && dbm) {
|
||||
/* Should not ever get here */
|
||||
msr_log(msr, 1, "collection_retrieve_ex: Internal Error: Collection remained open (name \"%s\", key \"%s\").",
|
||||
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, col_key, col_key_len));
|
||||
|
||||
apr_sdbm_close(dbm);
|
||||
}
|
||||
|
||||
return col;
|
||||
|
||||
cleanup:
|
||||
|
||||
if ((existing_dbm == NULL) && dbm) {
|
||||
apr_sdbm_close(dbm);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
|
||||
const char *col_key, int col_key_len)
|
||||
{
|
||||
apr_time_t time_before = apr_time_now();
|
||||
apr_table_t *rtable = NULL;
|
||||
|
||||
rtable = collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len);
|
||||
|
||||
msr->time_storage_read += apr_time_now() - time_before;
|
||||
|
||||
return rtable;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int collection_store(modsec_rec *msr, apr_table_t *col) {
|
||||
char *dbm_filename = NULL;
|
||||
msc_string *var_name = NULL, *var_key = NULL;
|
||||
unsigned char *blob = NULL;
|
||||
unsigned int blob_size, blob_offset;
|
||||
apr_status_t rc;
|
||||
apr_sdbm_datum_t key;
|
||||
apr_sdbm_datum_t value;
|
||||
apr_sdbm_t *dbm = NULL;
|
||||
const apr_array_header_t *arr;
|
||||
apr_table_entry_t *te;
|
||||
int i;
|
||||
const apr_table_t *stored_col = NULL;
|
||||
const apr_table_t *orig_col = NULL;
|
||||
|
||||
var_name = (msc_string *)apr_table_get(col, "__name");
|
||||
if (var_name == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
var_key = (msc_string *)apr_table_get(col, "__key");
|
||||
if (var_key == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (msr->txcfg->data_dir == NULL) {
|
||||
msr_log(msr, 1, "collection_store: Unable to store collection (name \"%s\", key \"%s\"). Use "
|
||||
"SecDataDir to define data directory first.", log_escape_ex(msr->mp, var_name->value, var_name->value_len),
|
||||
log_escape_ex(msr->mp, var_key->value, var_key->value_len));
|
||||
goto error;
|
||||
}
|
||||
|
||||
// ENH: lowercase the var name in the filename
|
||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", var_name->value, NULL);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_store: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, var_name->value),
|
||||
log_escape(msr->mp, dbm_filename));
|
||||
}
|
||||
|
||||
/* Delete IS_NEW on store. */
|
||||
apr_table_unset(col, "IS_NEW");
|
||||
|
||||
/* Delete UPDATE_RATE on store to save space as it is calculated */
|
||||
apr_table_unset(col, "UPDATE_RATE");
|
||||
|
||||
/* Update the timeout value. */
|
||||
{
|
||||
msc_string *var = (msc_string *)apr_table_get(col, "TIMEOUT");
|
||||
if (var != NULL) {
|
||||
int timeout = atoi(var->value);
|
||||
var = (msc_string *)apr_table_get(col, "__expire_KEY");
|
||||
if (var != NULL) {
|
||||
var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now()) + timeout));
|
||||
var->value_len = strlen(var->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* LAST_UPDATE_TIME */
|
||||
{
|
||||
msc_string *var = (msc_string *)apr_table_get(col, "LAST_UPDATE_TIME");
|
||||
if (var == NULL) {
|
||||
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
var->name = "LAST_UPDATE_TIME";
|
||||
var->name_len = strlen(var->name);
|
||||
apr_table_setn(col, var->name, (void *)var);
|
||||
}
|
||||
var->value = apr_psprintf(msr->mp, "%" APR_TIME_T_FMT, (apr_time_t)(apr_time_sec(apr_time_now())));
|
||||
var->value_len = strlen(var->value);
|
||||
}
|
||||
|
||||
/* UPDATE_COUNTER */
|
||||
{
|
||||
msc_string *var = (msc_string *)apr_table_get(col, "UPDATE_COUNTER");
|
||||
int counter = 0;
|
||||
if (var == NULL) {
|
||||
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
|
||||
var->name = "UPDATE_COUNTER";
|
||||
var->name_len = strlen(var->name);
|
||||
apr_table_setn(col, var->name, (void *)var);
|
||||
} else {
|
||||
counter = atoi(var->value);
|
||||
}
|
||||
var->value = apr_psprintf(msr->mp, "%d", counter + 1);
|
||||
var->value_len = strlen(var->value);
|
||||
}
|
||||
|
||||
/* ENH Make the expiration timestamp accessible in blob form so that
|
||||
* it is easier/faster to determine expiration without having to
|
||||
* convert back to table form
|
||||
*/
|
||||
|
||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
|
||||
CREATEMODE, msr->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_store: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
|
||||
get_apr_error(msr->mp, rc));
|
||||
dbm = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Need to lock to pull in the stored data again and apply deltas. */
|
||||
rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_store: Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
|
||||
get_apr_error(msr->mp, rc));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If there is an original value, then create a delta and
|
||||
* apply the delta to the current value */
|
||||
orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value);
|
||||
if (orig_col != NULL) {
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_store: Re-retrieving collection prior to store: %s",
|
||||
apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value));
|
||||
}
|
||||
|
||||
stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len);
|
||||
}
|
||||
|
||||
/* Merge deltas and calculate the size first. */
|
||||
blob_size = 3 + 2;
|
||||
arr = apr_table_elts(col);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
msc_string *var = (msc_string *)te[i].val;
|
||||
int len;
|
||||
|
||||
/* If there is an original value, then apply the delta
|
||||
* to the latest stored value */
|
||||
if (stored_col != NULL) {
|
||||
const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name);
|
||||
if (orig_var != NULL) {
|
||||
const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name);
|
||||
if (stored_var != NULL) {
|
||||
int origval = atoi(orig_var->value);
|
||||
int ourval = atoi(var->value);
|
||||
int storedval = atoi(stored_var->value);
|
||||
int delta = ourval - origval;
|
||||
int newval = storedval + delta;
|
||||
|
||||
if (newval < 0) newval = 0; /* Counters never go below zero. */
|
||||
|
||||
var->value = apr_psprintf(msr->mp, "%d", newval);
|
||||
var->value_len = strlen(var->value);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_store: Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]",
|
||||
log_escape_ex(msr->mp, var_name->value, var_name->value_len),
|
||||
log_escape_ex(msr->mp, var->name, var->name_len),
|
||||
origval, ourval, delta, storedval, delta, newval, var->value, var->value_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = var->name_len + 1;
|
||||
if (len >= 65536) len = 65536;
|
||||
blob_size += len + 2;
|
||||
|
||||
len = var->value_len + 1;
|
||||
if (len >= 65536) len = 65536;
|
||||
blob_size += len + 2;
|
||||
}
|
||||
|
||||
/* Now generate the binary object. */
|
||||
blob = apr_pcalloc(msr->mp, blob_size);
|
||||
if (blob == NULL) {
|
||||
if (dbm != NULL) {
|
||||
apr_sdbm_unlock(dbm);
|
||||
apr_sdbm_close(dbm);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
blob[0] = 0x49;
|
||||
blob[1] = 0x52;
|
||||
blob[2] = 0x01;
|
||||
|
||||
blob_offset = 3;
|
||||
arr = apr_table_elts(col);
|
||||
te = (apr_table_entry_t *)arr->elts;
|
||||
for (i = 0; i < arr->nelts; i++) {
|
||||
msc_string *var = (msc_string *)te[i].val;
|
||||
int len;
|
||||
|
||||
len = var->name_len + 1;
|
||||
if (len >= 65536) len = 65536;
|
||||
|
||||
blob[blob_offset + 0] = (len & 0xff00) >> 8;
|
||||
blob[blob_offset + 1] = len & 0x00ff;
|
||||
memcpy(blob + blob_offset + 2, var->name, len - 1);
|
||||
blob[blob_offset + 2 + len - 1] = '\0';
|
||||
blob_offset += 2 + len;
|
||||
|
||||
len = var->value_len + 1;
|
||||
if (len >= 65536) len = 65536;
|
||||
|
||||
blob[blob_offset + 0] = (len & 0xff00) >> 8;
|
||||
blob[blob_offset + 1] = len & 0x00ff;
|
||||
memcpy(blob + blob_offset + 2, var->value, len - 1);
|
||||
blob[blob_offset + 2 + len - 1] = '\0';
|
||||
blob_offset += 2 + len;
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collection_store: Wrote variable: name \"%s\", value \"%s\".",
|
||||
log_escape_ex(msr->mp, var->name, var->name_len),
|
||||
log_escape_ex(msr->mp, var->value, var->value_len));
|
||||
}
|
||||
}
|
||||
|
||||
blob[blob_offset] = 0;
|
||||
blob[blob_offset + 1] = 0;
|
||||
|
||||
/* And, finally, store it. */
|
||||
key.dptr = var_key->value;
|
||||
key.dsize = var_key->value_len + 1;
|
||||
|
||||
value.dptr = (char *)blob;
|
||||
value.dsize = blob_size;
|
||||
|
||||
rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collection_store: Failed to write to DBM file \"%s\": %s", dbm_filename,
|
||||
get_apr_error(msr->mp, rc));
|
||||
if (dbm != NULL) {
|
||||
apr_sdbm_unlock(dbm);
|
||||
apr_sdbm_close(dbm);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
apr_sdbm_unlock(dbm);
|
||||
apr_sdbm_close(dbm);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "collection_store: Persisted collection (name \"%s\", key \"%s\").",
|
||||
log_escape_ex(msr->mp, var_name->value, var_name->value_len),
|
||||
log_escape_ex(msr->mp, var_key->value, var_key->value_len));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int collections_remove_stale(modsec_rec *msr, const char *col_name) {
|
||||
char *dbm_filename = NULL;
|
||||
apr_sdbm_datum_t key, value;
|
||||
apr_sdbm_t *dbm = NULL;
|
||||
apr_status_t rc;
|
||||
apr_array_header_t *keys_arr;
|
||||
char **keys;
|
||||
apr_time_t now = apr_time_sec(msr->request_time);
|
||||
int i;
|
||||
|
||||
if (msr->txcfg->data_dir == NULL) {
|
||||
/* The user has been warned about this problem enough times already by now.
|
||||
* msr_log(msr, 1, "Unable to access collection file (name \"%s\"). Use SecDataDir to "
|
||||
* "define data directory first.", log_escape(msr->mp, col_name));
|
||||
*/
|
||||
goto error;
|
||||
}
|
||||
|
||||
if(strstr(col_name,"USER") || strstr(col_name,"SESSION") || strstr(col_name, "RESOURCE"))
|
||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", msr->txcfg->webappid, "_", col_name, NULL);
|
||||
else
|
||||
dbm_filename = apr_pstrcat(msr->mp, msr->txcfg->data_dir, "/", col_name, NULL);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collections_remove_stale: Retrieving collection (name \"%s\", filename \"%s\")",log_escape(msr->mp, col_name),
|
||||
log_escape(msr->mp, dbm_filename));
|
||||
}
|
||||
|
||||
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
|
||||
CREATEMODE, msr->mp);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collections_remove_stale: Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
|
||||
get_apr_error(msr->mp, rc));
|
||||
dbm = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* First get a list of all keys. */
|
||||
keys_arr = apr_array_make(msr->mp, 256, sizeof(char *));
|
||||
rc = apr_sdbm_lock(dbm, APR_FLOCK_SHARED);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collections_remove_stale: Failed to lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
|
||||
get_apr_error(msr->mp, rc));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* No one can write to the file while doing this so
|
||||
* do it as fast as possible.
|
||||
*/
|
||||
rc = apr_sdbm_firstkey(dbm, &key);
|
||||
while(rc == APR_SUCCESS) {
|
||||
char *s = apr_pstrmemdup(msr->mp, key.dptr, key.dsize - 1);
|
||||
*(char **)apr_array_push(keys_arr) = s;
|
||||
rc = apr_sdbm_nextkey(dbm, &key);
|
||||
}
|
||||
apr_sdbm_unlock(dbm);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collections_remove_stale: Found %d record(s) in file \"%s\".", keys_arr->nelts,
|
||||
log_escape(msr->mp, dbm_filename));
|
||||
}
|
||||
|
||||
/* Now retrieve the entires one by one. */
|
||||
keys = (char **)keys_arr->elts;
|
||||
for (i = 0; i < keys_arr->nelts; i++) {
|
||||
key.dptr = keys[i];
|
||||
key.dsize = strlen(key.dptr) + 1;
|
||||
|
||||
rc = apr_sdbm_fetch(dbm, &value, key);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collections_remove_stale: Failed reading DBM file \"%s\": %s",
|
||||
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (value.dptr != NULL) {
|
||||
apr_table_t *col = NULL;
|
||||
msc_string *var = NULL;
|
||||
|
||||
col = collection_unpack(msr, (const unsigned char *)value.dptr, value.dsize, 0);
|
||||
if (col == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
var = (msc_string *)apr_table_get(col, "__expire_KEY");
|
||||
if (var == NULL) {
|
||||
msr_log(msr, 1, "collections_remove_stale: Collection cleanup discovered entry with no "
|
||||
"__expire_KEY (name \"%s\", key \"%s\").",
|
||||
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
|
||||
} else {
|
||||
unsigned int expiry_time = atoi(var->value);
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 9) {
|
||||
msr_log(msr, 9, "collections_remove_stale: Record (name \"%s\", key \"%s\") set to expire in %" APR_TIME_T_FMT " seconds.",
|
||||
log_escape(msr->mp, col_name), log_escape_ex(msr->mp, key.dptr, key.dsize - 1),
|
||||
expiry_time - now);
|
||||
}
|
||||
|
||||
if (expiry_time <= now) {
|
||||
rc = apr_sdbm_delete(dbm, key);
|
||||
if (rc != APR_SUCCESS) {
|
||||
msr_log(msr, 1, "collections_remove_stale: Failed deleting collection (name \"%s\", "
|
||||
"key \"%s\"): %s", log_escape(msr->mp, col_name),
|
||||
log_escape_ex(msr->mp, key.dptr, key.dsize - 1), get_apr_error(msr->mp, rc));
|
||||
msr->msc_sdbm_delete_error = 1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (msr->txcfg->debuglog_level >= 4) {
|
||||
msr_log(msr, 4, "collections_remove_stale: Removed stale collection (name \"%s\", "
|
||||
"key \"%s\").", log_escape(msr->mp, col_name),
|
||||
log_escape_ex(msr->mp, key.dptr, key.dsize - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Ignore entry not found - it may have been removed in the meantime. */
|
||||
}
|
||||
}
|
||||
|
||||
apr_sdbm_close(dbm);
|
||||
|
||||
return 1;
|
||||
|
||||
error:
|
||||
|
||||
if (dbm) {
|
||||
apr_sdbm_close(dbm);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _PERSIST_DBM_H_
|
||||
#define _PERSIST_DBM_H_
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "modsecurity.h"
|
||||
|
||||
apr_table_t DSOLOCAL *collection_retrieve(modsec_rec *msr, const char *col_name,
|
||||
const char *col_value, int col_value_length);
|
||||
|
||||
int DSOLOCAL collection_store(modsec_rec *msr, apr_table_t *collection);
|
||||
|
||||
int DSOLOCAL collections_remove_stale(modsec_rec *msr, const char *col_name);
|
||||
|
||||
#endif
|
||||
3389
apache2/re.c
3389
apache2/re.c
File diff suppressed because it is too large
Load Diff
417
apache2/re.h
417
apache2/re.h
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#ifndef _MSC_RE_H_
|
||||
#define _MSC_RE_H_
|
||||
|
||||
#define ABSOLUTE_VALUE 0
|
||||
#define POSITIVE_VALUE 1
|
||||
#define NEGATIVE_VALUE 2
|
||||
|
||||
typedef struct msre_engine msre_engine;
|
||||
typedef struct msre_ruleset msre_ruleset;
|
||||
typedef struct msre_ruleset_internal msre_ruleset_internal;
|
||||
typedef struct msre_rule msre_rule;
|
||||
typedef struct msre_var_metadata msre_var_metadata;
|
||||
typedef struct msre_var msre_var;
|
||||
typedef struct msre_op_metadata msre_op_metadata;
|
||||
typedef struct msre_tfn_metadata msre_tfn_metadata;
|
||||
typedef struct msre_actionset msre_actionset;
|
||||
typedef struct msre_action_metadata msre_action_metadata;
|
||||
typedef struct msre_action msre_action;
|
||||
typedef struct msre_reqbody_processor_metadata msre_reqbody_processor_metadata;
|
||||
typedef struct msre_cache_rec msre_cache_rec;
|
||||
|
||||
#include "apr_general.h"
|
||||
#include "apr_tables.h"
|
||||
#include "modsecurity.h"
|
||||
#include "msc_pcre.h"
|
||||
#include "msc_tree.h"
|
||||
#include "persist_dbm.h"
|
||||
#include "apache2.h"
|
||||
#include "http_config.h"
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
#include "msc_lua.h"
|
||||
#endif
|
||||
|
||||
/* Actions, variables, functions and operator functions */
|
||||
char DSOLOCAL *update_rule_target_ex(modsec_rec *msr, msre_ruleset *ruleset, msre_rule *rule, const char *p2,
|
||||
const char *p3);
|
||||
|
||||
int DSOLOCAL msre_ruleset_rule_matches_exception(msre_rule *rule, rule_exception *re);
|
||||
|
||||
char DSOLOCAL *msre_ruleset_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
|
||||
const char *p2, const char *p3);
|
||||
|
||||
char DSOLOCAL *msre_ruleset_phase_rule_update_target_matching_exception(modsec_rec *msr, msre_ruleset *ruleset, rule_exception *re,
|
||||
apr_array_header_t *phase_arr, const char *p2, const char *p3);
|
||||
|
||||
apr_status_t DSOLOCAL collection_original_setvar(modsec_rec *msr, const char *col_name, const msc_string *orig_var);
|
||||
|
||||
int DSOLOCAL expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t *mptmp);
|
||||
|
||||
msre_var_metadata DSOLOCAL *msre_resolve_var(msre_engine *engine, const char *name);
|
||||
|
||||
msre_var DSOLOCAL *msre_create_var_ex(apr_pool_t *pool, msre_engine *engine, const char *name, const char *param,
|
||||
modsec_rec *msr, char **error_msg);
|
||||
|
||||
int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t *vartable,
|
||||
char **error_msg);
|
||||
|
||||
int DSOLOCAL rule_id_in_range(int ruleid, const char *range);
|
||||
|
||||
msre_var DSOLOCAL *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
|
||||
msre_rule *rule, apr_pool_t *mptmp);
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
apr_table_t DSOLOCAL *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header_t *tfn_arr,
|
||||
msre_rule *rule, apr_pool_t *mptmp);
|
||||
#endif
|
||||
|
||||
/* Structures with the corresponding functions */
|
||||
|
||||
struct msre_engine {
|
||||
apr_pool_t *mp;
|
||||
apr_table_t *variables;
|
||||
apr_table_t *operators;
|
||||
apr_table_t *actions;
|
||||
apr_table_t *tfns;
|
||||
apr_table_t *reqbody_processors;
|
||||
};
|
||||
|
||||
msre_engine DSOLOCAL *msre_engine_create(apr_pool_t *parent_pool);
|
||||
|
||||
void DSOLOCAL msre_engine_destroy(msre_engine *engine);
|
||||
|
||||
msre_op_metadata DSOLOCAL *msre_engine_op_resolve(msre_engine *engine, const char *name);
|
||||
|
||||
struct msre_ruleset {
|
||||
apr_pool_t *mp;
|
||||
msre_engine *engine;
|
||||
|
||||
apr_array_header_t *phase_request_headers;
|
||||
apr_array_header_t *phase_request_body;
|
||||
apr_array_header_t *phase_response_headers;
|
||||
apr_array_header_t *phase_response_body;
|
||||
apr_array_header_t *phase_logging;
|
||||
};
|
||||
|
||||
apr_status_t DSOLOCAL msre_ruleset_process_phase(msre_ruleset *ruleset, modsec_rec *msr);
|
||||
|
||||
apr_status_t DSOLOCAL msre_ruleset_process_phase_internal(msre_ruleset *ruleset, modsec_rec *msr);
|
||||
|
||||
msre_ruleset DSOLOCAL *msre_ruleset_create(msre_engine *engine, apr_pool_t *mp);
|
||||
|
||||
int DSOLOCAL msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase);
|
||||
|
||||
msre_rule DSOLOCAL *msre_ruleset_fetch_rule(msre_ruleset *ruleset, const char *id, int offset);
|
||||
|
||||
int DSOLOCAL msre_ruleset_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re);
|
||||
|
||||
/*
|
||||
int DSOLOCAL msre_ruleset_phase_rule_remove_with_exception(msre_ruleset *ruleset, rule_exception *re,
|
||||
apr_array_header_t *phase_arr);
|
||||
*/
|
||||
|
||||
#define RULE_NO_MATCH 0
|
||||
#define RULE_MATCH 1
|
||||
|
||||
#define RULE_PH_NONE 0 /* Not a placeholder */
|
||||
#define RULE_PH_SKIPAFTER 1 /* Implicit placeholder for skipAfter */
|
||||
#define RULE_PH_MARKER 2 /* Explicit placeholder for SecMarker */
|
||||
|
||||
#define RULE_TYPE_NORMAL 0 /* SecRule */
|
||||
#define RULE_TYPE_ACTION 1 /* SecAction */
|
||||
#define RULE_TYPE_MARKER 2 /* SecMarker */
|
||||
#if defined(WITH_LUA)
|
||||
#define RULE_TYPE_LUA 3 /* SecRuleScript */
|
||||
#endif
|
||||
|
||||
struct msre_rule {
|
||||
apr_array_header_t *targets;
|
||||
const char *op_name;
|
||||
const char *op_param;
|
||||
void *op_param_data;
|
||||
msre_op_metadata *op_metadata;
|
||||
unsigned int op_negated;
|
||||
msre_actionset *actionset;
|
||||
const char *p1;
|
||||
const char *unparsed;
|
||||
const char *filename;
|
||||
int line_num;
|
||||
int placeholder;
|
||||
int type;
|
||||
|
||||
msre_ruleset *ruleset;
|
||||
msre_rule *chain_starter;
|
||||
#if defined(PERFORMANCE_MEASUREMENT)
|
||||
unsigned int execution_time;
|
||||
unsigned int trans_time;
|
||||
unsigned int op_time;
|
||||
#endif
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
/* Compiled Lua script. */
|
||||
msc_script *script;
|
||||
#endif
|
||||
|
||||
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 0
|
||||
ap_regex_t *sub_regex;
|
||||
#else
|
||||
regex_t *sub_regex;
|
||||
#endif
|
||||
char *sub_str;
|
||||
char *re_str;
|
||||
int re_precomp;
|
||||
int escape_re;
|
||||
|
||||
TreeRoot *ip_op;
|
||||
};
|
||||
|
||||
char DSOLOCAL *msre_rule_generate_unparsed(apr_pool_t *pool, const msre_rule *rule, const char *targets, const char *args, const char *actions);
|
||||
|
||||
msre_rule DSOLOCAL *msre_rule_create(msre_ruleset *ruleset, int type,
|
||||
const char *fn, int line, const char *targets,
|
||||
const char *args, const char *actions, char **error_msg);
|
||||
|
||||
#if defined(WITH_LUA)
|
||||
msre_rule DSOLOCAL *msre_rule_lua_create(msre_ruleset *ruleset,
|
||||
const char *fn, int line, const char *script_filename,
|
||||
const char *actions, char **error_msg);
|
||||
#endif
|
||||
|
||||
#define VAR_SIMPLE 0 /* REQUEST_URI */
|
||||
#define VAR_LIST 1
|
||||
|
||||
#define PHASE_REQUEST_HEADERS 1
|
||||
#define PHASE_REQUEST_BODY 2
|
||||
#define PHASE_RESPONSE_HEADERS 3
|
||||
#define PHASE_RESPONSE_BODY 4
|
||||
#define PHASE_LOGGING 5
|
||||
|
||||
typedef int (*fn_op_param_init_t)(msre_rule *rule, char **error_msg);
|
||||
typedef int (*fn_op_execute_t)(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg);
|
||||
|
||||
struct msre_op_metadata {
|
||||
const char *name;
|
||||
fn_op_param_init_t param_init;
|
||||
fn_op_execute_t execute;
|
||||
};
|
||||
|
||||
typedef int (*fn_tfn_execute_t)(apr_pool_t *pool, unsigned char *input, long int input_length, char **rval, long int *rval_length);
|
||||
|
||||
struct msre_tfn_metadata {
|
||||
const char *name;
|
||||
|
||||
/* Functions should populate *rval and return 1 on
|
||||
* success, or return -1 on failure (in which case *rval
|
||||
* should contain the error message. Strict functions
|
||||
* (those that validate in
|
||||
* addition to transforming) can return 0 when input
|
||||
* fails validation. Functions are free to perform
|
||||
* in-place transformation, or to allocate a new buffer
|
||||
* from the provideded temporary (per-rule) memory pool.
|
||||
*
|
||||
* NOTE Strict transformation functions not supported yet.
|
||||
*/
|
||||
fn_tfn_execute_t execute;
|
||||
};
|
||||
|
||||
void DSOLOCAL msre_engine_tfn_register(msre_engine *engine, const char *name,
|
||||
fn_tfn_execute_t execute);
|
||||
|
||||
void DSOLOCAL msre_engine_op_register(msre_engine *engine, const char *name,
|
||||
fn_op_param_init_t fn1, fn_op_execute_t fn2);
|
||||
|
||||
void DSOLOCAL msre_engine_register_default_tfns(msre_engine *engine);
|
||||
|
||||
void DSOLOCAL msre_engine_register_default_variables(msre_engine *engine);
|
||||
|
||||
void DSOLOCAL msre_engine_register_default_operators(msre_engine *engine);
|
||||
|
||||
void DSOLOCAL msre_engine_register_default_actions(msre_engine *engine);
|
||||
|
||||
msre_tfn_metadata DSOLOCAL *msre_engine_tfn_resolve(msre_engine *engine, const char *name);
|
||||
|
||||
#define VAR_DONT_CACHE 0
|
||||
#define VAR_CACHE 1
|
||||
|
||||
typedef char *(*fn_var_validate_t)(msre_ruleset *ruleset, msre_var *var);
|
||||
typedef int (*fn_var_generate_t)(modsec_rec *msr, msre_var *var, msre_rule *rule, apr_table_t *table, apr_pool_t *mptmp);
|
||||
|
||||
struct msre_var_metadata {
|
||||
const char *name;
|
||||
unsigned int type; /* VAR_TYPE_ constants */
|
||||
unsigned int argc_min;
|
||||
unsigned int argc_max;
|
||||
fn_var_validate_t validate;
|
||||
fn_var_generate_t generate;
|
||||
unsigned int is_cacheable; /* 0 - no, 1 - yes */
|
||||
unsigned int availability; /* when does this variable become available? */
|
||||
};
|
||||
|
||||
struct msre_var {
|
||||
char *name;
|
||||
const char *value;
|
||||
unsigned int value_len;
|
||||
char *param;
|
||||
const void *param_data;
|
||||
msre_var_metadata *metadata;
|
||||
msc_regex_t *param_regex;
|
||||
unsigned int is_negated;
|
||||
unsigned int is_counting;
|
||||
};
|
||||
|
||||
|
||||
struct msre_actionset {
|
||||
apr_table_t *actions;
|
||||
|
||||
/* Metadata */
|
||||
const char *id;
|
||||
const char *rev;
|
||||
const char *msg;
|
||||
const char *logdata;
|
||||
const char *version;
|
||||
int maturity;
|
||||
int accuracy;
|
||||
int severity;
|
||||
int phase;
|
||||
msre_rule *rule;
|
||||
int arg_min;
|
||||
int arg_max;
|
||||
|
||||
/* Flow */
|
||||
int is_chained;
|
||||
int skip_count;
|
||||
const char *skip_after;
|
||||
|
||||
/* Disruptive */
|
||||
int intercept_action;
|
||||
const char *intercept_uri;
|
||||
int intercept_status;
|
||||
const char *intercept_pause;
|
||||
|
||||
/* "block" needs parent action to reset it */
|
||||
msre_action *parent_intercept_action_rec;
|
||||
msre_action *intercept_action_rec;
|
||||
int parent_intercept_action;
|
||||
|
||||
/* Other */
|
||||
int log;
|
||||
int auditlog;
|
||||
int block;
|
||||
};
|
||||
|
||||
void DSOLOCAL msre_engine_variable_register(msre_engine *engine, const char *name,
|
||||
unsigned int type, unsigned int argc_min, unsigned int argc_max,
|
||||
fn_var_validate_t validate, fn_var_generate_t generate,
|
||||
unsigned int is_cacheable, unsigned int availability);
|
||||
|
||||
msre_actionset DSOLOCAL *msre_actionset_create(msre_engine *engine, apr_pool_t *mp, const char *text,
|
||||
char **error_msg);
|
||||
|
||||
msre_actionset DSOLOCAL *msre_actionset_merge(msre_engine *engine, apr_pool_t *mp, msre_actionset *parent,
|
||||
msre_actionset *child, int inherit_by_default);
|
||||
|
||||
msre_actionset DSOLOCAL *msre_actionset_create_default(msre_engine *engine);
|
||||
|
||||
void DSOLOCAL msre_actionset_set_defaults(msre_actionset *actionset);
|
||||
|
||||
void DSOLOCAL msre_actionset_init(msre_actionset *actionset, msre_rule *rule);
|
||||
|
||||
typedef char *(*fn_action_validate_t)(msre_engine *engine, apr_pool_t *mp, msre_action *action);
|
||||
typedef apr_status_t (*fn_action_init_t)(msre_engine *engine, apr_pool_t *mp, msre_actionset *actionset, msre_action *action);
|
||||
typedef apr_status_t (*fn_action_execute_t)(modsec_rec *msr, apr_pool_t *mptmp, msre_rule *rule, msre_action *action);
|
||||
|
||||
#define ACTION_DISRUPTIVE 1
|
||||
#define ACTION_NON_DISRUPTIVE 2
|
||||
#define ACTION_METADATA 3
|
||||
#define ACTION_FLOW 4
|
||||
|
||||
#define NO_PLUS_MINUS 0
|
||||
#define ALLOW_PLUS_MINUS 1
|
||||
|
||||
#define ACTION_CARDINALITY_ONE 1
|
||||
#define ACTION_CARDINALITY_MANY 2
|
||||
|
||||
#define ACTION_CGROUP_NONE 0
|
||||
#define ACTION_CGROUP_DISRUPTIVE 1
|
||||
#define ACTION_CGROUP_LOG 2
|
||||
#define ACTION_CGROUP_AUDITLOG 3
|
||||
|
||||
struct msre_action_metadata {
|
||||
const char *name;
|
||||
unsigned int type;
|
||||
unsigned int argc_min;
|
||||
unsigned int argc_max;
|
||||
unsigned int allow_param_plusminus;
|
||||
unsigned int cardinality;
|
||||
unsigned int cardinality_group;
|
||||
fn_action_validate_t validate;
|
||||
fn_action_init_t init;
|
||||
fn_action_execute_t execute;
|
||||
};
|
||||
|
||||
struct msre_action {
|
||||
msre_action_metadata *metadata;
|
||||
const char *param;
|
||||
const void *param_data;
|
||||
unsigned int param_plusminus; /* ABSOLUTE_VALUE, POSITIVE_VALUE, NEGATIVE_VALUE */
|
||||
};
|
||||
|
||||
void DSOLOCAL msre_engine_reqbody_processor_register(msre_engine *engine,
|
||||
const char *name, void *fn_init, void *fn_process, void *fn_complete);
|
||||
|
||||
typedef int (*fn_reqbody_processor_init_t)(modsec_rec *msr, char **error_msg);
|
||||
typedef int (*fn_reqbody_processor_process_t)(modsec_rec *msr, const char *buf,
|
||||
unsigned int size, char **error_msg);
|
||||
typedef int (*fn_reqbody_processor_complete_t)(modsec_rec *msr, char **error_msg);
|
||||
|
||||
struct msre_reqbody_processor_metadata {
|
||||
const char *name;
|
||||
fn_reqbody_processor_init_t init;
|
||||
fn_reqbody_processor_process_t process;
|
||||
fn_reqbody_processor_complete_t complete;
|
||||
};
|
||||
|
||||
/* -- MSRE Function Prototypes ---------------------------------------------- */
|
||||
|
||||
msre_var_metadata DSOLOCAL *msre_resolve_var(msre_engine *engine, const char *name);
|
||||
|
||||
int DSOLOCAL msre_parse_generic(apr_pool_t *pool, const char *text, apr_table_t *vartable,
|
||||
char **error_msg);
|
||||
|
||||
apr_status_t DSOLOCAL msre_parse_vars(msre_ruleset *ruleset, const char *text,
|
||||
apr_array_header_t *arr, char **error_msg);
|
||||
|
||||
char DSOLOCAL *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset);
|
||||
|
||||
/* -- Data Cache -- */
|
||||
|
||||
struct msre_cache_rec {
|
||||
int hits;
|
||||
int changed;
|
||||
int num;
|
||||
const char *path;
|
||||
const char *val;
|
||||
apr_size_t val_len;
|
||||
};
|
||||
|
||||
struct fuzzy_hash_param_data {
|
||||
const char *file;
|
||||
int threshold;
|
||||
};
|
||||
|
||||
#endif
|
||||
2956
apache2/re_actions.c
2956
apache2/re_actions.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1051
apache2/re_tfns.c
1051
apache2/re_tfns.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,815 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef UTF8TABLES_H_
|
||||
#define UTF8TABLES_H_
|
||||
|
||||
/**
|
||||
* This include file is used by acmp.c only; it's not included anywhere else.
|
||||
*/
|
||||
|
||||
typedef long acmp_utf8_char_t;
|
||||
|
||||
static const char utf8_seq_lengths[256] = {
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
|
||||
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
|
||||
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,
|
||||
4,4,4,4,4,4,4,4, 5,5,5,5,6,6,6,6,
|
||||
};
|
||||
|
||||
static const acmp_utf8_char_t utf8_offsets[6] = {
|
||||
0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL
|
||||
};
|
||||
|
||||
/**
|
||||
* How many element pairs are there in utf8_lcase_map
|
||||
*/
|
||||
#define UTF8_LCASEMAP_LEN 759
|
||||
|
||||
/**
|
||||
* Table mapping is from PHP's mbstring extension, maps uppercase
|
||||
*/
|
||||
static const acmp_utf8_char_t utf8_lcase_map[UTF8_LCASEMAP_LEN * 2] = {
|
||||
0x00000061, 0x00000041,
|
||||
0x00000062, 0x00000042,
|
||||
0x00000063, 0x00000043,
|
||||
0x00000064, 0x00000044,
|
||||
0x00000065, 0x00000045,
|
||||
0x00000066, 0x00000046,
|
||||
0x00000067, 0x00000047,
|
||||
0x00000068, 0x00000048,
|
||||
0x00000069, 0x00000049,
|
||||
0x0000006a, 0x0000004a,
|
||||
0x0000006b, 0x0000004b,
|
||||
0x0000006c, 0x0000004c,
|
||||
0x0000006d, 0x0000004d,
|
||||
0x0000006e, 0x0000004e,
|
||||
0x0000006f, 0x0000004f,
|
||||
0x00000070, 0x00000050,
|
||||
0x00000071, 0x00000051,
|
||||
0x00000072, 0x00000052,
|
||||
0x00000073, 0x00000053,
|
||||
0x00000074, 0x00000054,
|
||||
0x00000075, 0x00000055,
|
||||
0x00000076, 0x00000056,
|
||||
0x00000077, 0x00000057,
|
||||
0x00000078, 0x00000058,
|
||||
0x00000079, 0x00000059,
|
||||
0x0000007a, 0x0000005a,
|
||||
0x000000b5, 0x0000039c,
|
||||
0x000000e0, 0x000000c0,
|
||||
0x000000e1, 0x000000c1,
|
||||
0x000000e2, 0x000000c2,
|
||||
0x000000e3, 0x000000c3,
|
||||
0x000000e4, 0x000000c4,
|
||||
0x000000e5, 0x000000c5,
|
||||
0x000000e6, 0x000000c6,
|
||||
0x000000e7, 0x000000c7,
|
||||
0x000000e8, 0x000000c8,
|
||||
0x000000e9, 0x000000c9,
|
||||
0x000000ea, 0x000000ca,
|
||||
0x000000eb, 0x000000cb,
|
||||
0x000000ec, 0x000000cc,
|
||||
0x000000ed, 0x000000cd,
|
||||
0x000000ee, 0x000000ce,
|
||||
0x000000ef, 0x000000cf,
|
||||
0x000000f0, 0x000000d0,
|
||||
0x000000f1, 0x000000d1,
|
||||
0x000000f2, 0x000000d2,
|
||||
0x000000f3, 0x000000d3,
|
||||
0x000000f4, 0x000000d4,
|
||||
0x000000f5, 0x000000d5,
|
||||
0x000000f6, 0x000000d6,
|
||||
0x000000f8, 0x000000d8,
|
||||
0x000000f9, 0x000000d9,
|
||||
0x000000fa, 0x000000da,
|
||||
0x000000fb, 0x000000db,
|
||||
0x000000fc, 0x000000dc,
|
||||
0x000000fd, 0x000000dd,
|
||||
0x000000fe, 0x000000de,
|
||||
0x000000ff, 0x00000178,
|
||||
0x00000101, 0x00000100,
|
||||
0x00000103, 0x00000102,
|
||||
0x00000105, 0x00000104,
|
||||
0x00000107, 0x00000106,
|
||||
0x00000109, 0x00000108,
|
||||
0x0000010b, 0x0000010a,
|
||||
0x0000010d, 0x0000010c,
|
||||
0x0000010f, 0x0000010e,
|
||||
0x00000111, 0x00000110,
|
||||
0x00000113, 0x00000112,
|
||||
0x00000115, 0x00000114,
|
||||
0x00000117, 0x00000116,
|
||||
0x00000119, 0x00000118,
|
||||
0x0000011b, 0x0000011a,
|
||||
0x0000011d, 0x0000011c,
|
||||
0x0000011f, 0x0000011e,
|
||||
0x00000121, 0x00000120,
|
||||
0x00000123, 0x00000122,
|
||||
0x00000125, 0x00000124,
|
||||
0x00000127, 0x00000126,
|
||||
0x00000129, 0x00000128,
|
||||
0x0000012b, 0x0000012a,
|
||||
0x0000012d, 0x0000012c,
|
||||
0x0000012f, 0x0000012e,
|
||||
0x00000131, 0x00000049,
|
||||
0x00000133, 0x00000132,
|
||||
0x00000135, 0x00000134,
|
||||
0x00000137, 0x00000136,
|
||||
0x0000013a, 0x00000139,
|
||||
0x0000013c, 0x0000013b,
|
||||
0x0000013e, 0x0000013d,
|
||||
0x00000140, 0x0000013f,
|
||||
0x00000142, 0x00000141,
|
||||
0x00000144, 0x00000143,
|
||||
0x00000146, 0x00000145,
|
||||
0x00000148, 0x00000147,
|
||||
0x0000014b, 0x0000014a,
|
||||
0x0000014d, 0x0000014c,
|
||||
0x0000014f, 0x0000014e,
|
||||
0x00000151, 0x00000150,
|
||||
0x00000153, 0x00000152,
|
||||
0x00000155, 0x00000154,
|
||||
0x00000157, 0x00000156,
|
||||
0x00000159, 0x00000158,
|
||||
0x0000015b, 0x0000015a,
|
||||
0x0000015d, 0x0000015c,
|
||||
0x0000015f, 0x0000015e,
|
||||
0x00000161, 0x00000160,
|
||||
0x00000163, 0x00000162,
|
||||
0x00000165, 0x00000164,
|
||||
0x00000167, 0x00000166,
|
||||
0x00000169, 0x00000168,
|
||||
0x0000016b, 0x0000016a,
|
||||
0x0000016d, 0x0000016c,
|
||||
0x0000016f, 0x0000016e,
|
||||
0x00000171, 0x00000170,
|
||||
0x00000173, 0x00000172,
|
||||
0x00000175, 0x00000174,
|
||||
0x00000177, 0x00000176,
|
||||
0x0000017a, 0x00000179,
|
||||
0x0000017c, 0x0000017b,
|
||||
0x0000017e, 0x0000017d,
|
||||
0x0000017f, 0x00000053,
|
||||
0x00000183, 0x00000182,
|
||||
0x00000185, 0x00000184,
|
||||
0x00000188, 0x00000187,
|
||||
0x0000018c, 0x0000018b,
|
||||
0x00000192, 0x00000191,
|
||||
0x00000195, 0x000001f6,
|
||||
0x00000199, 0x00000198,
|
||||
0x0000019e, 0x00000220,
|
||||
0x000001a1, 0x000001a0,
|
||||
0x000001a3, 0x000001a2,
|
||||
0x000001a5, 0x000001a4,
|
||||
0x000001a8, 0x000001a7,
|
||||
0x000001ad, 0x000001ac,
|
||||
0x000001b0, 0x000001af,
|
||||
0x000001b4, 0x000001b3,
|
||||
0x000001b6, 0x000001b5,
|
||||
0x000001b9, 0x000001b8,
|
||||
0x000001bd, 0x000001bc,
|
||||
0x000001bf, 0x000001f7,
|
||||
0x000001c6, 0x000001c4,
|
||||
0x000001c9, 0x000001c7,
|
||||
0x000001cc, 0x000001ca,
|
||||
0x000001ce, 0x000001cd,
|
||||
0x000001d0, 0x000001cf,
|
||||
0x000001d2, 0x000001d1,
|
||||
0x000001d4, 0x000001d3,
|
||||
0x000001d6, 0x000001d5,
|
||||
0x000001d8, 0x000001d7,
|
||||
0x000001da, 0x000001d9,
|
||||
0x000001dc, 0x000001db,
|
||||
0x000001dd, 0x0000018e,
|
||||
0x000001df, 0x000001de,
|
||||
0x000001e1, 0x000001e0,
|
||||
0x000001e3, 0x000001e2,
|
||||
0x000001e5, 0x000001e4,
|
||||
0x000001e7, 0x000001e6,
|
||||
0x000001e9, 0x000001e8,
|
||||
0x000001eb, 0x000001ea,
|
||||
0x000001ed, 0x000001ec,
|
||||
0x000001ef, 0x000001ee,
|
||||
0x000001f3, 0x000001f1,
|
||||
0x000001f5, 0x000001f4,
|
||||
0x000001f9, 0x000001f8,
|
||||
0x000001fb, 0x000001fa,
|
||||
0x000001fd, 0x000001fc,
|
||||
0x000001ff, 0x000001fe,
|
||||
0x00000201, 0x00000200,
|
||||
0x00000203, 0x00000202,
|
||||
0x00000205, 0x00000204,
|
||||
0x00000207, 0x00000206,
|
||||
0x00000209, 0x00000208,
|
||||
0x0000020b, 0x0000020a,
|
||||
0x0000020d, 0x0000020c,
|
||||
0x0000020f, 0x0000020e,
|
||||
0x00000211, 0x00000210,
|
||||
0x00000213, 0x00000212,
|
||||
0x00000215, 0x00000214,
|
||||
0x00000217, 0x00000216,
|
||||
0x00000219, 0x00000218,
|
||||
0x0000021b, 0x0000021a,
|
||||
0x0000021d, 0x0000021c,
|
||||
0x0000021f, 0x0000021e,
|
||||
0x00000223, 0x00000222,
|
||||
0x00000225, 0x00000224,
|
||||
0x00000227, 0x00000226,
|
||||
0x00000229, 0x00000228,
|
||||
0x0000022b, 0x0000022a,
|
||||
0x0000022d, 0x0000022c,
|
||||
0x0000022f, 0x0000022e,
|
||||
0x00000231, 0x00000230,
|
||||
0x00000233, 0x00000232,
|
||||
0x00000253, 0x00000181,
|
||||
0x00000254, 0x00000186,
|
||||
0x00000256, 0x00000189,
|
||||
0x00000257, 0x0000018a,
|
||||
0x00000259, 0x0000018f,
|
||||
0x0000025b, 0x00000190,
|
||||
0x00000260, 0x00000193,
|
||||
0x00000263, 0x00000194,
|
||||
0x00000268, 0x00000197,
|
||||
0x00000269, 0x00000196,
|
||||
0x0000026f, 0x0000019c,
|
||||
0x00000272, 0x0000019d,
|
||||
0x00000275, 0x0000019f,
|
||||
0x00000280, 0x000001a6,
|
||||
0x00000283, 0x000001a9,
|
||||
0x00000288, 0x000001ae,
|
||||
0x0000028a, 0x000001b1,
|
||||
0x0000028b, 0x000001b2,
|
||||
0x00000292, 0x000001b7,
|
||||
0x00000345, 0x00000399,
|
||||
0x000003ac, 0x00000386,
|
||||
0x000003ad, 0x00000388,
|
||||
0x000003ae, 0x00000389,
|
||||
0x000003af, 0x0000038a,
|
||||
0x000003b1, 0x00000391,
|
||||
0x000003b2, 0x00000392,
|
||||
0x000003b3, 0x00000393,
|
||||
0x000003b4, 0x00000394,
|
||||
0x000003b5, 0x00000395,
|
||||
0x000003b6, 0x00000396,
|
||||
0x000003b7, 0x00000397,
|
||||
0x000003b8, 0x00000398,
|
||||
0x000003b9, 0x00000399,
|
||||
0x000003ba, 0x0000039a,
|
||||
0x000003bb, 0x0000039b,
|
||||
0x000003bc, 0x0000039c,
|
||||
0x000003bd, 0x0000039d,
|
||||
0x000003be, 0x0000039e,
|
||||
0x000003bf, 0x0000039f,
|
||||
0x000003c0, 0x000003a0,
|
||||
0x000003c1, 0x000003a1,
|
||||
0x000003c2, 0x000003a3,
|
||||
0x000003c3, 0x000003a3,
|
||||
0x000003c4, 0x000003a4,
|
||||
0x000003c5, 0x000003a5,
|
||||
0x000003c6, 0x000003a6,
|
||||
0x000003c7, 0x000003a7,
|
||||
0x000003c8, 0x000003a8,
|
||||
0x000003c9, 0x000003a9,
|
||||
0x000003ca, 0x000003aa,
|
||||
0x000003cb, 0x000003ab,
|
||||
0x000003cc, 0x0000038c,
|
||||
0x000003cd, 0x0000038e,
|
||||
0x000003ce, 0x0000038f,
|
||||
0x000003d0, 0x00000392,
|
||||
0x000003d1, 0x00000398,
|
||||
0x000003d5, 0x000003a6,
|
||||
0x000003d6, 0x000003a0,
|
||||
0x000003d9, 0x000003d8,
|
||||
0x000003db, 0x000003da,
|
||||
0x000003dd, 0x000003dc,
|
||||
0x000003df, 0x000003de,
|
||||
0x000003e1, 0x000003e0,
|
||||
0x000003e3, 0x000003e2,
|
||||
0x000003e5, 0x000003e4,
|
||||
0x000003e7, 0x000003e6,
|
||||
0x000003e9, 0x000003e8,
|
||||
0x000003eb, 0x000003ea,
|
||||
0x000003ed, 0x000003ec,
|
||||
0x000003ef, 0x000003ee,
|
||||
0x000003f0, 0x0000039a,
|
||||
0x000003f1, 0x000003a1,
|
||||
0x000003f2, 0x000003a3,
|
||||
0x000003f5, 0x00000395,
|
||||
0x00000430, 0x00000410,
|
||||
0x00000431, 0x00000411,
|
||||
0x00000432, 0x00000412,
|
||||
0x00000433, 0x00000413,
|
||||
0x00000434, 0x00000414,
|
||||
0x00000435, 0x00000415,
|
||||
0x00000436, 0x00000416,
|
||||
0x00000437, 0x00000417,
|
||||
0x00000438, 0x00000418,
|
||||
0x00000439, 0x00000419,
|
||||
0x0000043a, 0x0000041a,
|
||||
0x0000043b, 0x0000041b,
|
||||
0x0000043c, 0x0000041c,
|
||||
0x0000043d, 0x0000041d,
|
||||
0x0000043e, 0x0000041e,
|
||||
0x0000043f, 0x0000041f,
|
||||
0x00000440, 0x00000420,
|
||||
0x00000441, 0x00000421,
|
||||
0x00000442, 0x00000422,
|
||||
0x00000443, 0x00000423,
|
||||
0x00000444, 0x00000424,
|
||||
0x00000445, 0x00000425,
|
||||
0x00000446, 0x00000426,
|
||||
0x00000447, 0x00000427,
|
||||
0x00000448, 0x00000428,
|
||||
0x00000449, 0x00000429,
|
||||
0x0000044a, 0x0000042a,
|
||||
0x0000044b, 0x0000042b,
|
||||
0x0000044c, 0x0000042c,
|
||||
0x0000044d, 0x0000042d,
|
||||
0x0000044e, 0x0000042e,
|
||||
0x0000044f, 0x0000042f,
|
||||
0x00000450, 0x00000400,
|
||||
0x00000451, 0x00000401,
|
||||
0x00000452, 0x00000402,
|
||||
0x00000453, 0x00000403,
|
||||
0x00000454, 0x00000404,
|
||||
0x00000455, 0x00000405,
|
||||
0x00000456, 0x00000406,
|
||||
0x00000457, 0x00000407,
|
||||
0x00000458, 0x00000408,
|
||||
0x00000459, 0x00000409,
|
||||
0x0000045a, 0x0000040a,
|
||||
0x0000045b, 0x0000040b,
|
||||
0x0000045c, 0x0000040c,
|
||||
0x0000045d, 0x0000040d,
|
||||
0x0000045e, 0x0000040e,
|
||||
0x0000045f, 0x0000040f,
|
||||
0x00000461, 0x00000460,
|
||||
0x00000463, 0x00000462,
|
||||
0x00000465, 0x00000464,
|
||||
0x00000467, 0x00000466,
|
||||
0x00000469, 0x00000468,
|
||||
0x0000046b, 0x0000046a,
|
||||
0x0000046d, 0x0000046c,
|
||||
0x0000046f, 0x0000046e,
|
||||
0x00000471, 0x00000470,
|
||||
0x00000473, 0x00000472,
|
||||
0x00000475, 0x00000474,
|
||||
0x00000477, 0x00000476,
|
||||
0x00000479, 0x00000478,
|
||||
0x0000047b, 0x0000047a,
|
||||
0x0000047d, 0x0000047c,
|
||||
0x0000047f, 0x0000047e,
|
||||
0x00000481, 0x00000480,
|
||||
0x0000048b, 0x0000048a,
|
||||
0x0000048d, 0x0000048c,
|
||||
0x0000048f, 0x0000048e,
|
||||
0x00000491, 0x00000490,
|
||||
0x00000493, 0x00000492,
|
||||
0x00000495, 0x00000494,
|
||||
0x00000497, 0x00000496,
|
||||
0x00000499, 0x00000498,
|
||||
0x0000049b, 0x0000049a,
|
||||
0x0000049d, 0x0000049c,
|
||||
0x0000049f, 0x0000049e,
|
||||
0x000004a1, 0x000004a0,
|
||||
0x000004a3, 0x000004a2,
|
||||
0x000004a5, 0x000004a4,
|
||||
0x000004a7, 0x000004a6,
|
||||
0x000004a9, 0x000004a8,
|
||||
0x000004ab, 0x000004aa,
|
||||
0x000004ad, 0x000004ac,
|
||||
0x000004af, 0x000004ae,
|
||||
0x000004b1, 0x000004b0,
|
||||
0x000004b3, 0x000004b2,
|
||||
0x000004b5, 0x000004b4,
|
||||
0x000004b7, 0x000004b6,
|
||||
0x000004b9, 0x000004b8,
|
||||
0x000004bb, 0x000004ba,
|
||||
0x000004bd, 0x000004bc,
|
||||
0x000004bf, 0x000004be,
|
||||
0x000004c2, 0x000004c1,
|
||||
0x000004c4, 0x000004c3,
|
||||
0x000004c6, 0x000004c5,
|
||||
0x000004c8, 0x000004c7,
|
||||
0x000004ca, 0x000004c9,
|
||||
0x000004cc, 0x000004cb,
|
||||
0x000004ce, 0x000004cd,
|
||||
0x000004d1, 0x000004d0,
|
||||
0x000004d3, 0x000004d2,
|
||||
0x000004d5, 0x000004d4,
|
||||
0x000004d7, 0x000004d6,
|
||||
0x000004d9, 0x000004d8,
|
||||
0x000004db, 0x000004da,
|
||||
0x000004dd, 0x000004dc,
|
||||
0x000004df, 0x000004de,
|
||||
0x000004e1, 0x000004e0,
|
||||
0x000004e3, 0x000004e2,
|
||||
0x000004e5, 0x000004e4,
|
||||
0x000004e7, 0x000004e6,
|
||||
0x000004e9, 0x000004e8,
|
||||
0x000004eb, 0x000004ea,
|
||||
0x000004ed, 0x000004ec,
|
||||
0x000004ef, 0x000004ee,
|
||||
0x000004f1, 0x000004f0,
|
||||
0x000004f3, 0x000004f2,
|
||||
0x000004f5, 0x000004f4,
|
||||
0x000004f9, 0x000004f8,
|
||||
0x00000501, 0x00000500,
|
||||
0x00000503, 0x00000502,
|
||||
0x00000505, 0x00000504,
|
||||
0x00000507, 0x00000506,
|
||||
0x00000509, 0x00000508,
|
||||
0x0000050b, 0x0000050a,
|
||||
0x0000050d, 0x0000050c,
|
||||
0x0000050f, 0x0000050e,
|
||||
0x00000561, 0x00000531,
|
||||
0x00000562, 0x00000532,
|
||||
0x00000563, 0x00000533,
|
||||
0x00000564, 0x00000534,
|
||||
0x00000565, 0x00000535,
|
||||
0x00000566, 0x00000536,
|
||||
0x00000567, 0x00000537,
|
||||
0x00000568, 0x00000538,
|
||||
0x00000569, 0x00000539,
|
||||
0x0000056a, 0x0000053a,
|
||||
0x0000056b, 0x0000053b,
|
||||
0x0000056c, 0x0000053c,
|
||||
0x0000056d, 0x0000053d,
|
||||
0x0000056e, 0x0000053e,
|
||||
0x0000056f, 0x0000053f,
|
||||
0x00000570, 0x00000540,
|
||||
0x00000571, 0x00000541,
|
||||
0x00000572, 0x00000542,
|
||||
0x00000573, 0x00000543,
|
||||
0x00000574, 0x00000544,
|
||||
0x00000575, 0x00000545,
|
||||
0x00000576, 0x00000546,
|
||||
0x00000577, 0x00000547,
|
||||
0x00000578, 0x00000548,
|
||||
0x00000579, 0x00000549,
|
||||
0x0000057a, 0x0000054a,
|
||||
0x0000057b, 0x0000054b,
|
||||
0x0000057c, 0x0000054c,
|
||||
0x0000057d, 0x0000054d,
|
||||
0x0000057e, 0x0000054e,
|
||||
0x0000057f, 0x0000054f,
|
||||
0x00000580, 0x00000550,
|
||||
0x00000581, 0x00000551,
|
||||
0x00000582, 0x00000552,
|
||||
0x00000583, 0x00000553,
|
||||
0x00000584, 0x00000554,
|
||||
0x00000585, 0x00000555,
|
||||
0x00000586, 0x00000556,
|
||||
0x00001e01, 0x00001e00,
|
||||
0x00001e03, 0x00001e02,
|
||||
0x00001e05, 0x00001e04,
|
||||
0x00001e07, 0x00001e06,
|
||||
0x00001e09, 0x00001e08,
|
||||
0x00001e0b, 0x00001e0a,
|
||||
0x00001e0d, 0x00001e0c,
|
||||
0x00001e0f, 0x00001e0e,
|
||||
0x00001e11, 0x00001e10,
|
||||
0x00001e13, 0x00001e12,
|
||||
0x00001e15, 0x00001e14,
|
||||
0x00001e17, 0x00001e16,
|
||||
0x00001e19, 0x00001e18,
|
||||
0x00001e1b, 0x00001e1a,
|
||||
0x00001e1d, 0x00001e1c,
|
||||
0x00001e1f, 0x00001e1e,
|
||||
0x00001e21, 0x00001e20,
|
||||
0x00001e23, 0x00001e22,
|
||||
0x00001e25, 0x00001e24,
|
||||
0x00001e27, 0x00001e26,
|
||||
0x00001e29, 0x00001e28,
|
||||
0x00001e2b, 0x00001e2a,
|
||||
0x00001e2d, 0x00001e2c,
|
||||
0x00001e2f, 0x00001e2e,
|
||||
0x00001e31, 0x00001e30,
|
||||
0x00001e33, 0x00001e32,
|
||||
0x00001e35, 0x00001e34,
|
||||
0x00001e37, 0x00001e36,
|
||||
0x00001e39, 0x00001e38,
|
||||
0x00001e3b, 0x00001e3a,
|
||||
0x00001e3d, 0x00001e3c,
|
||||
0x00001e3f, 0x00001e3e,
|
||||
0x00001e41, 0x00001e40,
|
||||
0x00001e43, 0x00001e42,
|
||||
0x00001e45, 0x00001e44,
|
||||
0x00001e47, 0x00001e46,
|
||||
0x00001e49, 0x00001e48,
|
||||
0x00001e4b, 0x00001e4a,
|
||||
0x00001e4d, 0x00001e4c,
|
||||
0x00001e4f, 0x00001e4e,
|
||||
0x00001e51, 0x00001e50,
|
||||
0x00001e53, 0x00001e52,
|
||||
0x00001e55, 0x00001e54,
|
||||
0x00001e57, 0x00001e56,
|
||||
0x00001e59, 0x00001e58,
|
||||
0x00001e5b, 0x00001e5a,
|
||||
0x00001e5d, 0x00001e5c,
|
||||
0x00001e5f, 0x00001e5e,
|
||||
0x00001e61, 0x00001e60,
|
||||
0x00001e63, 0x00001e62,
|
||||
0x00001e65, 0x00001e64,
|
||||
0x00001e67, 0x00001e66,
|
||||
0x00001e69, 0x00001e68,
|
||||
0x00001e6b, 0x00001e6a,
|
||||
0x00001e6d, 0x00001e6c,
|
||||
0x00001e6f, 0x00001e6e,
|
||||
0x00001e71, 0x00001e70,
|
||||
0x00001e73, 0x00001e72,
|
||||
0x00001e75, 0x00001e74,
|
||||
0x00001e77, 0x00001e76,
|
||||
0x00001e79, 0x00001e78,
|
||||
0x00001e7b, 0x00001e7a,
|
||||
0x00001e7d, 0x00001e7c,
|
||||
0x00001e7f, 0x00001e7e,
|
||||
0x00001e81, 0x00001e80,
|
||||
0x00001e83, 0x00001e82,
|
||||
0x00001e85, 0x00001e84,
|
||||
0x00001e87, 0x00001e86,
|
||||
0x00001e89, 0x00001e88,
|
||||
0x00001e8b, 0x00001e8a,
|
||||
0x00001e8d, 0x00001e8c,
|
||||
0x00001e8f, 0x00001e8e,
|
||||
0x00001e91, 0x00001e90,
|
||||
0x00001e93, 0x00001e92,
|
||||
0x00001e95, 0x00001e94,
|
||||
0x00001e9b, 0x00001e60,
|
||||
0x00001ea1, 0x00001ea0,
|
||||
0x00001ea3, 0x00001ea2,
|
||||
0x00001ea5, 0x00001ea4,
|
||||
0x00001ea7, 0x00001ea6,
|
||||
0x00001ea9, 0x00001ea8,
|
||||
0x00001eab, 0x00001eaa,
|
||||
0x00001ead, 0x00001eac,
|
||||
0x00001eaf, 0x00001eae,
|
||||
0x00001eb1, 0x00001eb0,
|
||||
0x00001eb3, 0x00001eb2,
|
||||
0x00001eb5, 0x00001eb4,
|
||||
0x00001eb7, 0x00001eb6,
|
||||
0x00001eb9, 0x00001eb8,
|
||||
0x00001ebb, 0x00001eba,
|
||||
0x00001ebd, 0x00001ebc,
|
||||
0x00001ebf, 0x00001ebe,
|
||||
0x00001ec1, 0x00001ec0,
|
||||
0x00001ec3, 0x00001ec2,
|
||||
0x00001ec5, 0x00001ec4,
|
||||
0x00001ec7, 0x00001ec6,
|
||||
0x00001ec9, 0x00001ec8,
|
||||
0x00001ecb, 0x00001eca,
|
||||
0x00001ecd, 0x00001ecc,
|
||||
0x00001ecf, 0x00001ece,
|
||||
0x00001ed1, 0x00001ed0,
|
||||
0x00001ed3, 0x00001ed2,
|
||||
0x00001ed5, 0x00001ed4,
|
||||
0x00001ed7, 0x00001ed6,
|
||||
0x00001ed9, 0x00001ed8,
|
||||
0x00001edb, 0x00001eda,
|
||||
0x00001edd, 0x00001edc,
|
||||
0x00001edf, 0x00001ede,
|
||||
0x00001ee1, 0x00001ee0,
|
||||
0x00001ee3, 0x00001ee2,
|
||||
0x00001ee5, 0x00001ee4,
|
||||
0x00001ee7, 0x00001ee6,
|
||||
0x00001ee9, 0x00001ee8,
|
||||
0x00001eeb, 0x00001eea,
|
||||
0x00001eed, 0x00001eec,
|
||||
0x00001eef, 0x00001eee,
|
||||
0x00001ef1, 0x00001ef0,
|
||||
0x00001ef3, 0x00001ef2,
|
||||
0x00001ef5, 0x00001ef4,
|
||||
0x00001ef7, 0x00001ef6,
|
||||
0x00001ef9, 0x00001ef8,
|
||||
0x00001f00, 0x00001f08,
|
||||
0x00001f01, 0x00001f09,
|
||||
0x00001f02, 0x00001f0a,
|
||||
0x00001f03, 0x00001f0b,
|
||||
0x00001f04, 0x00001f0c,
|
||||
0x00001f05, 0x00001f0d,
|
||||
0x00001f06, 0x00001f0e,
|
||||
0x00001f07, 0x00001f0f,
|
||||
0x00001f10, 0x00001f18,
|
||||
0x00001f11, 0x00001f19,
|
||||
0x00001f12, 0x00001f1a,
|
||||
0x00001f13, 0x00001f1b,
|
||||
0x00001f14, 0x00001f1c,
|
||||
0x00001f15, 0x00001f1d,
|
||||
0x00001f20, 0x00001f28,
|
||||
0x00001f21, 0x00001f29,
|
||||
0x00001f22, 0x00001f2a,
|
||||
0x00001f23, 0x00001f2b,
|
||||
0x00001f24, 0x00001f2c,
|
||||
0x00001f25, 0x00001f2d,
|
||||
0x00001f26, 0x00001f2e,
|
||||
0x00001f27, 0x00001f2f,
|
||||
0x00001f30, 0x00001f38,
|
||||
0x00001f31, 0x00001f39,
|
||||
0x00001f32, 0x00001f3a,
|
||||
0x00001f33, 0x00001f3b,
|
||||
0x00001f34, 0x00001f3c,
|
||||
0x00001f35, 0x00001f3d,
|
||||
0x00001f36, 0x00001f3e,
|
||||
0x00001f37, 0x00001f3f,
|
||||
0x00001f40, 0x00001f48,
|
||||
0x00001f41, 0x00001f49,
|
||||
0x00001f42, 0x00001f4a,
|
||||
0x00001f43, 0x00001f4b,
|
||||
0x00001f44, 0x00001f4c,
|
||||
0x00001f45, 0x00001f4d,
|
||||
0x00001f51, 0x00001f59,
|
||||
0x00001f53, 0x00001f5b,
|
||||
0x00001f55, 0x00001f5d,
|
||||
0x00001f57, 0x00001f5f,
|
||||
0x00001f60, 0x00001f68,
|
||||
0x00001f61, 0x00001f69,
|
||||
0x00001f62, 0x00001f6a,
|
||||
0x00001f63, 0x00001f6b,
|
||||
0x00001f64, 0x00001f6c,
|
||||
0x00001f65, 0x00001f6d,
|
||||
0x00001f66, 0x00001f6e,
|
||||
0x00001f67, 0x00001f6f,
|
||||
0x00001f70, 0x00001fba,
|
||||
0x00001f71, 0x00001fbb,
|
||||
0x00001f72, 0x00001fc8,
|
||||
0x00001f73, 0x00001fc9,
|
||||
0x00001f74, 0x00001fca,
|
||||
0x00001f75, 0x00001fcb,
|
||||
0x00001f76, 0x00001fda,
|
||||
0x00001f77, 0x00001fdb,
|
||||
0x00001f78, 0x00001ff8,
|
||||
0x00001f79, 0x00001ff9,
|
||||
0x00001f7a, 0x00001fea,
|
||||
0x00001f7b, 0x00001feb,
|
||||
0x00001f7c, 0x00001ffa,
|
||||
0x00001f7d, 0x00001ffb,
|
||||
0x00001f80, 0x00001f88,
|
||||
0x00001f81, 0x00001f89,
|
||||
0x00001f82, 0x00001f8a,
|
||||
0x00001f83, 0x00001f8b,
|
||||
0x00001f84, 0x00001f8c,
|
||||
0x00001f85, 0x00001f8d,
|
||||
0x00001f86, 0x00001f8e,
|
||||
0x00001f87, 0x00001f8f,
|
||||
0x00001f90, 0x00001f98,
|
||||
0x00001f91, 0x00001f99,
|
||||
0x00001f92, 0x00001f9a,
|
||||
0x00001f93, 0x00001f9b,
|
||||
0x00001f94, 0x00001f9c,
|
||||
0x00001f95, 0x00001f9d,
|
||||
0x00001f96, 0x00001f9e,
|
||||
0x00001f97, 0x00001f9f,
|
||||
0x00001fa0, 0x00001fa8,
|
||||
0x00001fa1, 0x00001fa9,
|
||||
0x00001fa2, 0x00001faa,
|
||||
0x00001fa3, 0x00001fab,
|
||||
0x00001fa4, 0x00001fac,
|
||||
0x00001fa5, 0x00001fad,
|
||||
0x00001fa6, 0x00001fae,
|
||||
0x00001fa7, 0x00001faf,
|
||||
0x00001fb0, 0x00001fb8,
|
||||
0x00001fb1, 0x00001fb9,
|
||||
0x00001fb3, 0x00001fbc,
|
||||
0x00001fbe, 0x00000399,
|
||||
0x00001fc3, 0x00001fcc,
|
||||
0x00001fd0, 0x00001fd8,
|
||||
0x00001fd1, 0x00001fd9,
|
||||
0x00001fe0, 0x00001fe8,
|
||||
0x00001fe1, 0x00001fe9,
|
||||
0x00001fe5, 0x00001fec,
|
||||
0x00001ff3, 0x00001ffc,
|
||||
0x00002170, 0x00002160,
|
||||
0x00002171, 0x00002161,
|
||||
0x00002172, 0x00002162,
|
||||
0x00002173, 0x00002163,
|
||||
0x00002174, 0x00002164,
|
||||
0x00002175, 0x00002165,
|
||||
0x00002176, 0x00002166,
|
||||
0x00002177, 0x00002167,
|
||||
0x00002178, 0x00002168,
|
||||
0x00002179, 0x00002169,
|
||||
0x0000217a, 0x0000216a,
|
||||
0x0000217b, 0x0000216b,
|
||||
0x0000217c, 0x0000216c,
|
||||
0x0000217d, 0x0000216d,
|
||||
0x0000217e, 0x0000216e,
|
||||
0x0000217f, 0x0000216f,
|
||||
0x000024d0, 0x000024b6,
|
||||
0x000024d1, 0x000024b7,
|
||||
0x000024d2, 0x000024b8,
|
||||
0x000024d3, 0x000024b9,
|
||||
0x000024d4, 0x000024ba,
|
||||
0x000024d5, 0x000024bb,
|
||||
0x000024d6, 0x000024bc,
|
||||
0x000024d7, 0x000024bd,
|
||||
0x000024d8, 0x000024be,
|
||||
0x000024d9, 0x000024bf,
|
||||
0x000024da, 0x000024c0,
|
||||
0x000024db, 0x000024c1,
|
||||
0x000024dc, 0x000024c2,
|
||||
0x000024dd, 0x000024c3,
|
||||
0x000024de, 0x000024c4,
|
||||
0x000024df, 0x000024c5,
|
||||
0x000024e0, 0x000024c6,
|
||||
0x000024e1, 0x000024c7,
|
||||
0x000024e2, 0x000024c8,
|
||||
0x000024e3, 0x000024c9,
|
||||
0x000024e4, 0x000024ca,
|
||||
0x000024e5, 0x000024cb,
|
||||
0x000024e6, 0x000024cc,
|
||||
0x000024e7, 0x000024cd,
|
||||
0x000024e8, 0x000024ce,
|
||||
0x000024e9, 0x000024cf,
|
||||
0x0000ff41, 0x0000ff21,
|
||||
0x0000ff42, 0x0000ff22,
|
||||
0x0000ff43, 0x0000ff23,
|
||||
0x0000ff44, 0x0000ff24,
|
||||
0x0000ff45, 0x0000ff25,
|
||||
0x0000ff46, 0x0000ff26,
|
||||
0x0000ff47, 0x0000ff27,
|
||||
0x0000ff48, 0x0000ff28,
|
||||
0x0000ff49, 0x0000ff29,
|
||||
0x0000ff4a, 0x0000ff2a,
|
||||
0x0000ff4b, 0x0000ff2b,
|
||||
0x0000ff4c, 0x0000ff2c,
|
||||
0x0000ff4d, 0x0000ff2d,
|
||||
0x0000ff4e, 0x0000ff2e,
|
||||
0x0000ff4f, 0x0000ff2f,
|
||||
0x0000ff50, 0x0000ff30,
|
||||
0x0000ff51, 0x0000ff31,
|
||||
0x0000ff52, 0x0000ff32,
|
||||
0x0000ff53, 0x0000ff33,
|
||||
0x0000ff54, 0x0000ff34,
|
||||
0x0000ff55, 0x0000ff35,
|
||||
0x0000ff56, 0x0000ff36,
|
||||
0x0000ff57, 0x0000ff37,
|
||||
0x0000ff58, 0x0000ff38,
|
||||
0x0000ff59, 0x0000ff39,
|
||||
0x0000ff5a, 0x0000ff3a,
|
||||
0x00010428, 0x00010400,
|
||||
0x00010429, 0x00010401,
|
||||
0x0001042a, 0x00010402,
|
||||
0x0001042b, 0x00010403,
|
||||
0x0001042c, 0x00010404,
|
||||
0x0001042d, 0x00010405,
|
||||
0x0001042e, 0x00010406,
|
||||
0x0001042f, 0x00010407,
|
||||
0x00010430, 0x00010408,
|
||||
0x00010431, 0x00010409,
|
||||
0x00010432, 0x0001040a,
|
||||
0x00010433, 0x0001040b,
|
||||
0x00010434, 0x0001040c,
|
||||
0x00010435, 0x0001040d,
|
||||
0x00010436, 0x0001040e,
|
||||
0x00010437, 0x0001040f,
|
||||
0x00010438, 0x00010410,
|
||||
0x00010439, 0x00010411,
|
||||
0x0001043a, 0x00010412,
|
||||
0x0001043b, 0x00010413,
|
||||
0x0001043c, 0x00010414,
|
||||
0x0001043d, 0x00010415,
|
||||
0x0001043e, 0x00010416,
|
||||
0x0001043f, 0x00010417,
|
||||
0x00010440, 0x00010418,
|
||||
0x00010441, 0x00010419,
|
||||
0x00010442, 0x0001041a,
|
||||
0x00010443, 0x0001041b,
|
||||
0x00010444, 0x0001041c,
|
||||
0x00010445, 0x0001041d,
|
||||
0x00010446, 0x0001041e,
|
||||
0x00010447, 0x0001041f,
|
||||
0x00010448, 0x00010420,
|
||||
0x00010449, 0x00010421,
|
||||
0x0001044a, 0x00010422,
|
||||
0x0001044b, 0x00010423,
|
||||
0x0001044c, 0x00010424,
|
||||
0x0001044d, 0x00010425,
|
||||
};
|
||||
|
||||
#endif /*UTF8TABLES_H_*/
|
||||
@@ -1,8 +0,0 @@
|
||||
b1v1r = Brian Rectanus <brectanu@gmail.com>
|
||||
brectanu = Brian Rectanus <brectanu@gmail.com>
|
||||
brectanus = Brian Rectanus <brectanu@gmail.com>
|
||||
ivanr = Ivan Ristić <ivanr@webkreator.com>
|
||||
rbarnett = Ryan C. Barnett <rcbarnett@gmail.com>
|
||||
[anonymous] = Brian Rectanus <brectanu@gmail.com>
|
||||
(no author) = Brian Rectanus <brectanu@gmail.com>
|
||||
brenosilva = Breno Silva <breno.silva@gmail.com>
|
||||
17
autogen.sh
17
autogen.sh
@@ -1,17 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
#rm -rf autom4te.cache
|
||||
#automake --add-missing --copy --foreign
|
||||
#autoreconf --install
|
||||
#autoheader
|
||||
|
||||
rm -rf autom4te.cache
|
||||
rm -f aclocal.m4
|
||||
case `uname` in Darwin*) glibtoolize --force --copy ;;
|
||||
*) libtoolize --force --copy ;; esac
|
||||
autoreconf --install
|
||||
autoheader
|
||||
automake --add-missing --foreign --copy --force-missing
|
||||
autoconf --force
|
||||
rm -rf autom4te.cache
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#!@SHELL@
|
||||
|
||||
WRAPPED_OPTS=""
|
||||
for opt in "$@"; do
|
||||
case "$opt" in
|
||||
# Fix for -R not working w/apxs
|
||||
-R*) WRAPPED_OPTS="$WRAPPED_OPTS -Wl,$opt" ;;
|
||||
# OSF1 compiler option
|
||||
-pthread) WRAPPED_OPTS="$WRAPPED_OPTS -Wc,$opt" ;;
|
||||
# Unwrapped
|
||||
*) WRAPPED_OPTS="$WRAPPED_OPTS $opt" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
exec @APXS@ $WRAPPED_OPTS
|
||||
142
build/compile
142
build/compile
@@ -1,142 +0,0 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand `-c -o'.
|
||||
|
||||
scriptversion=2005-05-14.22
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand `-c -o'.
|
||||
Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file `INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
eat=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as `compile cc -o foo foo.c'.
|
||||
# So we strip `-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no `-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# `.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use `[/.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
@@ -1,91 +0,0 @@
|
||||
dnl Check for APR Libraries
|
||||
dnl CHECK_APR(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl APR_CFLAGS
|
||||
dnl APR_LDFLAGS
|
||||
dnl APR_LIBS
|
||||
dnl APR_LINK_LD
|
||||
|
||||
APR_CONFIG=""
|
||||
APR_CFLAGS=""
|
||||
APR_CPPFLAGS=""
|
||||
APR_LDFLAGS=""
|
||||
APR_LDADD=""
|
||||
APR_INCLUDEDIR=""
|
||||
APR_LINKLD=""
|
||||
AC_DEFUN([CHECK_APR],
|
||||
[dnl
|
||||
|
||||
AC_ARG_WITH(
|
||||
apr,
|
||||
[AC_HELP_STRING([--with-apr=PATH],[Path to apr prefix or config script])],
|
||||
[test_paths="${with_apr}"],
|
||||
[test_paths="/usr/local/libapr /usr/local/apr /usr/local /opt/libapr /opt/apr /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libapr config script])
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
APR_CONFIG=$x
|
||||
apr_path=no
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for APR_CONFIG in apr-1-mt-config apr-1-config apr-config-1 apr-mt-config-1 apr-mt-config apr-config; do
|
||||
if test -e "${x}/bin/${APR_CONFIG}"; then
|
||||
apr_path="${x}/bin"
|
||||
break
|
||||
elif test -e "${x}/${APR_CONFIG}"; then
|
||||
apr_path="${x}"
|
||||
break
|
||||
else
|
||||
apr_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$apr_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "${apr_path}"; then
|
||||
if test "${apr_path}" != "no"; then
|
||||
APR_CONFIG="${apr_path}/${APR_CONFIG}"
|
||||
fi
|
||||
AC_MSG_RESULT([${APR_CONFIG}])
|
||||
APR_VERSION="`${APR_CONFIG} --version`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr VERSION: $APR_VERSION); fi
|
||||
APR_CFLAGS="`${APR_CONFIG} --includes`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr CFLAGS: $APR_CFLAGS); fi
|
||||
APR_CPPFLAGS="`${APR_CONFIG} --cppflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr CPPFLAGS: $APR_CPPFLAGS); fi
|
||||
APR_LDFLAGS="`${APR_CONFIG} --libs`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LDFLAGS: $APR_LDFLAGS); fi
|
||||
APR_LDADD="`${APR_CONFIG} --link-libtool`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LDADD: $APR_LDADD); fi
|
||||
APR_INCLUDEDIR="`${APR_CONFIG} --includedir`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr INCLUDEDIR: $APR_INCLUDEDIR); fi
|
||||
APR_LINKLD="`${APR_CONFIG} --link-ld`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apr LINKLD: $APR_LINKLD); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(APR_CONFIG)
|
||||
AC_SUBST(APR_VERSION)
|
||||
AC_SUBST(APR_CFLAGS)
|
||||
AC_SUBST(APR_CPPFLAGS)
|
||||
AC_SUBST(APR_LDFLAGS)
|
||||
AC_SUBST(APR_LDADD)
|
||||
AC_SUBST(APR_INCLUDEDIR)
|
||||
AC_SUBST(APR_LINKLD)
|
||||
|
||||
if test -z "${APR_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** apr library not found.])
|
||||
ifelse([$2], , AC_MSG_ERROR([apr library is required]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using apr v${APR_VERSION}])
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,89 +0,0 @@
|
||||
dnl Check for APU Libraries
|
||||
dnl CHECK_APU(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl APU_CFLAGS
|
||||
dnl APU_LDFLAGS
|
||||
dnl APU_LIBS
|
||||
dnl APU_LINK_LD
|
||||
|
||||
APU_CONFIG=""
|
||||
APU_CFLAGS=""
|
||||
APU_LDFLAGS=""
|
||||
APU_LDADD=""
|
||||
APU_INCLUDEDIR=""
|
||||
APU_LINKLD=""
|
||||
|
||||
AC_DEFUN([CHECK_APU],
|
||||
[dnl
|
||||
|
||||
AC_ARG_WITH(
|
||||
apu,
|
||||
[AC_HELP_STRING([--with-apu=PATH],[Path to apu prefix or config script])],
|
||||
[test_paths="${with_apu}"],
|
||||
[test_paths="/usr/local/libapr-util /usr/local/apr-util /usr/local/libapu /usr/local/apu /usr/local/apr /usr/local /opt/libapr-util /opt/apr-util /opt/libapu /opt/apu /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libapu config script])
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
APU_CONFIG=$x
|
||||
apu_path="no"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for APU_CONFIG in apu-1-mt-config apu-1-config apu-config-1 apu-mt-config-1 apu-mt-config apu-config; do
|
||||
if test -e "${x}/bin/${APU_CONFIG}"; then
|
||||
apu_path="${x}/bin"
|
||||
break
|
||||
elif test -e "${x}/${APU_CONFIG}"; then
|
||||
apu_path="${x}"
|
||||
break
|
||||
else
|
||||
apu_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$apu_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "${apu_path}"; then
|
||||
if test "${apu_path}" != "no"; then
|
||||
APU_CONFIG="${apu_path}/${APU_CONFIG}"
|
||||
fi
|
||||
AC_MSG_RESULT([${APU_CONFIG}])
|
||||
APU_VERSION="`${APU_CONFIG} --version`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu VERSION: $APU_VERSION); fi
|
||||
APU_CFLAGS="`${APU_CONFIG} --includes`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu CFLAGS: $APU_CFLAGS); fi
|
||||
APU_LDFLAGS="`${APU_CONFIG} --ldflags`"
|
||||
APU_LDFLAGS="$APU_LDFLAGS `${APU_CONFIG} --libs`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDFLAGS: $APU_LDFLAGS); fi
|
||||
APU_LDADD="`${APU_CONFIG} --link-libtool`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LDADD: $APU_LDADD); fi
|
||||
APU_INCLUDEDIR="`${APU_CONFIG} --includedir`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu INCLUDEDIR: $APU_INCLUDEDIR); fi
|
||||
APU_LINKLD="`${APU_CONFIG} --link-ld`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apu LINKLD: $APU_LINKLD); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(APU_CONFIG)
|
||||
AC_SUBST(APU_VERSION)
|
||||
AC_SUBST(APU_CFLAGS)
|
||||
AC_SUBST(APU_LDFLAGS)
|
||||
AC_SUBST(APU_LDADD)
|
||||
AC_SUBST(APU_INCLUDEDIR)
|
||||
AC_SUBST(APU_LINKLD)
|
||||
|
||||
if test -z "${APU_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** apu library not found.])
|
||||
ifelse([$2], , AC_MSG_ERROR([apu library is required]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using apu v${APU_VERSION}])
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,110 +0,0 @@
|
||||
dnl Check for CURL Libraries
|
||||
dnl CHECK_CURL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl CURL_CFLAGS
|
||||
dnl CURL_LIBS
|
||||
|
||||
CURL_CONFIG=""
|
||||
CURL_VERSION=""
|
||||
CURL_CPPFLAGS=""
|
||||
CURL_CFLAGS=""
|
||||
CURL_LDFLAGS=""
|
||||
CURL_LDADD=""
|
||||
CURL_MIN_VERSION="7.15.1"
|
||||
|
||||
AC_DEFUN([CHECK_CURL],
|
||||
[dnl
|
||||
|
||||
AC_ARG_WITH(
|
||||
curl,
|
||||
[AC_HELP_STRING([--with-curl=PATH],[Path to curl prefix or config script])],
|
||||
[test_paths="${with_curl}"],
|
||||
[test_paths="/usr/local/libcurl /usr/local/curl /usr/local /opt/libcurl /opt/curl /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libcurl config script])
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
CURL_CONFIG=$x
|
||||
curl_path="no"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for CURL_CONFIG in curl-config; do
|
||||
if test -e "${x}/bin/${CURL_CONFIG}"; then
|
||||
curl_path="${x}/bin"
|
||||
break
|
||||
elif test -e "${x}/${CURL_CONFIG}"; then
|
||||
curl_path="${x}"
|
||||
break
|
||||
else
|
||||
curl_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$curl_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "${curl_path}"; then
|
||||
if test "${curl_path}" != "no"; then
|
||||
CURL_CONFIG="${curl_path}/${CURL_CONFIG}"
|
||||
fi
|
||||
AC_MSG_RESULT([${CURL_CONFIG}])
|
||||
CURL_VERSION=`${CURL_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//'`
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl VERSION: $CURL_VERSION); fi
|
||||
CURL_CFLAGS="`${CURL_CONFIG} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl CFLAGS: $CURL_CFLAGS); fi
|
||||
CURL_LDADD="`${CURL_CONFIG} --libs`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(curl LDADD: $CURL_LIBS); fi
|
||||
|
||||
dnl # Check version is ok
|
||||
AC_MSG_CHECKING([if libcurl is at least v${CURL_MIN_VERSION}])
|
||||
curl_min_ver=`echo ${CURL_MIN_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
|
||||
curl_ver=`echo ${CURL_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
|
||||
if test "$curl_min_ver" -le "$curl_ver"; then
|
||||
AC_MSG_RESULT([yes, $CURL_VERSION])
|
||||
curl_tlsv2_ver=`echo 7.34.0 | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
|
||||
if test "$curl_tlsv2_ver" -le "$curl_ver"; then
|
||||
CURL_CFLAGS="${CURL_CFLAGS} -DWITH_CURL_SSLVERSION_TLSv1_2"
|
||||
fi
|
||||
CURL_CFLAGS="${CURL_CFLAGS} -DWITH_CURL"
|
||||
else
|
||||
AC_MSG_RESULT([no, $CURL_VERSION])
|
||||
AC_MSG_NOTICE([NOTE: curl library may be too old])
|
||||
fi
|
||||
|
||||
dnl # Check/warn if GnuTLS is used
|
||||
AC_MSG_CHECKING([if libcurl is linked with gnutls])
|
||||
curl_uses_gnutls=`echo ${CURL_LIBS} | grep gnutls | wc -l`
|
||||
if test "$curl_uses_gnutls" -ne 0; then
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_MSG_NOTICE([NOTE: curl linked with gnutls may be buggy, openssl recommended])
|
||||
CURL_USES_GNUTLS=yes
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
CURL_USES_GNUTLS=no
|
||||
fi
|
||||
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(CURL_CONFIG)
|
||||
AC_SUBST(CURL_VERSION)
|
||||
AC_SUBST(CURL_CPPFLAGS)
|
||||
AC_SUBST(CURL_CFLAGS)
|
||||
AC_SUBST(CURL_LDFLAGS)
|
||||
AC_SUBST(CURL_LDADD)
|
||||
AC_SUBST(CURL_USES_GNUTLS)
|
||||
|
||||
if test -z "${CURL_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** curl library not found.])
|
||||
ifelse([$2], , AC_MSG_NOTICE([NOTE: curl library is only required for building mlogc]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using curl v${CURL_VERSION}])
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,195 +0,0 @@
|
||||
dnl Check for LUA Libraries
|
||||
dnl CHECK_LUA(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl LUA_CFLAGS
|
||||
dnl LUA_LIBS
|
||||
|
||||
AC_DEFUN([CHECK_LUA],
|
||||
[dnl
|
||||
|
||||
AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
|
||||
LUA_CONFIG=""
|
||||
LUA_VERSION=""
|
||||
LUA_CFLAGS=""
|
||||
LUA_CPPFLAGS=""
|
||||
LUA_LDADD=""
|
||||
LUA_LDFLAGS=""
|
||||
LUA_CONFIG=${PKG_CONFIG}
|
||||
LUA_PKGNAMES="lua5.1 lua-5.1 lua_5.1 lua-51 lua_51 lua51 lua5 lua"
|
||||
LUA_SONAMES="so la sl dll dylib a"
|
||||
|
||||
AC_ARG_WITH(
|
||||
lua,
|
||||
[AC_HELP_STRING([--with-lua=PATH],[Path to lua prefix or config script])]
|
||||
,, with_lua=yes)
|
||||
|
||||
AS_CASE(["${with_lua}"],
|
||||
[no], [test_paths=],
|
||||
[yes], [test_paths="/usr/local/liblua /usr/local/lua /usr/local /opt/liblua /opt/lua /opt /usr"],
|
||||
[test_paths="${with_lua}"])
|
||||
|
||||
AS_IF([test "x${test_paths}" != "x"], [
|
||||
AC_MSG_CHECKING([for liblua config script])
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
LUA_CONFIG=$x
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for y in $LUA_CONFIG; do
|
||||
if test -e "${x}/bin/${y}"; then
|
||||
LUA_CONFIG="${x}/bin/${y}"
|
||||
lua_config="${LUA_CONFIG}"
|
||||
break
|
||||
elif test -e "${x}/${y}"; then
|
||||
LUA_CONFIG="${x}/${y}"
|
||||
lua_config="${LUA_CONFIG}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${lua_config}"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
dnl # Try known package names
|
||||
if test -n "${LUA_CONFIG}"; then
|
||||
LUA_PKGNAME=""
|
||||
for x in ${LUA_PKGNAMES}; do
|
||||
if ${LUA_CONFIG} --exists ${x}; then
|
||||
LUA_PKGNAME="$x"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if test -n "${LUA_PKGNAME}"; then
|
||||
AC_MSG_RESULT([${LUA_CONFIG}])
|
||||
LUA_VERSION="`${LUA_CONFIG} ${LUA_PKGNAME} --modversion`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua VERSION: $LUA_VERSION); fi
|
||||
LUA_CFLAGS="`${LUA_CONFIG} ${LUA_PKGNAME} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua CFLAGS: $LUA_CFLAGS); fi
|
||||
LUA_LDADD="`${LUA_CONFIG} ${LUA_PKGNAME} --libs-only-l`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua LDADD: $LUA_LDADD); fi
|
||||
LUA_LDFLAGS="`${LUA_CONFIG} ${LUA_PKGNAME} --libs-only-L --libs-only-other`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(lua LDFLAGS: $LUA_LDFLAGS); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
dnl Hack to just try to find the lib and include
|
||||
AC_MSG_CHECKING([for lua install])
|
||||
for x in ${test_paths}; do
|
||||
for y in ${LUA_SONAMES}; do
|
||||
if test -e "${x}/liblua5.1.${y}"; then
|
||||
lua_lib_path="${x}"
|
||||
lua_lib_name="lua5.1"
|
||||
break
|
||||
elif test -e "${x}/lib/liblua5.1.${y}"; then
|
||||
lua_lib_path="${x}/lib"
|
||||
lua_lib_name="lua5.1"
|
||||
break
|
||||
elif test -e "${x}/lib64/liblua5.1.${y}"; then
|
||||
lua_lib_path="${x}/lib64"
|
||||
lua_lib_name="lua5.1"
|
||||
break
|
||||
elif test -e "${x}/lib32/liblua5.1.${y}"; then
|
||||
lua_lib_path="${x}/lib32"
|
||||
lua_lib_name="lua5.1"
|
||||
break
|
||||
elif test -e "${x}/liblua51.${y}"; then
|
||||
lua_lib_path="${x}"
|
||||
lua_lib_name="lua51"
|
||||
break
|
||||
elif test -e "${x}/lib/liblua51.${y}"; then
|
||||
lua_lib_path="${x}/lib"
|
||||
lua_lib_name="lua51"
|
||||
break
|
||||
elif test -e "${x}/lib64/liblua51.${y}"; then
|
||||
lua_lib_path="${x}/lib64"
|
||||
lua_lib_name="lua51"
|
||||
break
|
||||
elif test -e "${x}/lib32/liblua51.${y}"; then
|
||||
lua_lib_path="${x}/lib32"
|
||||
lua_lib_name="lua51"
|
||||
break
|
||||
elif test -e "${x}/liblua.${y}"; then
|
||||
lua_lib_path="${x}"
|
||||
lua_lib_name="lua"
|
||||
break
|
||||
elif test -e "${x}/lib/liblua.${y}"; then
|
||||
lua_lib_path="${x}/lib"
|
||||
lua_lib_name="lua"
|
||||
break
|
||||
elif test -e "${x}/lib64/liblua.${y}"; then
|
||||
lua_lib_path="${x}/lib64"
|
||||
lua_lib_name="lua"
|
||||
break
|
||||
elif test -e "${x}/lib32/liblua.${y}"; then
|
||||
lua_lib_path="${x}/lib32"
|
||||
lua_lib_name="lua"
|
||||
break
|
||||
else
|
||||
lua_lib_path=""
|
||||
lua_lib_name=""
|
||||
fi
|
||||
done
|
||||
if test -n "$lua_lib_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
for x in ${test_paths}; do
|
||||
if test -e "${x}/include/lua.h"; then
|
||||
lua_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/lua.h"; then
|
||||
lua_inc_path="${x}"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Check some sub-paths as well
|
||||
for lua_pkg_name in ${lua_lib_name} ${LUA_PKGNAMES}; do
|
||||
if test -e "${x}/include/${lua_pkg_name}/lua.h"; then
|
||||
lua_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/${lua_pkg_name}/lua.h"; then
|
||||
lua_inc_path="${x}"
|
||||
break
|
||||
else
|
||||
lua_inc_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$lua_inc_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${lua_lib_path}" -a -n "${lua_inc_path}"; then
|
||||
LUA_CONFIG=""
|
||||
AC_MSG_RESULT([${lua_lib_path} ${lua_inc_path}])
|
||||
LUA_VERSION="5.1"
|
||||
LUA_CFLAGS="-I${lua_inc_path}"
|
||||
LUA_LDADD="-l${lua_lib_name}"
|
||||
LUA_LDFLAGS="-L${lua_lib_path}"
|
||||
else
|
||||
LUA_VERSION=""
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
AC_SUBST(LUA_CFLAGS)
|
||||
AC_SUBST(LUA_LDADD)
|
||||
AC_SUBST(LUA_LDFLAGS)
|
||||
|
||||
if test -z "${LUA_VERSION}"; then
|
||||
ifelse([$2], , AC_MSG_NOTICE([optional lua library not found]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using lua v${LUA_VERSION}])
|
||||
LUA_CFLAGS="-DWITH_LUA ${LUA_CFLAGS}"
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,90 +0,0 @@
|
||||
dnl Check for PCRE Libraries
|
||||
dnl CHECK_PCRE(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl PCRE_CFLAGS
|
||||
dnl PCRE_LIBS
|
||||
|
||||
PCRE_CONFIG=""
|
||||
PCRE_VERSION=""
|
||||
PCRE_CPPFLAGS=""
|
||||
PCRE_CFLAGS=""
|
||||
PCRE_LDFLAGS=""
|
||||
PCRE_LDADD=""
|
||||
PCRE_LD_PATH=""
|
||||
|
||||
AC_DEFUN([CHECK_PCRE],
|
||||
[dnl
|
||||
|
||||
AC_ARG_WITH(
|
||||
pcre,
|
||||
[AC_HELP_STRING([--with-pcre=PATH],[Path to pcre prefix or config script])],
|
||||
[test_paths="${with_pcre}"],
|
||||
[test_paths="/usr/local/libpcre /usr/local/pcre /usr/local /opt/libpcre /opt/pcre /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libpcre config script])
|
||||
|
||||
dnl # Determine pcre lib directory
|
||||
if test -z "${with_pcre}"; then
|
||||
test_paths="/usr/local/pcre /usr/local /usr"
|
||||
else
|
||||
test_paths="${with_pcre}"
|
||||
fi
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
PCRE_CONFIG=$x
|
||||
pcre_path="no"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for PCRE_CONFIG in pcre-config; do
|
||||
if test -e "${x}/bin/${PCRE_CONFIG}"; then
|
||||
pcre_path="${x}/bin"
|
||||
break
|
||||
elif test -e "${x}/${PCRE_CONFIG}"; then
|
||||
pcre_path="${x}"
|
||||
break
|
||||
else
|
||||
pcre_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$pcre_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "${pcre_path}"; then
|
||||
if test "${pcre_path}" != "no"; then
|
||||
PCRE_CONFIG="${pcre_path}/${PCRE_CONFIG}"
|
||||
fi
|
||||
AC_MSG_RESULT([${PCRE_CONFIG}])
|
||||
PCRE_VERSION="`${PCRE_CONFIG} --version`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre VERSION: $PCRE_VERSION); fi
|
||||
PCRE_CFLAGS="`${PCRE_CONFIG} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre CFLAGS: $PCRE_CFLAGS); fi
|
||||
PCRE_LDADD="`${PCRE_CONFIG} --libs`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre LDADD: $PCRE_LDADD); fi
|
||||
PCRE_LD_PATH="/`${PCRE_CONFIG} --libs | cut -d'/' -f2,3,4,5,6 | cut -d ' ' -f1`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(pcre PCRE_LD_PATH: $PCRE_LD_PATH); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(PCRE_CONFIG)
|
||||
AC_SUBST(PCRE_VERSION)
|
||||
AC_SUBST(PCRE_CPPFLAGS)
|
||||
AC_SUBST(PCRE_CFLAGS)
|
||||
AC_SUBST(PCRE_LDFLAGS)
|
||||
AC_SUBST(PCRE_LDADD)
|
||||
AC_SUBST(PCRE_LD_PATH)
|
||||
|
||||
if test -z "${PCRE_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** pcre library not found.])
|
||||
ifelse([$2], , AC_MSG_ERROR([pcre library is required]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using pcre v${PCRE_VERSION}])
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,64 +0,0 @@
|
||||
dnl Check for SSDEEP Libraries
|
||||
dnl CHECK_SSDEEP(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl SSDEEP_CFLAGS
|
||||
dnl SSDEEP_LDFLAGS
|
||||
|
||||
AC_DEFUN([CHECK_SSDEEP],
|
||||
[dnl
|
||||
|
||||
SSDEEP_CFLAGS=""
|
||||
SSDEEP_LDFLAGS=""
|
||||
SSDEEP_LDADD=""
|
||||
|
||||
AC_ARG_WITH(
|
||||
ssdeep,
|
||||
[AC_HELP_STRING([--with-ssdeep=PATH],[Path to ssdeep prefix])]
|
||||
,, with_ssdeep=yes)
|
||||
|
||||
AS_CASE(["${with_ssdeep}"],
|
||||
[no], [test_paths=],
|
||||
[yes], [test_paths="/usr/ /usr/local/ /usr/local/libfuzzy /usr/local/fuzzy /opt/libfuzzy /opt/fuzzy /opt /opt/local"],
|
||||
[test_paths="${with_ssdeep}"])
|
||||
|
||||
AS_IF([test "x${test_paths}" != "x"], [
|
||||
AC_MSG_CHECKING([for ssdeep path])
|
||||
|
||||
SSDEEP_LIB_NAME="fuzzy"
|
||||
ssdeep_dir=
|
||||
|
||||
if test -z "$withssdeep" -o "$withssdeep" = "yes"; then
|
||||
for i in ${test_paths}; do
|
||||
if test -f "$i/include/fuzzy.h"; then
|
||||
SSDEEP_CFLAGS="-I$i/include"
|
||||
ssdeep_dir=$i
|
||||
fi
|
||||
done
|
||||
else
|
||||
if test -f "$withssdeep/include/fuzzy.h"; then
|
||||
SSDEEP_CFLAGS="-I$withssdeep/include"
|
||||
ssdeep_dir=$withssdeep
|
||||
fi
|
||||
fi
|
||||
|
||||
SSDEEP_LDFLAGS="-L$ssdeep_dir/lib -lfuzzy"
|
||||
SSDEEP_LDADD="-lfuzzy"
|
||||
|
||||
])
|
||||
|
||||
if test -z "${SSDEEP_CFLAGS}"; then
|
||||
AC_MSG_RESULT([no])
|
||||
SSDEEP_LDFLAGS=""
|
||||
SSDEEP_LDADD=""
|
||||
AC_MSG_NOTICE([optional ssdeep library not found])
|
||||
else
|
||||
SSDEEP_CFLAGS="-DWITH_SSDEEP ${SSDEEP_CFLAGS}"
|
||||
AC_MSG_RESULT([${SSDEEP_LDFLAGS} ${SSDEEP_CFLAGS}])
|
||||
fi
|
||||
|
||||
AC_SUBST(SSDEEP_LDFLAGS)
|
||||
AC_SUBST(SSDEEP_LDADD)
|
||||
AC_SUBST(SSDEEP_CFLAGS)
|
||||
|
||||
|
||||
])
|
||||
@@ -1,90 +0,0 @@
|
||||
dnl Check for LIBXML2 Libraries
|
||||
dnl CHECK_LIBXML2(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl LIBXML2_CFLAGS
|
||||
dnl LIBXML2_LIBS
|
||||
|
||||
LIBXML2_CONFIG=""
|
||||
LIBXML2_VERSION=""
|
||||
LIBXML2_CFLAGS=""
|
||||
LIBXML2_CPPFLAGS=""
|
||||
LIBXML2_LDADD=""
|
||||
LIBXML2_LDFLAGS=""
|
||||
|
||||
AC_DEFUN([CHECK_LIBXML2],
|
||||
[dnl
|
||||
|
||||
AC_ARG_WITH(
|
||||
libxml,
|
||||
[AC_HELP_STRING([--with-libxml=PATH],[Path to libxml2 prefix or config script])],
|
||||
[test_paths="${with_libxml}"],
|
||||
[test_paths="/usr/local/libxml2 /usr/local/xml2 /usr/local/xml /usr/local /opt/libxml2 /opt/libxml /opt/xml2 /opt/xml /opt /usr"])
|
||||
|
||||
AC_MSG_CHECKING([for libxml2 config script])
|
||||
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
LIBXML2_CONFIG=$x
|
||||
libxml2_path="no"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for LIBXML2_CONFIG in xml2-config xml-2-config xml-config; do
|
||||
if test -e "${x}/bin/${LIBXML2_CONFIG}"; then
|
||||
libxml2_path="${x}/bin"
|
||||
break
|
||||
elif test -e "${x}/${LIBXML2_CONFIG}"; then
|
||||
libxml2_path="${x}"
|
||||
break
|
||||
else
|
||||
libxml2_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$libxml2_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if test -n "${libxml2_path}"; then
|
||||
if test "${libxml2_path}" != "no"; then
|
||||
LIBXML2_CONFIG="${libxml2_path}/${LIBXML2_CONFIG}"
|
||||
fi
|
||||
AC_MSG_RESULT([${LIBXML2_CONFIG}])
|
||||
LIBXML2_VERSION=`${LIBXML2_CONFIG} --version | sed 's/^[[^0-9]][[^[:space:]]][[^[:space:]]]*[[[:space:]]]*//'`
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml VERSION: $LIBXML2_VERSION); fi
|
||||
LIBXML2_CFLAGS="`${LIBXML2_CONFIG} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml CFLAGS: $LIBXML2_CFLAGS); fi
|
||||
LIBXML2_LDADD="`${LIBXML2_CONFIG} --libs`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(xml LDADD: $LIBXML2_LDADD); fi
|
||||
|
||||
AC_MSG_CHECKING([if libxml2 is at least v2.6.29])
|
||||
libxml2_min_ver=`echo 2.6.29 | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
|
||||
libxml2_ver=`echo ${LIBXML2_VERSION} | awk -F. '{print (\$ 1 * 1000000) + (\$ 2 * 1000) + \$ 3}'`
|
||||
if test "$libxml2_ver" -ge "$libxml2_min_ver"; then
|
||||
AC_MSG_RESULT([yes, $LIBXML2_VERSION])
|
||||
else
|
||||
AC_MSG_RESULT([no, $LIBXML2_VERSION])
|
||||
AC_MSG_ERROR([NOTE: libxml2 library must be at least 2.6.29])
|
||||
fi
|
||||
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
|
||||
AC_SUBST(LIBXML2_CONFIG)
|
||||
AC_SUBST(LIBXML2_VERSION)
|
||||
AC_SUBST(LIBXML2_CFLAGS)
|
||||
AC_SUBST(LIBXML2_CPPFLAGS)
|
||||
AC_SUBST(LIBXML2_LDADD)
|
||||
AC_SUBST(LIBXML2_LDFLAGS)
|
||||
|
||||
if test -z "${LIBXML2_VERSION}"; then
|
||||
AC_MSG_NOTICE([*** xml library not found.])
|
||||
ifelse([$2], , AC_MSG_ERROR([libxml2 is required]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using libxml2 v${LIBXML2_VERSION}])
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
@@ -1,153 +0,0 @@
|
||||
dnl Check for YAJL Libraries
|
||||
dnl CHECK_YAJL(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND])
|
||||
dnl Sets:
|
||||
dnl YAJL_CFLAGS
|
||||
dnl YAJL_LDADD
|
||||
dnl YAJL_LDFLAGS
|
||||
dnl YAJL_LIBS
|
||||
|
||||
AC_DEFUN([CHECK_YAJL],
|
||||
[dnl
|
||||
|
||||
AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
|
||||
YAJL_CONFIG=""
|
||||
YAJL_VERSION=""
|
||||
YAJL_CFLAGS=""
|
||||
YAJL_CPPFLAGS=""
|
||||
YAJL_LDADD=""
|
||||
YAJL_LDFLAGS=""
|
||||
YAJL_CONFIG=${PKG_CONFIG}
|
||||
YAJL_PKGNAMES="yajl2 yajl"
|
||||
YAJL_SONAMES="so la sl dll dylib"
|
||||
|
||||
AC_ARG_WITH(
|
||||
yajl,
|
||||
[AC_HELP_STRING([--with-yajl=PATH],[Path to yajl prefix or config script])]
|
||||
,, with_yajl=yes)
|
||||
|
||||
AS_CASE(["${with_yajl}"],
|
||||
[no], [test_paths=],
|
||||
[yes], [test_paths="/usr/local/libyajl /usr/local/yajl /usr/local /opt/libyajl /opt/yajl /opt /usr"],
|
||||
[test_paths="${with_yajl}"])
|
||||
|
||||
AS_IF([test "x${test_paths}" != "x"], [
|
||||
AC_MSG_CHECKING([for libyajl config script])
|
||||
for x in ${test_paths}; do
|
||||
dnl # Determine if the script was specified and use it directly
|
||||
if test ! -d "$x" -a -e "$x"; then
|
||||
YAJL_CONFIG=$x
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Try known config script names/locations
|
||||
for y in $YAJL_CONFIG; do
|
||||
if test -e "${x}/bin/${y}"; then
|
||||
YAJL_CONFIG="${x}/bin/${y}"
|
||||
yajl_config="${YAJL_CONFIG}"
|
||||
break
|
||||
elif test -e "${x}/${y}"; then
|
||||
YAJL_CONFIG="${x}/${y}"
|
||||
yajl_config="${YAJL_CONFIG}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${yajl_config}"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
dnl # Try known package names
|
||||
if test -n "${YAJL_CONFIG}"; then
|
||||
YAJL_PKGNAME=""
|
||||
for x in ${YAJL_PKGNAMES}; do
|
||||
if ${YAJL_CONFIG} --exists ${x}; then
|
||||
YAJL_PKGNAME="$x"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if test -n "${YAJL_PKGNAME}"; then
|
||||
AC_MSG_RESULT([${YAJL_CONFIG}])
|
||||
YAJL_VERSION="`${YAJL_CONFIG} ${YAJL_PKGNAME} --modversion`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(yajl VERSION: $YAJL_VERSION); fi
|
||||
YAJL_CFLAGS="`${YAJL_CONFIG} ${YAJL_PKGNAME} --cflags`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(yajl CFLAGS: $YAJL_CFLAGS); fi
|
||||
YAJL_LDADD="`${YAJL_CONFIG} ${YAJL_PKGNAME} --libs-only-l`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(yajl LDADD: $YAJL_LDADD); fi
|
||||
YAJL_LDFLAGS="`${YAJL_CONFIG} ${YAJL_PKGNAME} --libs-only-L --libs-only-other`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(yajl LDFLAGS: $YAJL_LDFLAGS); fi
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
dnl Hack to just try to find the lib and include
|
||||
AC_MSG_CHECKING([for yajl install])
|
||||
for x in ${test_paths}; do
|
||||
for y in ${YAJL_SONAMES}; do
|
||||
if test -e "${x}/libyajl.${y}"; then
|
||||
yajl_lib_path="${x}/"
|
||||
yajl_lib_name="yajl"
|
||||
break
|
||||
else
|
||||
yajl_lib_path=""
|
||||
yajl_lib_name=""
|
||||
fi
|
||||
done
|
||||
if test -n "$yajl_lib_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
for x in ${test_paths}; do
|
||||
if test -e "${x}/include/yajl_parse.h"; then
|
||||
yajl_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/yajl_parse.h"; then
|
||||
yajl_inc_path="${x}"
|
||||
break
|
||||
fi
|
||||
|
||||
dnl # Check some sub-paths as well
|
||||
for yajl_pkg_name in ${yajl_lib_name} ${YAJL_PKGNAMES}; do
|
||||
if test -e "${x}/include/${yajl_pkg_name}/yajl_parse.h"; then
|
||||
yajl_inc_path="${x}/include"
|
||||
break
|
||||
elif test -e "${x}/${yajl_pkg_name}/yajl_parse.h"; then
|
||||
yajl_inc_path="${x}"
|
||||
break
|
||||
else
|
||||
yajl_inc_path=""
|
||||
fi
|
||||
done
|
||||
if test -n "$yajl_inc_path"; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test -n "${yajl_lib_path}" -a -n "${yajl_inc_path}"; then
|
||||
YAJL_CONFIG=""
|
||||
AC_MSG_RESULT([${yajl_lib_path} ${yajl_inc_path}])
|
||||
YAJL_VERSION="2"
|
||||
YAJL_CFLAGS="-I${yajl_inc_path}"
|
||||
YAJL_LDADD="-l${yajl_lib_name}"
|
||||
YAJL_LDFLAGS="-L${yajl_lib_path}"
|
||||
else
|
||||
YAJL_VERSION=""
|
||||
AC_MSG_RESULT([no])
|
||||
fi
|
||||
fi
|
||||
|
||||
])
|
||||
|
||||
YAJL_LIBS=${YAJL_LDADD}
|
||||
AC_SUBST(YAJL_CFLAGS)
|
||||
AC_SUBST(YAJL_LDADD)
|
||||
AC_SUBST(YAJL_LIBS)
|
||||
AC_SUBST(YAJL_LDFLAGS)
|
||||
if test -z "${YAJL_VERSION}"; then
|
||||
ifelse([$2], , AC_MSG_NOTICE([optional yajl library not found]), $2)
|
||||
else
|
||||
AC_MSG_NOTICE([using yajl v${YAJL_VERSION}])
|
||||
YAJL_CFLAGS="-DWITH_YAJL ${YAJL_CFLAGS}"
|
||||
ifelse([$1], , , $1)
|
||||
fi
|
||||
])
|
||||
772
configure.ac
772
configure.ac
@@ -1,772 +0,0 @@
|
||||
dnl
|
||||
dnl Autoconf configuration for ModSecurity
|
||||
dnl
|
||||
dnl Use ./autogen.sh to produce a configure script
|
||||
dnl
|
||||
|
||||
AC_PREREQ(2.63)
|
||||
|
||||
AC_INIT([modsecurity], [2.9], [support@modsecurity.org])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([build])
|
||||
AC_CONFIG_SRCDIR([LICENSE])
|
||||
AC_CONFIG_HEADERS([apache2/modsecurity_config_auto.h])
|
||||
AC_CONFIG_AUX_DIR([build])
|
||||
AC_PREFIX_DEFAULT([/usr/local/modsecurity])
|
||||
|
||||
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
||||
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
|
||||
|
||||
LT_PREREQ([2.2])
|
||||
LT_INIT([dlopen])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_AWK
|
||||
AC_PROG_CC
|
||||
AC_PROG_CPP
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PROG_MAKE_SET
|
||||
AC_PROG_GREP
|
||||
AC_PATH_PROGS(PERL, [perl perl5], )
|
||||
AC_PATH_PROGS(ENV_CMD, [env printenv], )
|
||||
|
||||
# Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h unistd.h sys/types.h sys/stat.h sys/utsname.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_CONST
|
||||
AC_C_INLINE
|
||||
AC_C_RESTRICT
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_TM
|
||||
AC_TYPE_UINT8_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
AC_FUNC_MEMCMP
|
||||
AC_CHECK_FUNCS([atexit getcwd memmove memset strcasecmp strchr strdup strerror strncasecmp strrchr strstr strtol fchmod strcasestr])
|
||||
|
||||
# Some directories
|
||||
MSC_BASE_DIR=`pwd`
|
||||
MSC_PKGBASE_DIR="$MSC_BASE_DIR/.."
|
||||
MSC_TEST_DIR="$MSC_BASE_DIR/tests"
|
||||
MSC_REGRESSION_DIR="$MSC_TEST_DIR/regression"
|
||||
MSC_REGRESSION_SERVERROOT_DIR="$MSC_REGRESSION_DIR/server_root"
|
||||
MSC_REGRESSION_CONF_DIR="$MSC_REGRESSION_SERVERROOT_DIR/conf"
|
||||
MSC_REGRESSION_LOGS_DIR="$MSC_REGRESSION_SERVERROOT_DIR/logs"
|
||||
MSC_REGRESSION_DOCROOT_DIR="$MSC_REGRESSION_SERVERROOT_DIR/htdocs"
|
||||
|
||||
AC_SUBST(MSC_BASE_DIR)
|
||||
AC_SUBST(MSC_PKGBASE_DIR)
|
||||
AC_SUBST(MSC_TEST_DIR)
|
||||
AC_SUBST(MSC_REGRESSION_DIR)
|
||||
AC_SUBST(MSC_REGRESSION_SERVERROOT_DIR)
|
||||
AC_SUBST(MSC_REGRESSION_CONF_DIR)
|
||||
AC_SUBST(MSC_REGRESSION_LOGS_DIR)
|
||||
AC_SUBST(MSC_REGRESSION_DOCROOT_DIR)
|
||||
|
||||
### Configure Options
|
||||
|
||||
#OS type
|
||||
|
||||
AC_CANONICAL_HOST
|
||||
CANONICAL_HOST=$host
|
||||
|
||||
AH_TEMPLATE([AIX], [Define if the operating system is AIX])
|
||||
AH_TEMPLATE([LINUX], [Define if the operating system is LINUX])
|
||||
AH_TEMPLATE([OPENBSD], [Define if the operating system is OpenBSD])
|
||||
AH_TEMPLATE([SOLARIS], [Define if the operating system is SOLARIS])
|
||||
AH_TEMPLATE([HPUX], [Define if the operating system is HPUX])
|
||||
AH_TEMPLATE([MACOSX], [Define if the operating system is Macintosh OSX])
|
||||
AH_TEMPLATE([FREEBSD], [Define if the operating system is FREEBSD])
|
||||
AH_TEMPLATE([NETBSD], [Define if the operating system is NetBSD])
|
||||
|
||||
|
||||
case $host in
|
||||
*-*-aix*)
|
||||
echo "Checking platform... Identified as AIX"
|
||||
aixos=true
|
||||
;;
|
||||
*-*-hpux*)
|
||||
echo "Checking platform... Identified as HPUX"
|
||||
hpuxos=true
|
||||
;;
|
||||
*-*-darwin*)
|
||||
echo "Checking platform... Identified as Macintosh OS X"
|
||||
macos=true
|
||||
;;
|
||||
*-*-linux*)
|
||||
echo "Checking platform... Identified as Linux"
|
||||
linuxos=true
|
||||
case "${host_cpu}" in
|
||||
s390x)
|
||||
cpu_type="-DLINUX_S390"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*-*-solaris*)
|
||||
echo "Checking platform... Identified as Solaris"
|
||||
solarisos=true
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
echo "Checking platform... Identified as FreeBSD"
|
||||
freebsdos=true
|
||||
;;
|
||||
*-*-netbsd*)
|
||||
echo "Checking platform... Identified as NetBSD"
|
||||
netbsdos=true
|
||||
;;
|
||||
*-*-openbsd*)
|
||||
echo "Checking platform... Identified as OpenBSD"
|
||||
openbsdos=true
|
||||
;;
|
||||
*-*-kfreebsd*)
|
||||
echo "Checking platform... Identified as kFreeBSD, treating as linux"
|
||||
linuxos=true
|
||||
;;
|
||||
*-*-gnu*.*)
|
||||
echo "Checking platform... Identified as HURD, treating as linux"
|
||||
linuxos=true
|
||||
;;
|
||||
*)
|
||||
echo "Unknown CANONICAL_HOST $host"
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
|
||||
AM_CONDITIONAL([AIX], [test x$aixos = xtrue])
|
||||
AM_CONDITIONAL([HPUX], [test x$hpuxos = xtrue])
|
||||
AM_CONDITIONAL([MACOSX], [test x$macos = xtrue])
|
||||
AM_CONDITIONAL([LINUX], [test x$linuxos = xtrue])
|
||||
AM_CONDITIONAL([LINUX390], [test x$linuxos390 = xtrue])
|
||||
AM_CONDITIONAL([SOLARIS], [test x$solarisos = xtrue])
|
||||
AM_CONDITIONAL([FREEBSD], [test x$freebsdos = xtrue])
|
||||
AM_CONDITIONAL([OPENBSD], [test x$openbsdos = xtrue])
|
||||
AM_CONDITIONAL([NETBSD], [test x$netbsdos = xtrue])
|
||||
|
||||
#Subdirs
|
||||
TOPLEVEL_SUBDIRS="tools"
|
||||
|
||||
# Apache2 Module
|
||||
AC_ARG_ENABLE(apache2-module,
|
||||
AS_HELP_STRING([--disable-apache2-module],
|
||||
[Disable building Apache2 module.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_apache2_module=1
|
||||
else
|
||||
build_apache2_module=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_apache2_module=1
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_APACHE2_MODULE], [test "$build_apache2_module" -eq 1])
|
||||
if test "$build_apache2_module" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS apache2"
|
||||
fi
|
||||
|
||||
|
||||
# Standalone Module
|
||||
AC_ARG_ENABLE(standalone-module,
|
||||
AS_HELP_STRING([--enable-standalone-module],
|
||||
[Enable building standalone module.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_standalone_module=1
|
||||
else
|
||||
build_standalone_module=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_standalone_module=0
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_STANDALONE_MODULE], [test "$build_standalone_module" -eq 1])
|
||||
if test "$build_standalone_module" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS standalone"
|
||||
fi
|
||||
|
||||
|
||||
# Extensions
|
||||
AC_ARG_ENABLE(extentions,
|
||||
AS_HELP_STRING([--enable-extentions],
|
||||
[Enable building extension.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_extentions=1
|
||||
else
|
||||
build_extentions=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_extentions=0
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_extentions], [test "$build_extentions" -eq 1])
|
||||
if test "$build_extentions" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS ext"
|
||||
fi
|
||||
|
||||
|
||||
# Mlogc
|
||||
AC_ARG_ENABLE(mlogc,
|
||||
AS_HELP_STRING([--disable-mlogc],
|
||||
[Disable building mlogc.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_mlogc=1
|
||||
else
|
||||
build_mlogc=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_mlogc=1
|
||||
])
|
||||
|
||||
CHECK_CURL()
|
||||
|
||||
if test -z "${CURL_VERSION}"; then
|
||||
AC_MSG_NOTICE([NOTE: mlgoc compilation was disabled.])
|
||||
build_mlogc=0
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL([BUILD_MLOGC], [test "$build_mlogc" -eq 1])
|
||||
if test "$build_mlogc" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS mlogc"
|
||||
fi
|
||||
|
||||
# Audit Log Parser v2 (ALP2)
|
||||
AC_ARG_ENABLE(alp2,
|
||||
AS_HELP_STRING([--enable-alp2],
|
||||
[Enable building audit log parser lib.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_alp2=1
|
||||
else
|
||||
build_alp2=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_alp2=0
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_ALP2], [test "$build_alp2" -eq 1])
|
||||
if test "$build_alp2" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS alp2"
|
||||
fi
|
||||
|
||||
# Documentation
|
||||
AC_ARG_ENABLE(docs,
|
||||
AS_HELP_STRING([--enable-docs],
|
||||
[Enable building documentation.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
build_docs=1
|
||||
else
|
||||
build_docs=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
build_docs=0
|
||||
])
|
||||
AM_CONDITIONAL([BUILD_DOCS], [test "$build_docs" -eq 1])
|
||||
if test "$build_docs" -eq 1; then
|
||||
TOPLEVEL_SUBDIRS="$TOPLEVEL_SUBDIRS docs"
|
||||
fi
|
||||
|
||||
|
||||
# Add PCRE Studying
|
||||
|
||||
AC_ARG_ENABLE(pcre-study,
|
||||
AS_HELP_STRING([--enable-pcre-study],
|
||||
[Enable PCRE regex studying during configure.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
pcre_study='-DWITH_PCRE_STUDY'
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_study"
|
||||
else
|
||||
pcre_study=''
|
||||
fi
|
||||
],
|
||||
[
|
||||
pcre_study='-DWITH_PCRE_STUDY'
|
||||
])
|
||||
|
||||
# Add PCRE JIT
|
||||
|
||||
AC_ARG_ENABLE(pcre-jit,
|
||||
AS_HELP_STRING([--enable-pcre-jit],
|
||||
[Enable PCRE regex jit support during configure.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
pcre_jit='-DWITH_PCRE_JIT'
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_jit"
|
||||
else
|
||||
pcre_jit=''
|
||||
fi
|
||||
],
|
||||
[
|
||||
pcre_jit=''
|
||||
])
|
||||
|
||||
|
||||
# Limit PCRE matching
|
||||
AC_ARG_ENABLE(pcre-match-limit,
|
||||
AS_HELP_STRING([--enable-pcre-match-limit],
|
||||
[Enable PCRE regex match limit during configure.]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_MSG_ERROR([PCRE match limits require a numeric value])
|
||||
elif test "$enableval" = "no"; then
|
||||
pcre_match_limit=''
|
||||
else
|
||||
pcre_match_limit="-DMODSEC_PCRE_MATCH_LIMIT=$enableval"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit"
|
||||
fi
|
||||
],
|
||||
[
|
||||
pcre_match_limit='-DMODSEC_PCRE_MATCH_LIMIT=1500'
|
||||
])
|
||||
|
||||
# Limit PCRE matching recursion
|
||||
AC_ARG_ENABLE(pcre-match-limit-recursion,
|
||||
AS_HELP_STRING([--enable-pcre-match-limit-recursion],
|
||||
[Enable PCRE regex match limit recursion during configure.]),
|
||||
[
|
||||
if test "$enableval" = "yes"; then
|
||||
AC_MSG_ERROR([PCRE match limits require a numeric value])
|
||||
elif test "$enableval" = "no"; then
|
||||
pcre_match_limit_recursion=''
|
||||
else
|
||||
pcre_match_limit_recursion="-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=$enableval"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $pcre_match_limit_recursion"
|
||||
fi
|
||||
],
|
||||
[
|
||||
pcre_match_limit_recursion='-DMODSEC_PCRE_MATCH_LIMIT_RECURSION=1500'
|
||||
])
|
||||
|
||||
# Enable Lua per transaction cache
|
||||
AC_ARG_ENABLE(lua-cache,
|
||||
AS_HELP_STRING([--enable-lua-cache],
|
||||
[Enable Lua per transaction cache.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
lua_cache="-DCACHE_LUA"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $lua_cache"
|
||||
else
|
||||
lua_cache=
|
||||
fi
|
||||
],
|
||||
[
|
||||
lua_cache=
|
||||
])
|
||||
|
||||
# Enable phase-1 in post_read_request
|
||||
AC_ARG_ENABLE(htaccess-config,
|
||||
AS_HELP_STRING([--enable-htaccess-config],
|
||||
[Enable some mod_security directives into htaccess files.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
htaccess_config="-DHTACCESS_CONFIG"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $htaccess_config"
|
||||
else
|
||||
htaccess_config=
|
||||
fi
|
||||
],
|
||||
[
|
||||
htaccess_config=
|
||||
])
|
||||
|
||||
# Enable phase-1 in post_read_request
|
||||
AC_ARG_ENABLE(request-early,
|
||||
AS_HELP_STRING([--enable-request-early],
|
||||
[Place phase1 into post_read_request hook. default is hook_request_early]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
request_early="-DREQUEST_EARLY"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $request_early"
|
||||
else
|
||||
request_early=
|
||||
fi
|
||||
],
|
||||
[
|
||||
request_early='-DREQUEST_EARLY'
|
||||
])
|
||||
|
||||
# Ignore configure errors
|
||||
AC_ARG_ENABLE(errors,
|
||||
AS_HELP_STRING([--disable-errors],
|
||||
[Disable errors during configure.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
report_errors=1
|
||||
else
|
||||
report_errors=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
report_errors=1
|
||||
])
|
||||
|
||||
# Verbose output
|
||||
AC_ARG_ENABLE(verbose-output,
|
||||
AS_HELP_STRING([--enable-verbose-output],
|
||||
[Enable more verbose configure output.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
verbose_output=1
|
||||
else
|
||||
verbose_output=0
|
||||
fi
|
||||
],
|
||||
[
|
||||
verbose_output=0
|
||||
])
|
||||
|
||||
# Strict Compile
|
||||
AC_ARG_ENABLE(strict-compile,
|
||||
AS_HELP_STRING([--enable-strict-compile],
|
||||
[Enable strict compilation (warnings are errors).]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
strict_compile="-std=c99 -Wstrict-overflow=1 -Wextra -Wno-missing-field-initializers -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wno-unused-parameter -Wformat -Wformat-security -Werror -fstack-protector -D_FORTIFY_SOURCE=2"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $strict_compile"
|
||||
else
|
||||
strict_compile=
|
||||
fi
|
||||
],
|
||||
[
|
||||
strict_compile=
|
||||
])
|
||||
|
||||
# DEBUG_CONF
|
||||
AC_ARG_ENABLE(debug-conf,
|
||||
AS_HELP_STRING([--enable-debug-conf],
|
||||
[Enable debug during configuration.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
debug_conf="-DDEBUG_CONF"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_conf"
|
||||
else
|
||||
debug_conf=
|
||||
fi
|
||||
],
|
||||
[
|
||||
debug_conf=
|
||||
])
|
||||
|
||||
# CACHE_DEBUG
|
||||
AC_ARG_ENABLE(debug-cache,
|
||||
AS_HELP_STRING([--enable-debug-cache],
|
||||
[Enable debug for transformation caching.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
debug_cache="-DCACHE_DEBUG"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_cache"
|
||||
else
|
||||
debug_cache=
|
||||
fi
|
||||
],
|
||||
[
|
||||
debug_cache=
|
||||
])
|
||||
|
||||
# DEBUG_ACMP
|
||||
AC_ARG_ENABLE(debug-acmp,
|
||||
AS_HELP_STRING([--enable-debug-acmp],
|
||||
[Enable debugging acmp code.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
debug_acmp="-DDEBUG_ACMP"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_acmp"
|
||||
else
|
||||
debug_acmp=
|
||||
fi
|
||||
],
|
||||
[
|
||||
debug_acmp=
|
||||
])
|
||||
|
||||
# DEBUG_MEM
|
||||
AC_ARG_ENABLE(debug-mem,
|
||||
AS_HELP_STRING([--enable-debug-mem],
|
||||
[Enable debug during configuration.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
debug_mem="-DDEBUG_MEM"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $debug_mem"
|
||||
else
|
||||
debug_mem=
|
||||
fi
|
||||
],
|
||||
[
|
||||
debug_mem=
|
||||
])
|
||||
|
||||
# PERFORMANCE_MEASUREMENT
|
||||
AC_ARG_ENABLE(performance-measurement,
|
||||
AS_HELP_STRING([--enable-performance-measurement],
|
||||
[Enable performance-measurement stats.]),
|
||||
[
|
||||
if test "$enableval" != "no"; then
|
||||
perf_meas="-DPERFORMANCE_MEASUREMENT"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $perf_meas"
|
||||
else
|
||||
perf_meas=
|
||||
fi
|
||||
],
|
||||
[
|
||||
perf_meas=
|
||||
])
|
||||
|
||||
# NO_MODSEC_API
|
||||
AC_ARG_ENABLE(modsec-api,
|
||||
AS_HELP_STRING([--disable-modsec-api],
|
||||
[Disable the API; compiling against some older Apache versions require this.]),
|
||||
[
|
||||
if test "$enableval" != "yes"; then
|
||||
modsec_api="-DNO_MODSEC_API"
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS $modsec_api"
|
||||
else
|
||||
modsec_api=
|
||||
fi
|
||||
],
|
||||
[
|
||||
modsec_api=
|
||||
])
|
||||
|
||||
# Find apxs
|
||||
AC_MSG_NOTICE(looking for Apache module support via DSO through APXS)
|
||||
AC_ARG_WITH(apxs,
|
||||
[AS_HELP_STRING([[--with-apxs=FILE]],
|
||||
[FILE is the path to apxs; defaults to "apxs".])],
|
||||
[
|
||||
if test "$withval" = "yes"; then
|
||||
APXS=apxs
|
||||
else
|
||||
APXS="$withval"
|
||||
fi
|
||||
])
|
||||
|
||||
if test -z "$APXS"; then
|
||||
for i in /usr/local/apache22/bin \
|
||||
/usr/local/apache2/bin \
|
||||
/usr/local/apache/bin \
|
||||
/usr/local/sbin \
|
||||
/usr/local/bin \
|
||||
/usr/sbin \
|
||||
/usr/bin;
|
||||
do
|
||||
if test -f "$i/apxs2"; then
|
||||
APXS="$i/apxs2"
|
||||
break
|
||||
elif test -f "$i/apxs"; then
|
||||
APXS="$i/apxs"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# arbitrarily picking the same version subversion looks for, don't know how
|
||||
# accurate this really is, but at least it'll force us to have apache2...
|
||||
HTTPD_WANTED_MMN=20020903
|
||||
|
||||
if test -n "$APXS" -a "$APXS" != "no" -a -x "$APXS" ; then
|
||||
APXS_INCLUDE="`$APXS -q INCLUDEDIR`"
|
||||
if test -r $APXS_INCLUDE/httpd.h; then
|
||||
AC_MSG_NOTICE(found apxs at $APXS)
|
||||
AC_MSG_NOTICE(checking httpd version)
|
||||
AC_EGREP_CPP(VERSION_OK,
|
||||
[
|
||||
#include "$APXS_INCLUDE/ap_mmn.h"
|
||||
#if AP_MODULE_MAGIC_AT_LEAST($HTTPD_WANTED_MMN,0)
|
||||
VERSION_OK
|
||||
#endif],
|
||||
[AC_MSG_NOTICE(httpd is recent enough)],
|
||||
[
|
||||
if test "$report_errors" -eq 1; then
|
||||
AC_MSG_ERROR(apache is too old, mmn must be at least $HTTPD_WANTED_MMN)
|
||||
else
|
||||
AC_MSG_NOTICE(apache is too old, mmn must be at least $HTTPD_WANTED_MMN)
|
||||
fi
|
||||
])
|
||||
fi
|
||||
APXS_INCLUDEDIR="`$APXS -q INCLUDEDIR`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDEDIR: $APXS_INCLUDEDIR); fi
|
||||
# Make sure the include dir is used
|
||||
if test -n "$APXS_INCLUDEDIR"; then
|
||||
APXS_INCLUDES="-I${APXS_INCLUDEDIR} `$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`"
|
||||
else
|
||||
APXS_INCLUDES="`$APXS -q INCLUDES` `$APXS -q EXTRA_INCLUDES`"
|
||||
fi
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs INCLUDES: $APXS_INCLUDES); fi
|
||||
APXS_CFLAGS=-I`$APXS -q INCLUDEDIR`
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CFLAGS: $APXS_CFLAGS); fi
|
||||
APXS_LDFLAGS=
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LDFLAGS: $APXS_LDFLAGS); fi
|
||||
APXS_LIBDIR="`$APXS -q LIBDIR`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBDIR: $APXS_LIBDIR); fi
|
||||
# Make sure the lib dir is used
|
||||
if test -n "$APXS_LIBDIR"; then
|
||||
APXS_LIBS="-L${APXS_LIBDIR} `$APXS -q LIBS` `$APXS -q EXTRA_LIBS`"
|
||||
else
|
||||
APXS_LIBS="`$APXS -q LIBS` `$APXS -q EXTRA_LIBS`"
|
||||
fi
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBS: $APXS_LIBS); fi
|
||||
APXS_LIBTOOL="`$APXS -q LIBTOOL`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBTOOL: $APXS_LIBTOOL); fi
|
||||
APXS_CC="`$APXS -q CC`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs CC: $APXS_CC); fi
|
||||
APXS_BINDIR="`$APXS -q BINDIR`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs BINDIR: $APXS_BINDIR); fi
|
||||
APXS_SBINDIR="`$APXS -q SBINDIR`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs SBINDIR: $APXS_SBINDIR); fi
|
||||
APXS_PROGNAME="`$APXS -q PROGNAME`"
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs PROGNAME: $APXS_PROGNAME); fi
|
||||
APXS_LIBEXECDIR="`$APXS -q LIBEXECDIR`"
|
||||
if test "xx$APXS_LIBEXECDIR" = "xx"; then APXS_LIBEXECDIR="`$APXS -q LIBDIR`/modules"; fi
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs LIBEXECDIR: $APXS_LIBEXECDIR); fi
|
||||
APXS_MODULES=$APXS_LIBEXECDIR
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs MODULES: $APXS_MODULES); fi
|
||||
if test "$APXS_SBINDIR" = "/"; then
|
||||
APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME"
|
||||
else
|
||||
APXS_HTTPD="$APXS_SBINDIR/$APXS_PROGNAME"
|
||||
fi
|
||||
if test "$verbose_output" -eq 1; then AC_MSG_NOTICE(apxs HTTPD: $APXS_HTTPD); fi
|
||||
else
|
||||
if test "$report_errors" -eq 1; then
|
||||
AC_MSG_ERROR(couldn't find APXS)
|
||||
else
|
||||
AC_MSG_NOTICE(couldn't find APXS)
|
||||
fi
|
||||
fi
|
||||
|
||||
### Build *EXTRA_CFLAGS vars
|
||||
|
||||
# Allow overriding EXTRA_CFLAGS
|
||||
if $ENV_CMD | $GREP "^EXTRA_CFLAGS" > /dev/null 2>&1; then
|
||||
if test -z "$debug_mem"; then
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS $strict_compile"
|
||||
fi
|
||||
else
|
||||
if test -n "$debug_mem"; then
|
||||
EXTRA_CFLAGS="-O0 -g -Wall"
|
||||
else
|
||||
EXTRA_CFLAGS="-O2 -g -Wall $strict_compile"
|
||||
fi
|
||||
fi
|
||||
|
||||
MODSEC_EXTRA_CFLAGS="$pcre_study $pcre_match_limit $pcre_match_limit_recursion $pcre_jit $request_early $htaccess_config $lua_cache $debug_conf $debug_cache $debug_acmp $debug_mem $perf_meas $modsec_api $cpu_type"
|
||||
|
||||
APXS_WRAPPER=build/apxs-wrapper
|
||||
APXS_EXTRA_CFLAGS=""
|
||||
for f in $EXTRA_CFLAGS; do
|
||||
APXS_EXTRA_CFLAGS="$APXS_EXTRA_CFLAGS -Wc,$f"
|
||||
done;
|
||||
MODSEC_APXS_EXTRA_CFLAGS=""
|
||||
for f in $MODSEC_EXTRA_CFLAGS; do
|
||||
MODSEC_APXS_EXTRA_CFLAGS="$MODSEC_APXS_EXTRA_CFLAGS -Wc,$f"
|
||||
done;
|
||||
|
||||
### Substitute the vars
|
||||
|
||||
AC_SUBST(TOPLEVEL_SUBDIRS)
|
||||
AC_SUBST(EXTRA_CFLAGS)
|
||||
AC_SUBST(MODSEC_EXTRA_CFLAGS)
|
||||
AC_SUBST(APXS)
|
||||
AC_SUBST(APXS_WRAPPER)
|
||||
AC_SUBST(APXS_INCLUDEDIR)
|
||||
AC_SUBST(APXS_INCLUDES)
|
||||
AC_SUBST(APXS_EXTRA_CFLAGS)
|
||||
AC_SUBST(MODSEC_APXS_EXTRA_CFLAGS)
|
||||
AC_SUBST(APXS_LDFLAGS)
|
||||
AC_SUBST(APXS_LIBS)
|
||||
AC_SUBST(APXS_CFLAGS)
|
||||
AC_SUBST(APXS_LIBTOOL)
|
||||
AC_SUBST(APXS_CC)
|
||||
AC_SUBST(APXS_LIBDIR)
|
||||
AC_SUBST(APXS_BINDIR)
|
||||
AC_SUBST(APXS_SBINDIR)
|
||||
AC_SUBST(APXS_PROGNAME)
|
||||
AC_SUBST(APXS_LIBEXECDIR)
|
||||
AC_SUBST(APXS_MODULES)
|
||||
AC_SUBST(APXS_HTTPD)
|
||||
|
||||
CHECK_PCRE()
|
||||
if test "$build_apache2_module" -ne 0 -o "$build_mlogc" -ne 0; then
|
||||
CHECK_APR()
|
||||
CHECK_APU()
|
||||
fi
|
||||
CHECK_LIBXML2()
|
||||
CHECK_LUA()
|
||||
#if test "$build_mlogc" -ne 0; then
|
||||
#CHECK_CURL()
|
||||
#fi
|
||||
|
||||
# Check for YAJL libs (for JSON body processor)
|
||||
CHECK_YAJL()
|
||||
#AC_SEARCH_LIBS([yajl_alloc], [yajl])
|
||||
CHECK_SSDEEP()
|
||||
#AC_SEARCH_LIBS([fuzzy_hash_buf], [fuzzy])
|
||||
|
||||
CFLAGS="$CFLAGS $APU_CFLAGS"
|
||||
AC_TRY_COMPILE(
|
||||
[#include <apr_crypto.h>],
|
||||
[
|
||||
#if APU_HAVE_CRYPTO == 0
|
||||
#error APR util was not compiled with crypto support.
|
||||
#endif
|
||||
],
|
||||
[ AC_DEFINE([WITH_APU_CRYPTO], [1], [APR util was compiled with crypto support])
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_APU_CRYPTO"
|
||||
],
|
||||
[ AC_MSG_WARN([APR util was not compiled with crypto support. SecRemoteRule will not support the parameter 'crypto']) ]
|
||||
)
|
||||
|
||||
# Current our unique download backend is curl, furhter we can support more.
|
||||
if test ! -z "${CURL_VERSION}"; then
|
||||
AC_DEFINE([WITH_REMOTE_RULES], [1], [Enables SecRemoteRules support])
|
||||
MODSEC_EXTRA_CFLAGS="$MODSEC_EXTRA_CFLAGS -DWITH_REMOTE_RULES"
|
||||
fi
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([tools/Makefile])
|
||||
if test "$build_alp2" -ne 0; then
|
||||
AC_CONFIG_FILES([alp2/Makefile])
|
||||
fi
|
||||
if test "$build_apache2_module" -ne 0; then
|
||||
AC_CONFIG_FILES([apache2/Makefile])
|
||||
fi
|
||||
if test "$build_standalone_module" -ne 0; then
|
||||
AC_CONFIG_FILES([standalone/Makefile])
|
||||
AC_CONFIG_FILES([nginx/modsecurity/config])
|
||||
fi
|
||||
if test "$build_extentions" -ne 0; then
|
||||
AC_CONFIG_FILES([ext/Makefile])
|
||||
fi
|
||||
AC_CONFIG_FILES([build/apxs-wrapper], [chmod +x build/apxs-wrapper])
|
||||
if test -e "$PERL"; then
|
||||
if test "$build_mlogc" -ne 0; then
|
||||
AC_CONFIG_FILES([mlogc/mlogc-batch-load.pl], [chmod +x mlogc/mlogc-batch-load.pl])
|
||||
AC_CONFIG_FILES([tests/regression/misc/40-secRemoteRules.t])
|
||||
AC_CONFIG_FILES([tests/regression/misc/50-ipmatchfromfile-external.t])
|
||||
AC_CONFIG_FILES([tests/regression/misc/60-pmfromfile-external.t])
|
||||
fi
|
||||
AC_CONFIG_FILES([tests/run-unit-tests.pl], [chmod +x tests/run-unit-tests.pl])
|
||||
AC_CONFIG_FILES([tests/run-regression-tests.pl], [chmod +x tests/run-regression-tests.pl])
|
||||
AC_CONFIG_FILES([tests/gen_rx-pm.pl], [chmod +x tests/gen_rx-pm.pl])
|
||||
AC_CONFIG_FILES([tests/csv_rx-pm.pl], [chmod +x tests/csv_rx-pm.pl])
|
||||
AC_CONFIG_FILES([tests/regression/server_root/conf/httpd.conf])
|
||||
|
||||
# Perl based tools
|
||||
AC_CONFIG_FILES([tools/rules-updater.pl], [chmod +x tools/rules-updater.pl])
|
||||
fi
|
||||
if test "$build_mlogc" -ne 0; then
|
||||
AC_CONFIG_FILES([mlogc/Makefile])
|
||||
fi
|
||||
AC_CONFIG_FILES([tests/Makefile])
|
||||
|
||||
AC_OUTPUT
|
||||
@@ -1,11 +0,0 @@
|
||||
Please access the ModSecurity Github space to access the below documentation.
|
||||
|
||||
* ModSecurity 2 Data Formats
|
||||
* ModSecurity Frequently Asked Questions (FAQ)
|
||||
* ModSecurity Migration Matrix
|
||||
* ModSecurity Rules Language Porting Specification
|
||||
* ModSecurity Wiki
|
||||
* Reference Manual
|
||||
* RoadMap
|
||||
|
||||
https://github.com/SpiderLabs/ModSecurity/wiki/
|
||||
File diff suppressed because it is too large
Load Diff
2303
doc/doxygen-iis.conf
2303
doc/doxygen-iis.conf
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,63 +0,0 @@
|
||||
|
||||
EXT_CFLAGS = -I../apache2 \
|
||||
@APR_CFLAGS@ \
|
||||
@APU_CFLAGS@ \
|
||||
@APXS_CFLAGS@ \
|
||||
@LIBXML2_CFLAGS@ \
|
||||
@LUA_CFLAGS@ \
|
||||
@SSDEEP_CFLAGS@
|
||||
|
||||
EXT_CPPFLAGS = @APR_CPPFLAGS@ \
|
||||
@LIBXML2_CPPFLAGS@
|
||||
|
||||
EXT_LIBADD = @APR_LDADD@ \
|
||||
@APU_LDADD@ \
|
||||
@LIBXML2_LDADD@ \
|
||||
@LUA_LDADD@
|
||||
|
||||
EXT_LDFLAGS = -no-undefined -module -avoid-version \
|
||||
@APR_LDFLAGS@ \
|
||||
@APU_LDFLAGS@ \
|
||||
@APXS_LDFLAGS@ \
|
||||
@LIBXML2_LDFLAGS@ \
|
||||
@LUA_LDFLAGS@ \
|
||||
@SSDEEP_LDFLAGS@
|
||||
|
||||
pkglibdir = $(prefix)/lib
|
||||
|
||||
pkglib_LTLIBRARIES = mod_op_strstr.la \
|
||||
mod_tfn_reverse.la \
|
||||
mod_var_remote_addr_port.la \
|
||||
mod_reqbody_example.la
|
||||
|
||||
mod_op_strstr_la_SOURCES = mod_op_strstr.c
|
||||
mod_op_strstr_la_CFLAGS = $(EXT_CFLAGS)
|
||||
mod_op_strstr_la_CPPFLAGS = $(EXT_CPPFLAGS)
|
||||
mod_op_strstr_la_LIBADD = $(EXT_LIBADD)
|
||||
mod_op_strstr_la_LDFLAGS = $(EXT_LDFLAGS)
|
||||
|
||||
mod_tfn_reverse_la_SOURCES = mod_tfn_reverse.c
|
||||
mod_tfn_reverse_la_CFLAGS = $(EXT_CFLAGS)
|
||||
mod_tfn_reverse_la_CPPFLAGS = $(EXT_CPPFLAGS)
|
||||
mod_tfn_reverse_la_LIBADD = $(EXT_LIBADD)
|
||||
mod_tfn_reverse_la_LDFLAGS = $(EXT_LDFLAGS)
|
||||
|
||||
mod_var_remote_addr_port_la_SOURCES = mod_var_remote_addr_port.c
|
||||
mod_var_remote_addr_port_la_CFLAGS = $(EXT_CFLAGS)
|
||||
mod_var_remote_addr_port_la_CPPFLAGS = $(EXT_CPPFLAGS)
|
||||
mod_var_remote_addr_port_la_LIBADD = $(EXT_LIBADD)
|
||||
mod_var_remote_addr_port_la_LDFLAGS = $(EXT_LDFLAGS)
|
||||
|
||||
mod_reqbody_example_la_SOURCES = mod_reqbody_example.c
|
||||
mod_reqbody_example_la_CFLAGS = $(EXT_CFLAGS)
|
||||
mod_reqbody_example_la_CPPFLAGS = $(EXT_CPPFLAGS)
|
||||
mod_reqbody_example_la_LIBADD = $(EXT_LIBADD)
|
||||
mod_reqbody_example_la_LDFLAGS = $(EXT_LDFLAGS)
|
||||
|
||||
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 $(APXS_MODULES); \
|
||||
done
|
||||
89
ext/README
89
ext/README
@@ -1,89 +0,0 @@
|
||||
Custom ModSecurity Modules
|
||||
--------------------------
|
||||
|
||||
This directory contains three examples how you can extend
|
||||
ModSecurity without having to touch it directly, simply
|
||||
by creating custom Apache modules.
|
||||
|
||||
NOTE: ModSecurity must be compiled with API support
|
||||
to use this feature (the API is enabled by default,
|
||||
but it will have been disabled if you used -DNO_MODSEC_API).
|
||||
|
||||
|
||||
Building the Example Custom Modules
|
||||
-----------------------------------
|
||||
|
||||
1) Example custom transformation function module
|
||||
|
||||
Module mod_tfn_reverse.c creates a custom transformation
|
||||
function "reverse" that reverses the content it receives
|
||||
on input.
|
||||
|
||||
# Compile as a normal user
|
||||
apxs -I<MODSECURITY_SOURCE_CODE> -I/usr/include/libxml2 \
|
||||
-ca mod_tfn_reverse.c
|
||||
|
||||
# Install as superuser
|
||||
sudo apxs -i mod_tfn_reverse.la
|
||||
|
||||
|
||||
2) Example custom operator module
|
||||
|
||||
Module mod_op_strstr.c creates a custom operator "strstr"
|
||||
that implements fast matching using the Boyer-Moore-Horspool
|
||||
algorithm.
|
||||
|
||||
# Compile as a normal user
|
||||
apxs -I<MODSECURITY_SOURCE_CODE> -I/usr/include/libxml2 \
|
||||
-ca mod_op_strstr.c
|
||||
|
||||
# Install as superuser
|
||||
sudo apxs -i mod_op_strstr.la
|
||||
|
||||
|
||||
3) Example custom target variable module
|
||||
|
||||
Module mod_var_remote_addr_port.c creates a custom variable "REMOTE_ADDR_PORT"
|
||||
that combines the REMOTE_ADDR and REMOTE_PORT into a.b.c.d:port format.
|
||||
|
||||
# Compile as a normal user
|
||||
apxs -I<MODSECURITY_SOURCE_CODE> -I/usr/include/libxml2 \
|
||||
-ca mod_var_remote_addr_port.c
|
||||
|
||||
# Install as superuser
|
||||
sudo apxs -i mod_var_remote_addr_port.la
|
||||
|
||||
|
||||
3) Example custom request body parser module
|
||||
|
||||
Module mod_reqbody_example.c creates a custom request body parser named
|
||||
"EXAMPLE". It does noting in particular, but shows the basic structure
|
||||
of such a module.
|
||||
|
||||
# Compile as a normal user
|
||||
apxs -I<MODSECURITY_SOURCE_CODE> -I/usr/include/libxml2 \
|
||||
-ca mod_reqbody_example.c
|
||||
|
||||
# Install as superuser
|
||||
sudo apxs -i mod_var_remote_addr_port.la
|
||||
|
||||
# Write a phase 1 rule to set the parser
|
||||
SecAction "phase:1,pass,nolog,ctl:requestBodyProcessor=EXAMPLE"
|
||||
|
||||
|
||||
Using the Modules
|
||||
-----------------
|
||||
|
||||
Once the modules are built and installed, you load them like any other Apache module, but they must be loaded *after* the mod_security2.so module.
|
||||
|
||||
# Load ModSecurity
|
||||
LoadModule security2_module modules/mod_security2.so
|
||||
|
||||
# Load ModSecurity custom modules
|
||||
LoadModule tfn_reverse_module modules/mod_tfn_reverse.so
|
||||
LoadModule op_strstr_module modules/mod_op_strstr.so
|
||||
LoadModule var_remote_addr_port_module modules/mod_var_remote_addr_port.so
|
||||
|
||||
# All three custom var/op/tfn used
|
||||
SecRule REMOTE_ADDR_PORT "@strstr 1.2.3.4:5678" "t:reverse"
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "ap_config.h"
|
||||
#include "apr_optional.h"
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
#define ALPHABET_SIZE 256
|
||||
#define MAX_PATTERN_SIZE 64
|
||||
|
||||
static void initBoyerMooreHorspool(const char *pattern, int patlength,
|
||||
int *bm_badcharacter_array);
|
||||
|
||||
static int BoyerMooreHorspool(const char *pattern, int patlength,
|
||||
const char *text, int textlen, int *bm_badcharacter_array);
|
||||
|
||||
/**
|
||||
* Operator parameter initialisation entry point.
|
||||
*/
|
||||
static int op_strstr_init(msre_rule *rule, char **error_msg) {
|
||||
/* Operator initialisation function will be called once per
|
||||
* statement where operator is used. It is meant to be used
|
||||
* to check the parameters to see whether they are present
|
||||
* and if they are in the correct format.
|
||||
*/
|
||||
|
||||
/* In this example we just look for a simple non-empty parameter. */
|
||||
if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
|
||||
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'strstr'.");
|
||||
return 0; /* ERROR */
|
||||
}
|
||||
|
||||
/* If you need to transform the data in the parameter into something
|
||||
* else you should do that here. Simply create a new structure to hold
|
||||
* the transformed data and place the pointer to it into rule->op_param_data.
|
||||
* You will have access to this pointer later on.
|
||||
*/
|
||||
rule->op_param_data = apr_pcalloc(rule->ruleset->mp, ALPHABET_SIZE * sizeof(int));
|
||||
initBoyerMooreHorspool(rule->op_param, strlen(rule->op_param), (int *)rule->op_param_data);
|
||||
|
||||
/* OK */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Operator execution entry point.
|
||||
*/
|
||||
static int op_strstr_exec(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
|
||||
/* Here we need to inspect the contents of the supplied variable. */
|
||||
|
||||
/* In a general case it is possible for the value
|
||||
* to be NULL. What you need to do in this case
|
||||
* depends on your operator. In this example we return
|
||||
* a "no match" response.
|
||||
*/
|
||||
if (var->value == NULL) return 0; /* No match. */
|
||||
|
||||
/* Another thing to note is that variables are not C strings,
|
||||
* meaning the NULL byte is not used to determine the end
|
||||
* of the string. Variable length var->value_len should be
|
||||
* used for this purpose.
|
||||
*/
|
||||
|
||||
if (BoyerMooreHorspool(rule->op_param, strlen(rule->op_param),
|
||||
var->value, var->value_len, (int *)rule->op_param_data) >= 0)
|
||||
{
|
||||
return 1; /* Match. */
|
||||
}
|
||||
|
||||
return 0; /* No match. */
|
||||
}
|
||||
|
||||
static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) {
|
||||
void (*fn)(const char *name, void *fn_init, void *fn_exec);
|
||||
|
||||
/* Look for the registration function
|
||||
* exported by ModSecurity.
|
||||
*/
|
||||
fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_operator);
|
||||
if (fn) {
|
||||
/* Use it to register our new
|
||||
* transformation function under the
|
||||
* name "reverse".
|
||||
*/
|
||||
fn("strstr", (void *)op_strstr_init, (void *)op_strstr_exec);
|
||||
} else {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_op_strstr: Unable to find modsec_register_operator.");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void register_hooks(apr_pool_t *p) {
|
||||
ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST);
|
||||
}
|
||||
|
||||
/* Dispatch list for API hooks */
|
||||
module AP_MODULE_DECLARE_DATA op_strstr_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
NULL, /* create per-dir config structures */
|
||||
NULL, /* merge per-dir config structures */
|
||||
NULL, /* create per-server config structures */
|
||||
NULL, /* merge per-server config structures */
|
||||
NULL, /* table of config file commands */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
This example uses an implementation Boyer-Moore-Horspool
|
||||
matching algorithm as implemented in Streamline (http://ffpf.sourceforge.net).
|
||||
|
||||
Copyright (c) 2004-2006, Vrije Universiteit Amsterdam
|
||||
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 the Vrije Universiteit nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
*/
|
||||
|
||||
static void precompute_badcharacter(const char *pattern, int patlength,
|
||||
int bm_badcharacter_array[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALPHABET_SIZE; ++i) {
|
||||
bm_badcharacter_array[i] = patlength;
|
||||
}
|
||||
|
||||
for (i = 0; i < patlength - 1; ++i){
|
||||
bm_badcharacter_array[(uint8_t)pattern[i]] = patlength - i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void initBoyerMooreHorspool(const char *pattern, int patlength,
|
||||
int *bm_badcharacter_array)
|
||||
{
|
||||
precompute_badcharacter(pattern,
|
||||
(patlength < MAX_PATTERN_SIZE ? patlength : MAX_PATTERN_SIZE), bm_badcharacter_array);
|
||||
}
|
||||
|
||||
static int BoyerMooreHorspool(const char *pattern, int patlength,
|
||||
const char *text, int textlen, int *bm_badcharacter_array)
|
||||
{
|
||||
int j;
|
||||
char c;
|
||||
|
||||
j = 0;
|
||||
while (j <= textlen - patlength) {
|
||||
c = text[j + patlength - 1];
|
||||
if (pattern[patlength - 1] == c && memcmp(pattern, text + j, patlength - 1) == 0) {
|
||||
return j;
|
||||
}
|
||||
j += bm_badcharacter_array[(uint8_t)c];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
/* This is just an example on how to make an extension to allow custom
|
||||
* request body parsing. This just describes how to do this externally
|
||||
* and you should look more at on e of the internal parsers to see
|
||||
* the full potential.
|
||||
*
|
||||
* This module defines "EXAMPLE" and can be enabled with a rule like this:
|
||||
*
|
||||
* SecAction "phase:1,pass,nolog,ctl:requestBodyProcessor=EXAMPLE"
|
||||
*
|
||||
* See these for real parsers:
|
||||
* msc_reqbody.c
|
||||
* msc_multipart.c
|
||||
* msc_xml.c
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "ap_config.h"
|
||||
#include "apr_optional.h"
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
typedef struct example_ctx {
|
||||
unsigned long length;
|
||||
} example_ctx;
|
||||
|
||||
/**
|
||||
* This function will be invoked to initialize the processor. This is
|
||||
* probably only needed for streaming parsers that must create a context.
|
||||
*/
|
||||
static int example_init(modsec_rec *msr, char **error_msg)
|
||||
{
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_reqbody_example: init()");
|
||||
|
||||
msr->reqbody_processor_ctx = apr_pcalloc(msr->mp, sizeof(example_ctx));
|
||||
if (msr->reqbody_processor_ctx == NULL) {
|
||||
/* Set error message and return -1 if unsuccessful */
|
||||
*error_msg = apr_pstrdup(msr->mp, "failed to create example requbody processor context");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return 1 on success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will be invoked whenever the ModSecurity has data to
|
||||
* be processed. You probably at least need to increment the no_files
|
||||
* length, but otherwise this is only useful for a streaming parser.
|
||||
*/
|
||||
static int example_process(modsec_rec *msr,
|
||||
const char *buf, unsigned int size, char **error_msg)
|
||||
{
|
||||
example_ctx *ctx = (example_ctx *)msr->reqbody_processor_ctx;
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_reqbody_example: process()");
|
||||
|
||||
/* Need to increment the no_files length if this is not an uploaded file.
|
||||
* Failing to do this will mess up some other limit checks.
|
||||
*/
|
||||
msr->msc_reqbody_no_files_length += size;
|
||||
|
||||
/* Check for an existing context and do something interesting
|
||||
* with the chunk of data we have been given.
|
||||
*/
|
||||
if (ctx != NULL) {
|
||||
ctx->length += size;
|
||||
}
|
||||
|
||||
/* Return 1 on success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called to signal the parser that the request body is
|
||||
* complete. Here you should do any final parsing. For non-streaming parsers
|
||||
* you can parse the data in msr->msc_reqbody_buffer of length
|
||||
* msr->msc_reqbody_length. See modsecurity_request_body_end_urlencoded() in
|
||||
* msc_reqbody.c for an example of this.
|
||||
*/
|
||||
static int example_complete(modsec_rec *msr, char **error_msg)
|
||||
{
|
||||
example_ctx *ctx = (example_ctx *)msr->reqbody_processor_ctx;
|
||||
|
||||
if (error_msg == NULL) return -1;
|
||||
*error_msg = NULL;
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_reqbody_example: complete()");
|
||||
|
||||
ap_log_error(APLOG_MARK, APLOG_INFO | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_reqbody_example: request body length=%lu", ctx->length);
|
||||
|
||||
/* Return 1 on success */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) {
|
||||
|
||||
void (*fn)(const char *name,
|
||||
void *fn_init, void *fn_process, void *fn_complete);
|
||||
|
||||
/* Look for the registration function exported by ModSecurity. */
|
||||
fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_reqbody_processor);
|
||||
if (fn) {
|
||||
/* Use it to register our new request body parser functions under
|
||||
* the name "EXAMPLE".
|
||||
*/
|
||||
fn("EXAMPLE",
|
||||
(void *)example_init,
|
||||
(void *)example_process,
|
||||
(void *)example_complete);
|
||||
}
|
||||
else {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_reqbody_example: Unable to find modsec_register_reqbody_processor.");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* This is a function to register another function to be called during
|
||||
* the Apache configuration process.
|
||||
*/
|
||||
static void register_hooks(apr_pool_t *p) {
|
||||
ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST);
|
||||
}
|
||||
|
||||
/* Dispatch list for API hooks */
|
||||
module AP_MODULE_DECLARE_DATA reqbody_example_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
NULL, /* create per-dir config structures */
|
||||
NULL, /* merge per-dir config structures */
|
||||
NULL, /* create per-server config structures */
|
||||
NULL, /* merge per-server config structures */
|
||||
NULL, /* table of config file commands */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/*
|
||||
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
|
||||
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
|
||||
*
|
||||
* You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* If any of the files related to licensing are missing or if you have any
|
||||
* other questions related to licensing please contact Trustwave Holdings, Inc.
|
||||
* directly using the email address security@modsecurity.org.
|
||||
*/
|
||||
|
||||
#include "httpd.h"
|
||||
#include "http_core.h"
|
||||
#include "http_config.h"
|
||||
#include "http_log.h"
|
||||
#include "http_protocol.h"
|
||||
#include "ap_config.h"
|
||||
#include "apr_optional.h"
|
||||
|
||||
#include "modsecurity.h"
|
||||
|
||||
/**
|
||||
* This function will be invoked by
|
||||
* ModSecurity to transform input.
|
||||
*/
|
||||
static int reverse(apr_pool_t *mptmp, unsigned char *input,
|
||||
long int input_len, char **rval, long int *rval_len)
|
||||
{
|
||||
/* Transformation functions can choose to do their
|
||||
* thing in-place, overwriting the existing content. This
|
||||
* is normally possible only if the transformed content
|
||||
* is of equal length or shorter.
|
||||
*
|
||||
* If you need to expand the content use the temporary
|
||||
* memory pool mptmp to allocate the space.
|
||||
*/
|
||||
|
||||
/* Reverse the string in place, but only if it's long enough. */
|
||||
if (input_len > 1) {
|
||||
long int i = 0;
|
||||
long int j = input_len - 1;
|
||||
while(i < j) {
|
||||
char c = input[i];
|
||||
input[i] = input[j];
|
||||
input[j] = c;
|
||||
i++;
|
||||
j--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tell ModSecurity about the content
|
||||
* we have generated. In this case we
|
||||
* merely point back to the input buffer.
|
||||
*/
|
||||
*rval = (char *)input;
|
||||
*rval_len = input_len;
|
||||
|
||||
/* Must return 1 if the content was
|
||||
* changed, or 0 otherwise.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int hook_pre_config(apr_pool_t *mp, apr_pool_t *mp_log, apr_pool_t *mp_temp) {
|
||||
void (*fn)(const char *name, void *fn);
|
||||
|
||||
/* Look for the registration function
|
||||
* exported by ModSecurity.
|
||||
*/
|
||||
fn = APR_RETRIEVE_OPTIONAL_FN(modsec_register_tfn);
|
||||
if (fn) {
|
||||
/* Use it to register our new
|
||||
* transformation function under the
|
||||
* name "reverse".
|
||||
*/
|
||||
fn("reverse", (void *)reverse);
|
||||
} else {
|
||||
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, NULL,
|
||||
"mod_tfn_reverse: Unable to find modsec_register_tfn.");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void register_hooks(apr_pool_t *p) {
|
||||
ap_hook_pre_config(hook_pre_config, NULL, NULL, APR_HOOK_LAST);
|
||||
}
|
||||
|
||||
/* Dispatch list for API hooks */
|
||||
module AP_MODULE_DECLARE_DATA tfn_reverse_module = {
|
||||
STANDARD20_MODULE_STUFF,
|
||||
NULL, /* create per-dir config structures */
|
||||
NULL, /* merge per-dir config structures */
|
||||
NULL, /* create per-server config structures */
|
||||
NULL, /* merge per-server config structures */
|
||||
NULL, /* table of config file commands */
|
||||
register_hooks /* register hooks */
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user